Skip to content

Repository files navigation

Limen

Preflight for web launches

Limen helps teams decide whether a landing page is actually ready for launch-day or paid traffic — before weak messaging, low trust, or poor CTA clarity waste the moment.

Quickstart · What it does · How it works · Capabilities · Local development

Next.js TypeScript Postgres Redis Playwright Status


The idea in one line

Should this page launch for this audience and this traffic source right now?

That is the entire reason Limen exists.


Why Limen exists

A landing page can look polished and still fail the moment real traffic hits it.

Typical launch mistakes are simple, expensive, and easy to miss:

  • the headline is too vague for cold traffic
  • the CTA asks for commitment too early
  • trust proof appears too late
  • metadata is weak or missing
  • the page is parseable, but not persuasive

Most tools catch isolated issues.

Limen is built to make a launch decision.


What Limen does

Limen takes a launch brief and a public landing page URL, then produces a launch-oriented review based on captured evidence.

Launch brief

  • target audience
  • traffic channel
  • desired action
  • offer
  • objections
  • competitors
  • brand voice

Evidence captured

  • HTML snapshot
  • rendered screenshot via Playwright
  • page title and metadata
  • hero and heading structure
  • CTA-like actions
  • trust-related signals
  • viewport and page capture metadata

Outputs

  • launch verdict
  • confidence level
  • launch summary
  • top reasons
  • top fixes
  • evidence-linked findings
  • persona replay
  • rewrite suggestions
  • extracted signals explorer
  • screenshot and HTML artifact previews

How it works

flowchart TD
    A[Create launch run] --> B[Submit launch brief]
    B --> C[Persist AuditRun]
    C --> D[Queue worker job]
    D --> E[Validate and normalize URL]
    E --> F[Fetch HTML]
    F --> G[Capture screenshot]
    G --> H[Persist artifacts]
    H --> I[Extract signals]
    I --> J[Generate findings]
    J --> K[Generate verdict]
    K --> L[Generate persona replay]
    L --> M[Generate rewrite suggestions]
    M --> N[Synthesize launch board]
    N --> O[Render run results UI]
Loading

Product rhythm

Brief → Evidence → Findings → Verdict → Persona view → Rewrites

Limen is intentionally built as a decision pipeline, not a generic scanner.


What the report feels like

Launch board

  • Verdict — should this page launch?
  • Confidence — how strong is the current evidence?
  • Top reasons — why Limen reached the verdict
  • Top fixes — what to change first

Evidence layer

  • HTML snapshot
  • rendered screenshot
  • extracted signals
  • evidence-linked findings

Operator layer

  • persona replay
  • rewrite suggestions

Current capabilities

Area Current state Notes
Launch brief intake ✅ Working Audience, channel, offer, objections, and more
Queue-backed execution ✅ Working BullMQ + Redis
HTML fetch ✅ Working URL normalization + fetch pipeline
Screenshot capture ✅ Working Playwright rendered evidence
Artifact persistence ✅ Working HTML + screenshot artifacts
Extracted signals ✅ Working H1, metadata, CTA candidates, trust signals, hero density
Findings generation ✅ Working Rule-based heuristics with evidence refs
Verdict generation ✅ Working LLM report when available; deterministic fallback produces a partial result
Launch summary ✅ Working Summary, top reasons, top fixes
Persona replay ✅ Working Primary + skeptical cold visitor
Rewrite suggestions ✅ Working Hero, support line, CTA, trust section
Artifact previews ✅ Working Screenshot + HTML snapshot in UI
Extracted signals UI ✅ Working Transparent evidence explorer
Ranking quality 🚧 Improving Needs better launch-readiness weighting
Telemetry vs findings separation 🚧 Improving Some internal pipeline events still need cleanup
Screenshot-aware reasoning depth 🚧 Improving Evidence exists; deeper interpretation still evolving

Screens

Landing page

Limen is presented as a launch-decision product, not just a diagnostics dashboard.

New run page

Collects the launch brief before the analysis starts.

Run page

Shows:

  • launch board summary
  • verdict
  • pipeline progress
  • top findings
  • screenshot + HTML evidence
  • persona replay
  • rewrite suggestions
  • extracted signals

Architecture

apps/
  web/        -> Next.js control plane and UI
  worker/     -> queue consumers, capture, extraction, synthesis
packages/
  shared/     -> schemas, constants, shared contracts
  db/         -> Prisma schema and DB client
  ui/         -> shared UI package placeholder

System roles

Web app

  • launch brief intake
  • run creation
  • run detail rendering
  • artifact serving

Worker

  • consuming queued runs
  • fetching page data
  • rendering screenshots
  • extracting signals
  • creating findings
  • generating summaries, persona outputs, and rewrites

