A small, free web tool you can put on Product Hunt this week: one service, no database, no API keys, with the SEO, icons and launch kit already done. Built and run locally with Flisk, hosted for free on Render.
The example tool is Contrast: put two colors in the address (/1d1c1a/fbfaf7) and get the WCAG contrast ratio,
AA/AAA verdicts and the nearest color that passes. Replace it with your own; everything around it stays.
Citable and Helpdock are built the same way.
| Where | |
|---|---|
| Title, description, canonical, robots meta, theme color per scheme | src/seo.ts → head() |
| Open Graph and X/Twitter card with a 1200×630 image | head(), brand/og.svg |
| JSON-LD: WebSite, Organization, WebApplication, FAQPage, BreadcrumbList | jsonLd(), faqJsonLd() |
robots.txt that names the AI answer crawlers, keeps out the API, points at the sitemap |
robotsTxt() |
sitemap.xml, llms.txt, site.webmanifest, /.well-known/security.txt |
src/seo.ts |
| favicon.ico (16/32/48), icon.svg, apple-touch-icon, 192/512 PNG, maskable icon | brand/*.svg → bun run icons → src/assets.generated.ts |
| One address per result (other spellings 301), a noindex 404 page | src/app.ts |
| A JSON API, an embeddable SVG badge and an MCP server (Streamable HTTP, no key) | src/app.ts, src/mcp.ts |
| No JavaScript at all; a Content-Security-Policy that allows none | src/guard.ts |
| Rate limits per client behind Render's proxy or Cloudflare | src/guard.ts |
| Tests that fail when a page loses its title, canonical, card or JSON-LD, or an icon goes missing | tests/seo.test.ts |
| CI: typecheck, lint, tests, and the production image started and asked for its SEO files | .github/workflows/ci.yml |
| Free hosting: one Render web service | render.yaml, Dockerfile, DEPLOY.md |
| A how-it-works film in the look of the Flisk promos, made from screenshots of your running site: autoplaying on the home page (MP4 with byte ranges, a still for reduced motion) and a GIF for the README | video/film.json → bun video/shots.ts && bun video/render.ts |
| Product Hunt kit: ICE scoring, taglines, gallery, first comment, checklist | LAUNCH.md |
| Where AI users look: the connector, plugin, MCP registries and GitHub Marketplace steps, and what went wrong for us | docs/DIRECTORIES.md |
Click Use this template on GitHub, clone your copy, then:
cd services/app/web
bun install
bun run rename --name "Acme" --domain acme.example.com --repo you/acmesrc/site.ts: the tagline (60 characters at most), the description (110 to 160), the FAQ and the examples. Every tag, JSON-LD node and SEO file is built from it.src/contrast.ts: replace it with your tool. Keep the shape: input from the address, a result object, one function that the page, the API and the MCP tool all call. Then updatesrc/pages.ts, the routes insrc/app.tsand the tool insrc/mcp.ts.brand/icon.svg,brand/icon-full.svg(full-bleed, for the maskable and Apple icons) andbrand/og.svg, thenbun run icons. It embeds them insrc/assets.generated.ts, because Flisk's image shipssrc/only.video/film.json: point "shots" at your pages (and the elements to highlight) and write the scenes, thenbun video/shots.ts && bun video/render.ts(needs Chrome and ffmpeg). It writes the film intosrc/video.generated.tsand the GIF intodocs/demo.gif.bun test: the SEO tests tell you what you broke.- List it where people ask an AI: a connector and a plugin for the Claude directory, the MCP registries, Cursor, and a GitHub Action if it fits CI. docs/DIRECTORIES.md has the order and the traps.
If the tool fetches other sites, take the SSRF guard (src/net.ts) from
Citable and use Slots and TtlCache
from src/guard.ts to cap and cache the work.
With Flisk (Docker, Tilt and the Flisk CLI):
flisk upIt opens at http://api.flisk-template-launch.localhost/api/web/ (the name follows .flisk/project.json). The app
never touches a database. Flisk still starts its shared Postgres container locally even though .flisk/project.json
leaves it out; online there is none.
Without Flisk:
cd services/app/web && bun install && bun run devAll optional. PORT, PUBLIC_URL (the address people use, for canonical links and the card; set it online),
TRUST_PROXY (none, last-forwarded on Render, cloudflare) and CALLS_PER_MINUTE (API and MCP, 120).
cd services/app/web
bun run typecheck && bun run lint && bun testMIT licensed.
