尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证AI project planner with editable briefs and starter prompts (Next.js, OpenRouter)
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗Turn a rough app idea into an editable project brief and an executable starter prompt for a coding agent. The brief covers app summary, target users, features (plain or spec-kit), tech stack, routes, data model, build phases, risks, and a distilled hand-off prompt.
Next.js App Router · React 19 · Tailwind CSS v4 · shadcn/ui · AI SDK v7 · OpenRouter · React Flow · Zod
.env (or .env.local):
OPENROUTER_API_KEY=your_openrouter_key
OPENROUTER_MODEL=anthropic/claude-sonnet-4.6 # optional
# Redis — required for sharing; enables rate limiting in production.
# Use EITHER the Vercel-KV names or Upstash's native names (both are read):
KV_REST_API_URL=https://...upstash.io
KV_REST_API_TOKEN=...
# …or, when bringing your own Upstash database (copy-paste from the console):
# UPSTASH_REDIS_REST_URL=https://...upstash.io
# UPSTASH_REDIS_REST_TOKEN=...
Provide the Redis credentials one of two ways:
KV_REST_API_URL / KV_REST_API_TOKEN.UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN from the Upstash console into either name pair.For local development, pull the Vercel values with vercel env pull .env.local. Redis is optional locally — without credentials, rate limiting is disabled (a no-op) and the app runs normally; only sharing requires the store.
The eval CLI reads the same key.
npm install
npm run dev
Open http://localhost:3000.
No credentials are needed to run the test suite, type-check or build — every value in .env.example is read at request time, not build time:
npm test
localStorage. Otherwise you see an empty dossier and a textarea.#s=<id> URL. Anyone with the link sees the same brief.The textarea is intentionally a one-shot rough sketch — keep it short. Two sentences is plenty. When you click Generate brief, the app makes a short first LLM call to /api/clarify and returns 3–5 idea-specific questions before generating anything.
The questions are not boilerplate. For "A SaaS for tracking team OKRs with Stripe billing" it will ask about OKR hierarchy depth, billing structure (per-seat vs flat vs tiered), and how teams update progress. For "A decision log for small teams" it will ask about multi-user, persistence, and Slack integration. Each question has 2–5 options plus an optional Other… free-text fallback. When several answers can apply at once (target platforms, integrations, content types), the question is marked "Select all that apply" and you can toggle multiple options; mutually-exclusive questions stay single-choice.
You can Skip questions at any time — useful when your idea already specifies the answers. Answered or skipped, your answers are forwarded as extra context to the brief-generation call.
Toggle this on when you want each feature spelled out in GitHub spec-kit format — the structured format senior product/engineering teams use to write reviewable specs.
With spec-kit mode ON, the brief generates 3 to 5 feature specifications, each with:
FR-001, FR-002, ... with MUST language. Unresolved details are marked [NEEDS CLARIFICATION: ...].SC-001, SC-002, ... — measurable and technology-agnostic.With spec-kit mode OFF, the brief is plain mode: just coreFeatures as bullet labels. Faster to skim, less work to maintain, suitable for personal projects or quick prototypes.
You can toggle spec-kit on or off between generations. The starter prompt distillation deliberately omits the FR-### / SC-### IDs — those are useful inside the dossier for editing and review, but adding them to an executable agent prompt creates noise without value.
The planner always picks a stack appropriate to the idea. If you describe a SaaS with Stripe billing, you'll get Stripe, Postgres, Prisma, NextAuth, and a background queue in the recommended stack — no apologies, no silent scope reduction. This is a tool for shipping real things, not tutorials.
The /api/plan endpoint streams NDJSON — one JSON event per line — with four event types:
partial — a partial brief; the client renders a live preview that fills in section by section.status — short progress messages like "Distilling starter prompt…".done — the final brief plus the LLM-distilled starter prompt and model id.error — the run failed and no done will follow. The planner reports its own failures on the stream rather than by throwing, so a request that has already started streaming still ends with a 200.A brief is only sent as done once it validates against the full schema. The stream yields deep partials, so a model that stops mid-object — usually on maxOutputTokens — leaves a brief that looks complete but is not; that case ends in error rather than a done carrying half a brief.
This is why sections appear progressively in the UI rather than all at once. End-to-end time is typically ~25–45 seconds; first content shows up in 3–5 seconds.
Each section card with a Regenerate button covers one piece of the brief: Feature Specifications, Pages & Routes, Data Model, Build Phases, Risks & Edge Cases. Click Regenerate, optionally type a constraint, click Run (or press Enter).
Behind the scenes the app POSTs to /api/plan/section with:
The model replaces only that section. Other sections, your edits, and the starter prompt are untouched. Examples of useful constraints:
When the data model is regenerated, the client also prunes any relationships that reference entity ids that no longer exist — your visualisation stays consistent.
Two views on the same data:
The Data Model editor card is where you actually change things. Add an entity. Rename one (and every relationship referring to it is updated automatically). Edit fields as a newline-delimited list. Add or remove relationships using dropdowns of source/target entity ids.
The React Flow diagram on the left is a live visualisation of the data model. As you edit entities or relationships in the editor, the graph re-renders immediately — and so does it during the initial stream as the model arrives.
The diagram lets you:
+ / − controls.Each entity shows its name and the first few fields. Relationships are labelled edges between entity nodes. This view is read-only on purpose — the editor card is the source of truth, and the diagram is for sanity-checking the shape of your data model at a glance.
At the bottom of the dossier is the Coding Agent Starter Prompt. This is the artifact you copy into your coding agent. It is not a concatenation of the brief sections — it's a separate LLM call that distils the brief into an executable instruction set with five sections:
# Intent — one paragraph: what to build and why.# Hard Constraints — bullet list, pulled from the brief's tech stack and mode choices.# MVP Slice — the P1 user story rendered as "when complete, the user can …" capabilities.# File Layout — concrete paths the agent should create, matching the brief's routes and data model.# Start Here — 2–4 numbered first steps, with a final instruction asking the agent to confirm understanding before continuing.Target length is 600–800 words. The distillation deliberately skips internal field ids (FR-001, SC-001) and risks-and-edge-cases content — those live in the brief for humans to review, not for the agent to execute.
"Regenerate from brief" is the button next to Copy prompt. Use it whenever you've edited the brief (renamed an entity, added a route, regenerated risks) and want the starter prompt to reflect the new state. It re-runs the same distillation pass via /api/starter-prompt, replacing only the prompt text. Your edits everywhere else are kept.
Copy prompt writes the current prompt text to your clipboard for pasting into Claude Code, Cursor, ChatGPT, or any other coding agent.
If the distillation call fails for some reason, the app silently falls back to a deterministic concatenation so you always have something to copy.
The Share button in the masthead does the following:
/api/share.http://your-host/#s=<id> and writes it to your clipboard.Anyone opening that URL — incognito, different browser, different machine — will have the app fetch /api/share?id=<id> on mount, hydrate the brief, clear the hash from the address bar, and auto-save the brief to their own localStorage. They can edit, regenerate, and re-share from there independently.
Trade-offs to know:
#s=<id> URLs return a "share is no longer available" error. KV_REST_API_URL and KV_REST_API_TOKEN must be set (see Environment above); a Vercel Marketplace Upstash for Redis integration provisions them automatically.crypto.randomUUID() (128-bit) and expire after 30 days.Every change to a brief — generation, edit, section regeneration, starter-prompt regeneration — auto-saves to localStorage under plan-architect:brief:<id>. The most-recent brief id is tracked separately, so a hard refresh restores exactly the state you left.
There is no UI for managing multiple saved briefs in this version, but the data is all there in localStorage if you need it. Generating a fresh brief mints a new id; the previous one stays in storage until the browser evicts it.
| Endpoint | Purpose |
|---|---|
POST /api/clarify | Returns 3–5 idea-aware clarifying questions. |
POST /api/plan | Streams a project brief (NDJSON: partial → status → done). |
POST /api/plan/section | Regenerates a single section of an existing brief. |
POST /api/starter-prompt | Re-distills the starter prompt from a brief. |
POST /api/share | Stores a brief in Upstash Redis (30-day TTL); returns a UUID. |
GET /api/share?id=<id> | Returns the stored brief for #s=<id> hydration. |
All endpoints share a Redis-backed rate limiter keyed by client IP, taken from
x-forwarded-for — the one header Vercel overwrites rather than forwards, and
therefore the only one a client cannot spoof to earn itself a fresh bucket.
Treat it as defence-in-depth, not as a security boundary.
The POST endpoints reject cross-origin requests via an Origin header check.
This app is designed for a single-user deployment behind Vercel Password Protection. The threat model assumes:
The deployment URL is protected — Vercel Password Protection (Pro/Enterprise) or your equivalent SSO/proxy gate sits in front of every route, including /api/*. Without this gate, the AI endpoints will silently bill your OpenRouter key for anyone who finds the URL.
The OpenRouter key never leaves the server. It is read only from process.env.OPENROUTER_API_KEY inside route handlers. There is no NEXT_PUBLIC_* exposure.
Briefs are not multi-tenant. Anyone past the gate can read any share-link payload.
If you instead want a public deployment, replace Password Protection with: real auth (NextAuth / Clerk), per-user scoping on the share store, and Turnstile/hCaptcha on AI endpoints. The current code is not hardened for that scenario.
The codebase ships with the following protections:
next.config.ts and proxy.ts: CSP, HSTS, X-Content-Type-Options, X-Frame-Options: DENY, Referrer-Policy, Permissions-Policy.GET /api/share to prevent enumeration.crypto.randomUUID() share ids (128 bits) with a 30-day TTL..max() on every brief field, and a 64 KB JSON ceiling on every route that accepts a whole brief — /api/plan/section, /api/starter-prompt and /api/share. On share that ceiling is also what bounds Redis growth: one write per request against a 30/hour budget.maxOutputTokens cap on every AI call (default 8000, override with OPENROUTER_MAX_OUTPUT_TOKENS).requestId.See eval/README.md. Quick start:
npm run dev # in a separate terminal
npx tsx scripts/eval.ts "A decision log for small teams"
# → eval/results/<timestamp>.json
The eval pipes your generated starter prompt through Claude (as if it were a coding agent receiving the spec) and scores the response on:
Use it as a regression signal when tuning the distillation prompt — the absolute numbers matter less than how they move between runs.
npm run dev # local development
npm test # node:test suite (no network, no credentials)
npm run lint # eslint
npm run build # production build
.github/workflows/ci.yml runs on every pull request and on pushes to main:
lint, test, tsc --noEmit, build, on Node 22 and 24. 22 is the floor engines declares, so CI checks that claim rather than assuming it. tsc is a separate step because next build does not fail on type errors.npm audit --audit-level=high, in its own job so a newly published advisory reads as an advisory rather than a broken test.Tests are plain node:test under tests/, run through tsx. They cover the planner's event stream, the share payload bounds, the rate limiter's client-IP key, and the eval scoring. None require network access or credentials, so the whole suite runs in well under a second.