Database

  • audit runs
  • page captures
  • artifacts
  • extracted signals
  • findings
  • persona replays
  • rewrite suggestions
  • analyzer outputs

Redis / queue

  • background execution for launch runs

Tech stack

Frontend

  • Next.js 16
  • React 19
  • TypeScript
  • Tailwind CSS
  • React Hook Form
  • Zod

Backend / worker

  • Node.js
  • TypeScript
  • BullMQ
  • Redis
  • Playwright

Data layer

  • Postgres
  • Prisma

Quickstart

Prerequisites

  • Node.js 22 (the version used by the deployment configuration)
  • pnpm 9.15.0 (see packageManager in package.json)
  • Docker for the local Postgres and Redis containers below

1) Install dependencies

pnpm install --frozen-lockfile

2) Start Postgres

docker run --name limen-postgres \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_PASSWORD=postgres \
  -e POSTGRES_DB=limen \
  -p 5432:5432 \
  -d postgres:16

If already created:

docker start limen-postgres

3) Start Redis

docker run --name limen-redis -p 6379:6379 -d redis:7

If already created:

docker start limen-redis

4) Create local env

cp .env.example .env
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/limen"
REDIS_URL="redis://localhost:6379"

5) Generate the Prisma client and apply migrations

pnpm --filter @limen/db prisma:generate
DATABASE_URL='postgresql://postgres:postgres@localhost:5432/limen' \
  pnpm --filter @limen/db prisma:deploy

6) Install Playwright browser

pnpm --filter worker exec playwright install chromium

7) Start the web app

DATABASE_URL='postgresql://postgres:postgres@localhost:5432/limen' \
REDIS_URL='redis://localhost:6379' \
pnpm --filter web dev

8) Start the worker

In another terminal:

DATABASE_URL='postgresql://postgres:postgres@localhost:5432/limen' \
REDIS_URL='redis://localhost:6379' \
pnpm --filter worker dev

Local development

Run workspace commands from the repository root. The web app and worker run in separate terminals.

The worker loads the root .env on Node.js 22. For the web app, put DATABASE_URL and REDIS_URL in apps/web/.env.local, or keep the inline environment variables shown in the quickstart.

Once the dev server is ready, open the local app or the new run form.

HTML and PNG artifacts default to the worker's .artifacts directory. ARTIFACT_STORAGE_PATH can select an absolute directory; the web process must be able to read the paths saved by the worker. Separate hosts need shared storage for artifact previews.

  • pnpm dev:web starts the web development server from the repository root.

  • pnpm dev:worker starts the worker in watch mode from the repository root.

A partial_failed run can still include captured evidence and deterministic findings. This status is used when no reasoning provider is configured or all configured reasoning providers fail.

Troubleshooting

  • Run stays queued: start the worker and check that both processes use the same REDIS_URL and DATABASE_URL.

  • Database connection or missing table errors: check the Postgres container and DATABASE_URL, then apply the existing migrations from the quickstart.

  • Missing Chromium executable: run pnpm --filter worker exec playwright install chromium in the environment that runs the worker.

  • Artifact preview returns 404: check that the file still exists and is readable by the web process. A database record alone does not restore a deleted artifact file.

Useful commands

Typecheck

Use pnpm typecheck to check all workspace packages, or target them individually:

pnpm --filter web typecheck
pnpm --filter worker typecheck
pnpm --filter @limen/db typecheck
pnpm --filter @limen/shared typecheck
pnpm --filter @limen/ui typecheck

Build worker

pnpm --filter worker build

Generate Prisma client

pnpm --filter @limen/db prisma:generate

Create a migration

After editing packages/db/prisma/schema.prisma, create a named migration against your local development database:

DATABASE_URL='postgresql://postgres:postgres@localhost:5432/limen' \
  pnpm --filter @limen/db prisma:migrate --name <migration-name>

Build web

pnpm --filter web build

Lint web

pnpm --filter web lint

The worker and shared package lint scripts are currently placeholders; they do not perform lint checks.

Inspect migration status

DATABASE_URL='postgresql://postgres:postgres@localhost:5432/limen' \
  pnpm --filter @limen/db exec prisma migrate status --schema ./prisma/schema.prisma

Current project status

Working today

  • launch run creation
  • queue-backed worker execution
  • HTML fetch
  • Playwright screenshot capture
  • artifact persistence
  • extracted signal persistence
  • finding generation
  • verdict generation
  • launch summary
  • persona replay
  • rewrite suggestions
  • artifact preview UI
  • extracted signals UI

Still evolving

  • issue prioritization quality
  • stronger launch-board scoring/rubric
  • more grounded persona replay
  • more concrete copy rewrites
  • clearer distinction between telemetry and user-facing issues
  • deeper screenshot-aware analysis
  • final UI polish for launch-grade presentation

