Edition No. 10 · 4 Sep 2026
Twelve repositories for writing that has to be read
Readability checks, prose linters, translation memory, and the tools that catch what a spellchecker cannot.
Nine editions have been about plumbing. Analytics, uptime, queues, backups, ingest, vectors, transcripts, dashboards, a CRM, a chat widget, a session recorder. Roughly a hundred and sixty repositories, and almost every one of them is a mechanism that sits around the thing you are actually selling.
Not one of them has looked at the sentences. And the sentences are the product's front door: the landing page hero, the docs paragraph an AI assistant decides to quote, the video description, the onboarding email, the button label. For someone writing in two languages, one of them not native, that is the most under-inspected surface in the whole operation — and unlike RAM or disk, nothing on a server will ever warn you it is wrong.
So today the slate starts with the words, then follows them outward: how a reader gets back to you after they close the tab, what happens automatically once they do, and — in the products — how you find out whether what the machine wrote was any good.
Seven entries are marketing-shaped, three sharpen the product itself, two are the bench. All twelve are new to the ledger; no repeats today. Four are genuine hidden gems under 3,000 stars. Five further candidates were verified and deliberately left out, named in the appendix with the reason.
This edition, in numbers
| Repos | 12 |
| Hidden gems (<3k stars) | 4 |
| Marketing / product / bench | 7 / 3 / 2 |
| New to the ledger | 12 |
| Repeats | 0 |
| Dropped on check | 5 |
If you only do three things
- Shlink (#4) — a video channel usually has no measurable connection to the website it points at. One container, one short subdomain, and every video description carries a link you can count. Dub (Ed.1 #2) was offered for this job on 21 August, but self-hosting it is a Next.js project. This one is a container and a database.
- LanguageTool (#1) — a grammar and style checker with genuinely serious Russian rules, running on a machine you control so no product copy leaves it. If you publish in English and Russian, every English page is read by native speakers, and every Russian page is read by people who will notice English word order instantly.
- uv (#12) — twenty minutes, and it is the reason more of the other eleven actually get tried.
uv run --with textstat script.pyruns a tool from this page without installing anything permanently, and without thesource venv/bin/activatedance that has broken more Sunday afternoons than any bug.
Every link in one place
| # | Repo | Website / docs | Stars | Licence |
|---|---|---|---|---|
| 1 | languagetool-org/languagetool | languagetool.org | 15.0k | LGPL-2.1 |
| 2 | vale-cli/vale | vale.sh | 6.1k | MIT |
| 3 | textstat/textstat 💎 | textstat.org | 1.4k | MIT |
| 4 | shlinkio/shlink | shlink.io | 5.1k | MIT |
| 5 | web-push-libs/pywebpush 💎 | pypi.org/project/pywebpush | 374 | MPL-2.0 |
| 6 | mautic/mautic | mautic.org | 10.2k | GPL-3.0 |
| 7 | langfuse/langfuse | langfuse.com | 32.4k | MIT, except ee/ |
| 8 | pemistahl/lingua-py 💎 | pypi.org/project/lingua-language-detector | 1.8k | Apache-2.0 |
| 9 | jealous/stockstats 💎 | pypi.org/project/stockstats | 1.5k | BSD-3-Clause |
| 10 | dgtlmoon/changedetection.io | changedetection.io | 33.4k | Apache-2.0 |
| 11 | duckdb/duckdb | duckdb.org | 38.7k | MIT |
| 12 | astral-sh/uv | docs.astral.sh/uv | 89.1k | MIT / Apache-2.0 |
The words themselves
Twelve repositories, checked and reviewed. Every version verified against the GitHub API and dated.
15k stars · LGPL-2.1 · v6.8 (2026-05-05) · Track this in Scout · Share this tool
Grammarly you can run yourself — and one of the very few checkers that takes Russian as seriously as English.
▶Repo detailsthe review · specs · pros & cons
What it is
An open-source spelling, grammar and style checker covering more than 25 languages, shipped as a self-hostable HTTP server with a simple JSON API. You post text at it; it returns a list of issues with suggested replacements, a rule identifier, and the character offsets to highlight.
What it is good for. A product page sells on clarity. If that page has slightly wrong prepositions, a buyer's confidence drops before they reach the demo — and they will never say why they left. Anyone writing marketing copy in two languages gets the most from a machine check on the non-English half: LanguageTool's Russian rule set is one of the strongest in open source, not a token afterthought bolted onto an English engine. Running it yourself also means unreleased landing copy, pricing lines and video scripts never get pasted into a third-party SaaS. Wire it into the Astro build (Ed.3 #4) and every page ships checked, in both languages, with nobody having to remember.
- Russian and English both treated as first-class, which almost nothing else in this ledger can claim.
- Self-hosted HTTP API: FastAPI, the Astro build, and Claude Code can all call the same instance.
- Browser extensions use the same server, so YouTube descriptions and email drafts get checked too.
- It is a JVM server, and with n-gram data it wants roughly 1–2 GB of RAM — a real cost on a small VPS already carrying an application. Check with Beszel (Ed.5 #8) first.
- The free rule set is deliberately weaker than the vendor's paid cloud tier: strong on grammar and mechanics, thinner on rewriting and nuance.
- LGPL-2.1 — fine to run as a separate service, but do not link it into a distributed binary without reading the licence carefully.
6.1k stars · MIT · v3.20.0 (2026-09-02) · Track this in Scout · Share this tool
A linter for your voice — the difference between a site that sounds like a company and one that sounds like nine separate afternoons.
▶Repo detailsthe review · specs · pros & cons
What it is
A markup-aware command-line linter for prose. You point it at a style — Microsoft's, Google's, or a set of YAML rules you write yourself — and it flags passive voice, banned phrases, heading capitalisation and inconsistent product terms across Markdown, HTML and MDX, while ignoring the code and front-matter around them.
What it is good for. LanguageTool tells you a sentence is wrong. Vale tells you it is not yours. Writing docs, blog posts and video descriptions over months, the failure is not grammar, it is drift: "sub-topic" on Monday and "subtopic" on Friday, "map" in the hero and "graph" in the docs. Those wobbling terms are exactly the strings an AI answer engine would otherwise quote a site by, so terminology consistency is an AI-search asset rather than a style hobby — the same argument geo-optimizer-skill (Ed.8 #3) makes about structure, applied to vocabulary. And when a coding assistant writes a great deal of the copy, a checked-in rules file is the only way to make it write in one consistent voice rather than a plausible average one.
- MIT, a single binary, no runtime to install — it will still work in three years.
- Understands Markdown and MDX, so it drops straight into Astro and Starlight (Ed.4 #4) without mangling components.
- Twenty lines of YAML gives you an enforceable house glossary — the cheapest brand consistency available.
- It ships almost no rules of its own: day one is installing or writing a style package, so the first session is configuration rather than results.
- Off-the-shelf styles produce false positives on technical writing until tuned, and an ignored linter is worse than none.
- The repository has moved —
errata-ai/valenow redirects tovale-cli/vale. Ownership changes are worth watching on a tool that a workflow is built around.
1.4k stars · MIT · 0.7.13 (2026-02-18) · Track this in Scout · Share this tool
One number that says whether the page you just wrote can be read by the person you wrote it for.
▶Repo detailsthe review · specs · pros & cons
What it is
A small Python library that scores a block of text for readability — Flesch Reading Ease, Flesch–Kincaid grade level, SMOG, Gunning fog and a dozen more — along with syllable, word and sentence counts. It supports several languages, Russian among them.
What it is good for. A product that promises clarity has to read clearly itself. A landing page written at postgraduate density quietly contradicts that promise before anyone clicks Sign up, and no analytics tool will ever tell you that is the reason. This gives you one number per page, cheap enough to compute for every page on every build, so you can watch the trend rather than argue about a paragraph. It also grades video scripts, which is where sentence density costs most directly — retention drops on complexity long before viewers leave a comment about it. Pair it with GoAccess (Ed.8 #4): rewrite the hero, watch the grade level drop, watch what happens to bounce.
- One
pip install, no models, no downloads, runs in milliseconds — the lowest-friction item on this page. - Handles Russian as well as English, so both halves of the site get the same treatment.
- MIT and tiny, so it can sit inside an application itself as a per-document statistic if you ever want it as a feature.
- Readability formulas count syllables, not clarity. A precise, well-written technical paragraph can legitimately score "difficult" — the number is a prompt to reread, never a target to optimise.
- Russian formula coverage is thinner and less validated than English; treat the Russian scores as relative, not absolute.
- Small library, modest maintenance cadence — fine for a scoring script, less so as a load-bearing product dependency.
5.3k stars · MIT · v5.1.6 (2026-09-06) · Track this in Scout · Share this tool
The short link in the YouTube description, and the only honest answer to 'did that video do anything?'
▶Repo detailsthe review · specs · pros & cons
What it is
A self-hosted URL shortener running on your own domain, with a REST API, per-link visit statistics, tags, UTM handling and built-in QR-code generation. One PHP container plus a database, and a separate web UI if you want one.
What it is good for. A video channel and the website it points at usually have no measurable relationship. You publish a tutorial, some people watch it, some number of visits arrive, and there is no way to connect the two. Dub (Ed.1 #2) was the answer offered on 21 August, and self-hosting a large Next.js application is not the shape of thing most people start on a Tuesday. Shlink is the shape they do. go.yourdomain/ru-map-01 in the description of every video, a QR code on the end card, and a stats endpoint that tells you which videos send people and which merely get watched. That is the number that turns a channel from a hobby into a channel with a job.
- MIT and mature at v5.x, with a real release cadence — the least risky attribution tool in the ledger.
- REST API means n8n or Claude Code can mint a tagged link per video automatically, so you never hand-make one.
- QR codes are built in, which matters for end cards and for slides in a Slidev deck (Ed.5 #4).
- PHP/Symfony — a stack many teams do not otherwise run, so its upgrades are a separate chore from everything else on the machine.
- The admin UI is a second project (
shlink-web-client) you also host; the core is API and CLI only. - A short-link domain needs its own DNS and TLS, and needs guarding — an open shortener gets abused and then blocklisted, which would take your links down mid-campaign.
Pull visit data via the REST API into research.db beside the yt-dlp (Ed.6 #4) video metadata, and "video → clicks → signups" becomes a single SQL join.
375 stars · MPL-2.0 · 2.5.0 on PyPI (2026-08-29) · Track this in Scout · Share this tool
A way to reach a returning visitor who never gave you an email address.
▶Repo detailsthe review · specs · pros & cons
What it is
The Python implementation of Web Push: it encrypts a payload with the VAPID scheme and hands it to the browser's push service, which delivers a notification to the visitor's desktop or Android device. This is the server half; the browser half is a service worker and a permission prompt you write yourself.
What it is good for. Every audience tool in this ledger assumes an email address — Listmonk, the lead magnet, Mautic below. But most people who read one tutorial will not hand one over, and a push subscription costs them a single click and no personal data at all. For a channel publishing bilingual tutorials on a schedule, "the next video is up" is precisely the notification people accept and do not resent. It is also the only re-engagement channel that needs no sending domain, no SPF, no DKIM and no DMARC — none of the machinery checkdmarc (Ed.8 #1) exists to police, and none of the deliverability risk. At 374 stars this is genuinely under the radar, and it is the standard Python implementation.
- Pure Python, MPL-2.0, drops straight into FastAPI — no third-party service, no per-notification cost, no visitor data leaving the server.
- Works on desktop Chrome, Firefox and Edge, and on Android, which covers most of a technical audience.
- No email address means no consent-and-deliverability chain to maintain, which for a solo founder is a genuine saving.
- 374 stars and effectively one maintainer, who says so plainly in the README. Read the source, vendor it, and do not build a business-critical channel on it without a fallback.
- iOS Safari only supports push for sites installed to the home screen, which removes a large slice of your reachable audience before you start.
- A permission prompt fired on page load is a bounce; an over-used channel is an unsubscribe you cannot win back. This one is easy to do badly.
10.5k stars · GPL-3.0 · 7.2.0 (2026-09-02) · Track this in Scout · Share this tool
The category ten editions have skipped: what happens on its own, after someone gives you their address.
▶Repo detailsthe review · specs · pros & cons
What it is
A full open-source marketing automation platform: contacts, segments, lead scoring, landing pages, forms, and multi-step campaigns with real branching — opened but did not click, wait three days, send the other version. The self-hosted equivalent of the marketing half of HubSpot.
What it is good for. Listmonk (Ed.2 #1) broadcasts to a list. Twenty (Ed.9 #1) records who people are. Nothing in the ledger acts when a person behaves a certain way, and for a solo founder that gap is expensive: it is the difference between a list and a funnel. The realistic use here is small and specific — one five-email onboarding sequence in English and the same one in Russian, triggered on signup, whose only job is getting a new user to the first thing the product actually does for them. That is precisely the moment OpenReplay (Ed.9 #3) will show you people never reach. Automation is how you attend to it while asleep.
- GPL-3.0, self-hosted, with no seat limits and no per-contact pricing — the entire economic reason to run it rather than rent it.
- Genuinely mature and actively released: 7.2.0 landed on 2 September, on a roughly two-to-three-week cadence.
- Owns both the sequence and the landing page it points at, so a campaign is one system rather than three glued together.
- The heaviest install on this page: PHP/Symfony with cron jobs it genuinely depends on, and it wants MySQL or MariaDB — a second database engine beside an existing Postgres, with its own backup story in restic (Ed.8 #11).
- It overlaps Listmonk directly. Running both means two subscriber lists drifting apart — pick one and delete the other.
- The interface is from an older era of enterprise software and will cost you a confused afternoon before it costs you nothing.
34.3k stars · MIT, except the ee/ directories which are commercially licensed · v4.30.0 (2026-09-04) · Track this in Scout · Share this tool
LiteLLM meters what the AI costs. This one tells you whether it was any good.
▶Repo detailsthe review · specs · pros & cons
What it is
An LLM engineering platform. It traces every model call inside a request, stores prompts as versioned artefacts outside your code, runs evaluations over saved datasets, and gives you a UI to compare outputs across prompt and model versions side by side.
What it is good for. When all of a product's value sits in the quality of one model output, the usual way to judge a prompt change is to open one conversation and have a feeling. Langfuse converts that into twenty real conversations saved as a dataset, a score per run, and a visible diff between prompt v3 and prompt v4 — which is what makes iteration compound rather than wander. It is also the direct answer to the decision this ledger has now deferred for seven editions: BERTopic vs turftopic vs LightRAG vs GraphRAG. You cannot pick a winner without a scoreboard. This is the scoreboard.
- MIT for everything you would actually use, with a first-class LiteLLM (Ed.5 #9) integration — cost and quality land in the same trace.
- Prompt management moves prompts out of the codebase, so tuning wording stops requiring a deploy.
- A free hosted tier means you can evaluate the whole idea before deciding whether it deserves space on a server you maintain.
- Self-hosting v3 and later wants Postgres, ClickHouse, Redis and S3-compatible storage — as heavy as OpenReplay, and you should not stand both up new in the same month.
- The
ee/directories are commercially licensed; read them before assuming the whole repository is MIT. - It ships close to daily. That is momentum, but self-hosters inherit the churn — pin a version.
1.8k stars · Apache-2.0 · v2.2.0 (2026-03-09) · Track this in Scout · Share this tool
Knowing which language a paragraph is in — before you spend a model call finding out.
▶Repo detailsthe review · specs · pros & cons
What it is
A language-detection library for Python covering 75 languages, built specifically to stay accurate on short and mixed-language text, which is where most detectors collapse. No neural network and no API call — it ships statistical models and runs entirely offline, returning a confidence value rather than a bare guess.
What it is good for. A chat log is a common import, and a genuinely bilingual chat log switches language mid-thread — often mid-paragraph. Almost everything downstream depends on knowing which: which stopword list, which cluster label language, which Presidio (Ed.7 #10) recogniser set, and whether a chunk deserves a cheap model or an expensive one. Deciding that per chunk with an LLM is a recurring bill; deciding it here takes microseconds and costs nothing. It also unlocks a small honest feature you can demo: telling the user "this conversation is 62% Russian" before they have read a word of it.
- Apache-2.0 and fully offline — nothing to call, nothing to pay for, nothing that can rate-limit you mid-import.
- Unusually strong on the short fragments that chunking produces, which is exactly the failure case for simpler detectors.
- Returns confidence values you can threshold, so ambiguous chunks can be routed differently instead of guessed at.
- Loading all 75 languages costs real memory. Restrict it to English and Russian at construction time and it becomes small — but you must remember to.
- Requires Python 3.12 or newer; check the interpreter on the target machine before planning around it.
- Single-author project. Stable and well-tested, but a bus factor of one is still a bus factor.
The detected language becomes a column beside each chunk in Postgres, and every later stage reads it instead of re-guessing.
The detected language becomes a column beside each chunk in Postgres, and every later stage reads it instead of re-guessing.
1.5k stars · BSD-3-Clause · v0.6.8 (2026-02-16) · Track this in Scout · Share this tool
Fifty indicators as DataFrame columns, under a licence you can actually ship.
▶Repo detailsthe review · specs · pros & cons
What it is
A thin wrapper that turns a pandas DataFrame of OHLCV bars into a StockDataFrame, where asking for df['macd'] or df['rsi_14'] computes the indicator on demand. More than fifty momentum, trend, volatility and volume indicators, with no compiled dependencies to install.
What it is good for. The trading chain in this ledger is all research machinery: tsfresh generating 700 features, Optuna searching, arch testing whether the winner is luck, SHAP explaining what it leans on. What is missing is the unglamorous layer where a human-legible indicator is computed the same way every time — in the product, for a chart a paying user looks at and recognises. This is that layer, it installs in one command, and BSD-3-Clause means it can sit inside a paid product screen, unlike backtesting.py (AGPL) or vectorbt (Commons Clause).
- BSD-3-Clause — genuinely shippable inside a commercial feature, which is rare in this corner of the ecosystem.
- No TA-Lib C library to compile, which removes the classic install wall on a plain VPS.
- The column-access API is small enough that Claude Code will get it right on the first attempt.
- Seven months since the last release and a small maintainer team — stable rather than abandoned, but verify before it becomes load-bearing.
- Indicators are conveniences, not edges. Computing fifty of them is not a strategy, and it is an easy way to fool yourself into feeling productive.
- On three years of one-minute price bars, casual column access recomputes far more than you expect. Cache deliberately.
This is that layer, it installs in one command, and BSD-3-Clause means it can sit inside a paid product screen, unlike backtesting.py (AGPL) or vectorbt (Commons Clause).
Sits directly beside existing pandas loading code.
33.7k stars · Apache-2.0 · 0.60.3 (2026-09-04) · Track this in Scout · Share this tool
A watcher on every competitor's pricing page, so you find out the day it changes rather than the quarter.
▶Repo detailsthe review · specs · pros & cons
What it is
A self-hosted website change monitor. You give it URLs, optionally point at one element on the page with a visual selector, and it notifies you — email, Telegram, Discord, ntfy or a webhook — the moment that content changes, with a diff of what moved.
What it is good for. RSSHub (Ed.4 #7) watches things that publish feeds. PRAW (Ed.7 #6) searches what has already been said. Neither notices that a competitor quietly changed their pricing, added a row to a comparison table, or started using the exact phrase you were about to build a page around. In a small market that is the highest-value signal there is, and nobody announces it. Three competitor pricing pages and two documentation homepages is a twenty-minute setup and a permanent early-warning system — and every diff it catches is a post you are first to write.
- Apache-2.0 and shipping constantly — 0.60.3 landed today, which is about as live as verification gets.
- The visual element selector means you watch the price, not the cookie banner or the rotating testimonial.
- Notifies into ntfy (Ed.7 #4), Telegram or n8n — all things earlier editions have already covered.
- Watching JavaScript-heavy pages needs the browser-rendering mode and a headless Chrome sidecar — real RAM on a box already carrying a lot.
- Watch too many pages and it becomes noise, and a noisy alert channel gets muted, which is worse than no alerts.
- The project also sells a hosted tier, so check which conveniences assume it before designing around them.
RSSHub (Ed.4 #7) watches things that publish feeds.
41.1k stars · MIT · v1.5.5 (2026-07-22) · Track this in Scout · Share this tool
SQL over three years of price bars in a file, with no server and no import step.
▶Repo detailsthe review · specs · pros & cons
What it is
An in-process analytical database — SQLite's shape, but built for scanning and aggregating columns rather than fetching individual rows. It queries CSV, Parquet and pandas DataFrames directly inside your Python process, with no server, no daemon and no loading step.
What it is good for. Two slow problems are often the same problem. A research project with three years of one-minute price bars has pandas re-reading and re-filtering them on every experiment, while a research.db steadily accumulates yt-dlp metadata, comments, transcripts and Reddit pulls that SQLite will eventually be slow to aggregate. DuckDB answers both: SELECT ... FROM 'bars_*.parquet' returns in about a second on data larger than RAM, and it will attach and query an existing SQLite file in place without a migration. The practical effect is that you stop waiting on your own data, which is what determines how many experiments you are actually willing to run.
- MIT, one
pip install, no server and no daemon — nothing new to back up beyond the files that already exist. - Reads Parquet and CSV directly, so there is no ETL ceremony between having data and asking it a question.
- Attaches SQLite and Postgres, so it sits beside an existing stack rather than asking to replace any of it.
- It is an analytical engine, not a replacement for the Postgres behind an application — concurrent writes are explicitly not its job.
- Storage-format stability has improved but still moves between majors; pin the version and keep the source files.
- One more SQL dialect's small differences to learn, which mostly bite in date handling.
89.6k stars · Apache-2.0 · 0.12.10 (2026-09-04) · Track this in Scout · Share this tool
The end of `source venv/bin/activate` — and of the Sunday afternoon lost to a broken environment.
▶Repo detailsthe review · specs · pros & cons · install
What it is
A single Rust binary that replaces pip, venv, pip-tools and pyenv at once. It creates environments, installs packages 10–100× faster, produces a reproducible lock file, and will install Python itself if the machine does not have the right version.
What it is good for. Nearly every Python recommendation across ten editions — Docling, BERTopic, whisperX, tsfresh, Presidio, Marker, and three items on this page — arrives with a dependency tangle attached. For someone who builds through Claude Code rather than through years of Python habits, a broken environment is the specific failure that kills adoption of an otherwise excellent tool: the install fails, the afternoon goes, and the tool never gets a second try. uv run script.py builds and uses the right environment with no activation step at all, and uv run --with textstat --with trafilatura script.py lets you try something from this page without installing anything permanently. That one command is why more of this ledger will get tested instead of bookmarked.
- One binary with no bootstrap Python required, so it works on a fresh VPS and on a laptop identically.
- Genuinely 10–100× faster than pip, which changes what you are willing to try on a whim.
uv run --withmakes throwaway experiments safe — nothing permanent is installed, nothing to clean up.
- Not a cure for packages that need compilers or CUDA — whisperX and Marker will still fight you on a CPU-only box.
- Every tutorial you read will say
pip install, so you will be translating instructions in your head for a while. - Still 0.x and moving quickly; behaviour occasionally shifts between minor versions.
That one command is why more of this ledger will get tested instead of bookmarked.
pip install
Checked, and left out
These were opened for this edition and did not make it, with the reason.
LinkStackOrg/LinkStack
LinkStackOrg/LinkStack (3.8k, AGPL-3.0) — self-hosted link-in-bio; verified alive but v4.8.6 was 2026-01-26, seven months quiet, and it is another PHP service to maintain. Shlink covers the measurable half of the job with a far better cadence. Backlogged.
crate-ci/typos
crate-ci/typos (4.0k, MIT/Apache-2.0, v1.48.0 2026-06-30) — verified healthy and good. Dropped as redundant: Vale and LanguageTool already cover customer-facing spelling, and three prose checkers means none gets run. Backlogged.
amperser/proselint
amperser/proselint (4.5k, BSD-3-Clause) — v0.16.0 on 2025-11-14, ten months quiet. Vale does the same job on a two-week cadence. Backlogged.
get-alex/alex
get-alex/alex (5.1k, MIT) — no release date readable from the GitHub page and npm returns 403 from this sandbox, so recency could not be proven. Backlogged; re-check from the Mac.
discourse/discourse
discourse/discourse (47.2k, GPL-2.0) — verified alive and dropped for the same reason apache/answer was on 2026-08-30: a forum with four posts signals the opposite of what he wants. Backlogged until there is steady traffic.






























