Chat-first PM research workspace: clarify → pick sources/depth → approve → run specialized tools with citations, Markdown artifact, and export.
- Open the app — centered composer and suggestion chips.
- Start a session — left sessions rail appears; optional layout emphasis on the artifact panel when findings exist.
- Chat with the lead agent — planning tools only until you Approve plan (server sets
plan_approved_at). - After approval — execution tools (stubs in T0) can run; Stop / Skip are wired with telemetry.
- Refresh or export Markdown from the artifact panel.
| Layer | Choice |
|---|---|
| Framework | Next.js 16 App Router |
| UI | React 19, Tailwind CSS 4 |
| AI | Vercel AI SDK + OpenRouter (@ai-sdk/openai) |
| Database | Neon Postgres (@neondatabase/serverless) |
| Analytics | PostHog (browser + optional server) |
| Tests | Vitest |
See .env.local.example. Mandatory for full local flow:
DATABASE_URLRESEARCH_DEV_USER_IDOPENROUTER_API_KEY
Verify keys referenced in code:
grep -r 'process\.env\.' src/ | sed 's/.*process\.env\.\([A-Z0-9_]*\).*/\1/' | sort -u- Authoritative DDL:
schema.sql— run in the Neon SQL editor (or your migration tool) to create tables. - Optional idempotent follow-up:
bun run db:upgrade(usessrc/lib/schema-upgrades.ts).
cd apps/research-copilot
bun install
cp .env.local.example .env.local # then fill secrets
bun run devSuccess: dev server starts and http://localhost:3000 loads the centered composer.
bun run build
bun run lint
bun run test| Method | Path | Body | Response |
|---|---|---|---|
GET |
/api/research/sessions |
— | { sessions } |
POST |
/api/research/sessions |
{ title? } |
{ session } |
GET |
/api/research/sessions/[id] |
— | { session, messages } |
POST |
/api/research/sessions/[id]/chat |
{ messages: UIMessage[] } |
UI message stream |
POST |
/api/research/sessions/[id]/plan/confirm |
{ plan_json? } |
{ session } |
POST |
/api/research/sessions/[id]/stop |
— | { session } |
POST |
/api/research/sessions/[id]/skip |
{ source_id } |
{ ok } |
GET |
/api/research/sessions/[id]/artifact |
— | { brief_markdown, findings_markdown, coverage } |
POST |
/api/research/sessions/[id]/export |
{ which?: 'brief' | 'findings' | 'both' } |
Markdown file |
| Event | Where |
|---|---|
research_session_started |
POST /api/research/sessions |
center_composer_first_message_sent |
Client bootstrap send |
project_rail_revealed |
Client after session create |
research_plan_edited |
Plan option chips |
research_plan_proposed |
propose_plan tool |
research_plan_approved |
POST .../plan/confirm (single emission) |
research_run_started |
First execution tool creating a run |
ai_tool_call_* / research_run_step_completed |
Tool execute |
first_cited_finding_rendered |
NLP stub inserts evidence |
research_steer_issued |
Client send while executing |
research_run_stopped |
POST .../stop |
research_source_skipped |
POST .../skip |
artifact_exported_markdown |
POST .../export |
post_session_survey_submitted |
Session survey |
T2-only: artifact_exported_gdoc (not emitted in T0).
- Tool gating: Execution tools check
plan_approved_atserver-side; planning tools are always available. - Active tools: Until approval, only
ask_clarificationandpropose_planare active instreamTextto reduce accidental tool calls.