Run API

POST /api/runs accepts a JSON launch brief. A successful response queues background work; it does not mean the analysis has finished.

competitors is optional and accepts up to five nonempty strings, each at most 200 characters.

objections must contain 1–8 nonempty strings, each at most 200 characters.

Text lengths: audience 3–200 characters, desiredAction 2–120, offer 2–240, and brandVoice 2–120.

Supported trafficChannel values are cold_paid, branded_search, founder_social, and launch_day.

Send the request with Content-Type: application/json:

{
  "url": "https://example.com",
  "audience": "Independent software founders",
  "trafficChannel": "cold_paid",
  "desiredAction": "Start a free trial",
  "offer": "A launch review for landing pages",
  "objections": ["Unsure how much setup is needed"],
  "brandVoice": "Clear and practical"
}

On success, the API returns HTTP 200:

{"runId": "<run-id>", "status": "queued"}

HTTP 400 includes error and issues fields when the JSON launch brief fails validation.

HTTP 500 reports that a run could not be created or queued; inspect the web server logs for the underlying error.

Open /runs/<runId> in the web app to follow progress and review results.


Example flow

Step 1

Create a launch run.

Step 2

Enter:

  • page URL
  • target audience
  • channel (for example cold_paid)
  • desired action
  • offer
  • objections
  • brand voice

Step 3

Limen will:

  • validate the URL
  • capture page HTML
  • render a screenshot
  • extract structure and trust signals
  • generate findings
  • produce a verdict
  • explain likely visitor reactions
  • propose copy improvements

Step 4

Review:

  • summary
  • top reasons
  • top fixes
  • findings
  • evidence
  • persona replay
  • rewrite suggestions

Design principles

Evidence before confidence

Findings should be backed by captured artifacts and structured signals.

Launch context matters

A page should not be judged without its audience and channel.

Decision support beats generic diagnostics

The product should answer:

  • should I launch?
  • why not?
  • what do I fix first?

Operator-facing outputs matter

Findings alone are not enough. Teams need summaries, personas, and actionable rewrites.


Roadmap direction

Potential next improvements:

  • cleaner separation between telemetry and user-facing findings
  • stronger ranking model for blockers vs opportunities
  • better verdict logic tied to launch readiness dimensions
  • more concrete rewrite outputs
  • more evidence-linked persona replay
  • screenshot-region-specific analysis
  • side-by-side before/after comparisons
  • preview URL support
  • launch history and regressions

Deploying on Zerops

Limen is fully configured for automated cloud deployment and vertical auto-scaling on Zerops.

1. Import Services & Infrastructure

Create the project and provision all required services (Next.js web app, background worker, managed PostgreSQL, and KeyDB queue) using the provided zerops-project.yml:

# Using the Zerops CLI (zCLI)
zcli project service-import zerops-project.yml

Or paste the contents of zerops-project.yml directly into the Zerops GUI under Project > Import Services.

2. Connect Your Repository & Deploy

  1. In your Zerops project dashboard, connect your GitHub repository to both the web and worker services.
  2. Zerops will detect zerops.yml and automatically run the build, dependency installation, browser binary provisioning, and database schema synchronization.

3. Environment Variables

Zerops automatically injects database and queue connection strings. Configure your LLM API keys in the Zerops GUI under the worker service environment variables:

Variable Description Required
DATABASE_URL Injected automatically by Zerops (${db_connectionString}) Yes
REDIS_URL Injected automatically by Zerops (redis://${redis_hostname}:${redis_port}) Yes
GEMINI_API_KEY Google Gemini; first reasoning provider when configured Recommended
GROK_API_KEY Grok; tried after Gemini Optional
ANTHROPIC_API_KEY Anthropic; tried after Grok Optional
OPENAI_API_KEY OpenAI; tried after Anthropic Optional

Repo structure

apps/
  web/
  worker/
packages/
  db/
  shared/
  ui/

This repository intentionally focuses on the product code. Internal planning, local research, and non-essential local files are excluded from GitHub.


Vision

Limen is not trying to become another generic audit dashboard.

The long-term goal is to become the layer teams run before launch to answer:

Is this landing page ready for the traffic we’re about to send?

That means Limen should eventually become:

  • more context-aware
  • more evidence-backed
  • more trustworthy
  • more decisive
  • more useful in real launch workflows

Final note

Limen already runs a real end-to-end launch review pipeline.

The next stage is making that intelligence:

  • sharper
  • more trusted
  • more product-ready

Don’t ask whether the page exists. Ask whether it’s ready.

About

Web-launch reviews with captured page evidence, background jobs, and actionable reports. Built with Next.js, TypeScript, PostgreSQL, Redis, and BullMQ. In development.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages