Sparkspec #2
Three small ideas worth building. Every week.
This week: AI-written tests that pass no matter what, losing every app you signed into with one account, and finding out your server is on a blocklist only after customers cannot reach you.
Welcome back. Same method as last week: we read public threads on Hacker News, Reddit and X, keep the complaints that are specific and repeated, and turn three of them into small apps you can build in a day. Every idea links to the thread it came from, so you can read the original words yourself.
A note on "validated": these problems show up in public discussion. That is a signal, not proof of demand or revenue. Talk to the people in the thread before you invest heavily.
Issue #2 is fully open too: all three specs and all three prompts are free this week.
Free, no signup needed to read. Want the next issue in your inbox? Get it free every week.
Idea 1: Saboteur, plant a few bugs in your AI-written diff and see if the tests notice
The problem
When an agent writes both the code and the tests, a green test run tells you very little. The tests can be shaped around whatever the code happens to do, including its bugs. Reading every line defeats the point of using the agent, so most people ship and hope.
Who has it
Developers and vibe coders who merge agent-written changes every day and want a quick, honest answer to "would my tests catch it if this change were wrong?"
Evidence
- In an Ask HN thread titled "How to deal with shipping AI-written code you don't understand?", one commenter writes: "The part that makes me uneasy is when the AI writes both the code and the tests. They might agree with each other and still miss the same thing. How are people here checking for that without doing the whole job twice?" Another suggests you can "introduce bugs deliberately and see if tests fail". Source: Hacker News thread
- In a separate thread on AI coding agents, a commenter says: "AI-generated tests will often embed existing bugs as testable patterns that fail when fixed or rely on empty asserts to increase coverage." They add that "Coverage is increasingly becoming theater". Source: Hacker News thread
What already exists: Mutation testing tools like Stryker, mutmut, PIT and cargo-mutants do this properly, and some can limit runs to changed code. They are per language and use mechanical mutations (flip a <, delete a line), which can take a long time to run. The small wedge is a language-agnostic tool that plants a handful of plausible, logic-level bugs in only the lines you just changed, runs your existing test command, and tells you in plain English which bugs got through.
One-page spec
User: A developer about to merge an agent-written change who wants a 5 minute check on whether the tests guard the new logic.
Core features
saboteur run: readsgit diffagainst a base branch and collects only the changed hunks.- Asks any OpenAI-compatible model for N small, realistic bugs in those lines (off by one, wrong branch, swapped arguments, missing null check), each as a patch with a one line description.
- Applies each bug in a throwaway git worktree, runs your test command, records caught or survived.
- Report: survivors first, each with the planted change, the file and line, and a suggested test to add.
- Optional
--mechanicalmode with simple operator flips, no model needed. - Exit code for CI: fail if the survival rate is above a threshold.
Out of scope
- Writing or fixing the tests automatically.
- Whole-repo mutation runs.
- A hosted service, accounts or a GitHub App in v1.
- Judging code style or quality.
Data model
Run: id, base_ref, head_sha, test_command, model, started_at, finished_at, survival_rateMutant: id, run_id, file, line, description, patch, status (caught|survived|error|timeout), test_output_tailConfig(saboteur.toml): test_command, base_ref, count, timeout_seconds, include and exclude globs, max_survival_rate
Tech suggestion: Node and TypeScript CLI, simple-git for diffs and worktrees, the OpenAI SDK pointed at any compatible base URL, results saved as JSON plus a Markdown report. No database needed.
1 day build plan
- Morning: diff parsing, worktree setup and cleanup, running the test command with a timeout.
- Midday: model prompt and patch validation, mechanical fallback mode.
- Afternoon: run loop, caught or survived scoring, Markdown report.
- Evening: CI exit codes, GitHub Actions example, README, publish to npm.
Vibe coding prompt
Build a Node.js CLI called saboteur, written in TypeScript, that checks whether a repo's tests would catch small bugs in the lines changed by the current branch. It must work with any language, because it only runs the user's own test command.
Config:
- saboteur.toml at the repo root: test_command (string), base_ref (default "main"), count (default 8), timeout_seconds (default 300), include and exclude globs, max_survival_rate (default 0.25).
- Validate with zod and print readable errors. `saboteur init` writes an example file.
Diff:
- Use simple-git to get the unified diff of the working tree against merge-base(base_ref, HEAD).
- Keep only added or modified lines in files matching include and not matching exclude. Ignore test files by default (paths containing test, spec or __tests__).
Planting bugs:
- Default mode: call an OpenAI-compatible chat completions API using OPENAI_BASE_URL, OPENAI_API_KEY and SABOTEUR_MODEL env vars. Send the changed hunks with 20 lines of context and ask for exactly `count` mutants as JSON: [{file, line, description, original, replacement}]. Each mutant must change one to three lines inside the changed hunks and should be a realistic logic bug (off by one, inverted condition, wrong variable, swapped arguments, removed guard, wrong default).
- Reject any mutant whose `original` text is not found at that location, or that touches lines outside the diff.
- `--mechanical` mode: no model. Generate mutants by flipping comparison operators, swapping true and false, changing + to - and removing a single return guard, only on changed lines.
Running:
- For each mutant, create a temporary git worktree at HEAD, copy in the user's uncommitted changes, apply the mutant, run test_command with the timeout, and remove the worktree afterwards (also on Ctrl+C).
- Non-zero exit = caught. Zero exit = survived. Timeout = timeout. Failure to apply = error.
- Run up to 2 mutants in parallel by default, configurable with --jobs.
Output:
- Save .saboteur/runs/<timestamp>.json with run and mutant records, including the last 40 lines of test output per mutant.
- Print and save a Markdown report: survival rate at the top, then survivors first, each with file:line, the description, a before and after snippet, and a one sentence suggestion for a test that would catch it.
- Exit with code 1 if survival rate is above max_survival_rate, so it can run in CI.
Include tests for diff parsing, mutant validation and worktree cleanup, an example GitHub Actions workflow, and a README that explains this is a quick sanity check, not a replacement for full mutation testing.
Idea 2: Spare Key, know which apps you lose if one login gets locked
The problem
"Sign in with GitHub" and "Sign in with Google" are convenient until that one account is suspended or locked. Then every service attached to it goes too, and you find out which ones only when you try to log in. Nobody keeps a list of which apps depend on which login, or whether a backup way in exists.
Who has it
Developers and indie hackers who use one or two identity providers for dozens of tools: hosting, analytics, payments, domains, AI APIs.
Evidence
- An Ask HN post titled "GitHub suspended my account, and I couldn't submit a support ticket" describes the support form failing with "An unexpected error occurred (status: 401)" and ends with the worry: "I guess Everything I login with github maybe lose if I don't use second login method." Source: Hacker News thread
What already exists: GitHub and Google each show the apps you have authorized, and password managers audit weak or reused passwords. Neither answers "if this one account vanished tomorrow, which services would I lose, and which of them have a second way in?" That is a short, local checklist app.
One-page spec
User: Someone who signs into many services with GitHub, Google, Apple or X and wants a 20 minute audit, then a reminder to repeat it every quarter.
Core features
- List of services, each with the identity provider it uses and its backup login (password set, second provider, passkey, recovery codes stored, none).
- Import helper: paste the list from your GitHub or Google "authorized apps" page, or load a password manager CSV export. Only name, URL and username are read; any password column is discarded in the browser and never stored.
- Blast radius view: pick a provider, see every service that would be lost, with the ones that have no backup in red.
- Per service "how to add a backup login" note and a link to its account settings page, filled in by you.
- "Last tested" date: mark when you actually logged in with the backup.
- Export a Markdown checklist and a quarterly reminder as an
.icsfile.
Out of scope
- Storing passwords, codes or recovery keys.
- Connecting to any provider API or browser extension.
- Changing settings on any service.
- Sync, accounts, a hosted version.
Data model
Service: id, name, url, provider (github|google|apple|microsoft|x|email), backup (password|second_provider|passkey|recovery_codes|none), importance (critical|nice), settings_url, notes, last_tested_atProvider: id, label, account_email, recovery_set_up (bool), notesAudit: completed_at, services_count, no_backup_count
Tech suggestion: A single static page built with Vite and vanilla TypeScript, data in IndexedDB, JSON import and export for backups. No server at all, so it can be opened offline or hosted on any static host.
1 day build plan
- Morning: data model, service list with add, edit and filters.
- Midday: paste and CSV import with column mapping and password column stripping.
- Afternoon: blast radius view, last tested dates, critical services summary.
- Evening: Markdown and
.icsexport, JSON backup, README, deploy to a static host.
Vibe coding prompt
Build a single-page web app called Spare Key with Vite and vanilla TypeScript. It runs entirely in the browser with no server, no accounts and no analytics.
Purpose: help a user see which services they would lose if one sign-in provider (GitHub, Google, Apple, Microsoft, X) locked or suspended their account, and which of those services have a backup way to log in.
Data (store in IndexedDB via the idb package):
- Service: id, name, url, provider (github | google | apple | microsoft | x | email), backup (password | second_provider | passkey | recovery_codes | none), importance (critical | nice), settings_url, notes, last_tested_at (date or null).
- Provider: id, label, account_email, recovery_set_up (boolean), notes.
- Audit: completed_at, services_count, no_backup_count.
Screens:
- Services: table with inline editing, filters by provider, backup and importance, and an "Add service" form.
- Import: (1) a textarea where the user pastes the text of their GitHub "Authorized OAuth Apps" page or Google "Third-party apps and services" page; split it into lines, let the user tick which lines are real services, and create them with the chosen provider. (2) A CSV import for password manager exports: auto-detect name, url and username columns, let the user confirm the mapping, and drop any password, totp or notes columns in memory before anything is saved. Show a clear message saying passwords are never read or stored.
- Blast radius: choose a provider, show every service using it, with services where backup is "none" in red and critical ones first. Show a count at the top like "If GitHub locked you out today, you would lose 14 services, 9 with no backup."
- Checklist: for each service with no backup, show its settings_url and a "Mark backup added" button, plus a "Mark tested today" button that sets last_tested_at.
Export:
- Markdown checklist grouped by provider.
- An .ics file with a recurring event every 3 months titled "Spare Key audit".
- Full JSON export and import for backups.
Design: clean, readable, plain CSS, dark mode via prefers-color-scheme, works well on mobile. Include unit tests for CSV column detection and password column stripping, and a README explaining how to deploy it to any static host.
Idea 3: Listwatch, find out your server is on a blocklist before your users do
The problem
Some IP blocklists list whole hosting providers, not just bad actors. Some networks and mail filters use those lists, so a perfectly normal site or mail server can become unreachable for part of its audience. Owners usually find out by accident, long after it started.
Who has it
People running sites, APIs or mail on DigitalOcean, Hetzner, Linode, Vultr or similar hosts, especially those who self-host email.
Evidence
- A Tell HN post titled "Uceprotect is extorting website owners" opens: "I recently discovered by accident that our website was being blocked by Orange's security filters." The author explains the IP was "listed on UCEPROTECT Level 3" because of the reputation of "the entire ASN" of their host, and that whitelisting is offered "for about $30/month or $108/year". Commenters push back that Level 3 is meant only as one signal in spam scoring, and another adds: "UCEPROTECT is why I stopped self hosting my own email :(" Source: Hacker News thread
What already exists: Hosted blocklist monitors like MXToolbox and HetrixTools check IPs against many lists, and one-off lookup pages exist. The small wedge is a self-hosted checker that runs on a schedule, alerts only on changes, tells you whether a listing is about your IP or your whole provider, and says plainly which lists mostly matter for email rather than web traffic.
One-page spec
User: A solo builder or small team with a handful of servers who wants a short alert when any of their IPs lands on, or drops off, a common blocklist.
Core features
listwatch.yaml: domains and IPs to watch. Domains are resolved to their A records and MX hosts automatically.- DNSBL checks by reverse-IP DNS lookup against a configurable list of zones (for example Spamhaus ZEN, Barracuda, SpamCop and the three UCEPROTECT levels).
- Each zone tagged with scope (
ip|range|provider) and typical use (email|general), so the alert explains the impact. - ASN lookup for each IP, so provider-wide listings are labelled as such.
- Alerts only on change (listed or delisted) to a webhook, ntfy topic or email via SMTP.
- History table and a tiny status page.
Out of scope
- Paying for or requesting delisting automatically.
- Testing actual reachability from mobile networks.
- Email deliverability scoring or inbox placement tests.
- Multi-tenant hosted version.
Data model
Target: id, kind (domain|ip), value, resolved_ips[], asn, asn_nameZone(config): host, name, scope, use, removal_url, notesCheck: target_ip, zone_host, checked_at, listed (bool), return_code, txt_reasonEvent: target_ip, zone_host, change (listed|delisted), at, notified (bool)
Tech suggestion: Python 3.12 with dnspython, SQLite from the standard library, a YAML config, and a static HTML status page written on each run. Run from cron or a systemd timer. Some lists block queries that come through big public DNS resolvers, so document using a local resolver like Unbound.
1 day build plan
- Morning: config, domain resolution, DNSBL lookups with timeouts.
- Midday: ASN lookup, zone metadata, SQLite history and change detection.
- Afternoon: alerts with plain English explanations.
- Evening: status page, cron and systemd examples, README.
Vibe coding prompt
Build a self-hosted Python 3.12 CLI called listwatch that checks a user's server IPs against DNS blocklists on a schedule and alerts only when something changes. Use dnspython, PyYAML, sqlite3 from the standard library and httpx. No web framework.
Config (listwatch.yaml):
- targets: a list of domains and IPs. For each domain, resolve A records and the A records of its MX hosts. IPv4 only in v1.
- zones: a list of DNSBL zones with fields host, name, scope (ip | range | provider), use (email | general), removal_url and notes. Ship a commented default list including zen.spamhaus.org, b.barracudacentral.org, bl.spamcop.net, dnsbl-1.uceprotect.net, dnsbl-2.uceprotect.net and dnsbl-3.uceprotect.net, and note that each list's own usage terms apply.
- resolver: optional nameserver IP. Warn in the README that some lists refuse queries from large public resolvers and recommend a local resolver such as Unbound.
- alerts: optional webhook_url, ntfy_url and smtp settings.
Commands:
- `listwatch check`: for every resolved IP and every zone, query <reversed-ip>.<zone host> for an A record with a 5 second timeout. NXDOMAIN means not listed. If listed, also fetch the TXT record for the reason. Look up the IP's ASN and ASN name via a DNS query to origin.asn.cymru.com and asn.cymru.com, cached for 7 days. Store every result in SQLite at ~/.listwatch/listwatch.db.
- Compare with the previous result for the same IP and zone. On a change, write an Event and send alerts.
- `listwatch status`: print a table of IP, ASN name, and each zone's current state.
- `listwatch page --out status.html`: write a static HTML page with the same table, red for listed, plus the last 50 events.
Alerts:
- Plain English text such as: "203.0.113.7 (example.com, DigitalOcean AS14061) is now listed on UCEPROTECT Level 3. Scope: provider. This list is mostly used by mail filters, so web traffic is usually unaffected. Details: <removal_url>."
- Send at most one alert per IP and zone per 24 hours.
Include tests for IP reversal, change detection and alert text, example cron and systemd timer files, and a README that explains scopes, what to do when listed, and why provider-level listings are different from your own IP being listed.
Before you build
- Read the source thread first. Reply there if you build something; the people who complained are your first users.
- Ideas are not exclusive. Others may build the same thing. Niche, execution and distribution decide who wins.
- Product names above are working titles. Check for trademark and domain conflicts before you launch.
Get every spec
Sparkspec is free: one email a week with three ideas, plus the first full spec and prompt.
Know a builder who keeps asking "what should I build?" Send them this page.
Sparkspec. Three small ideas worth building. Every week.