Updated 2026-10-08 — corrected documentation guidance; operational evidence retains its original dates.
Local-first medical guideline RAG knowledge base for a psychiatrist in Perth, Australia. The app uploads private clinical reference documents to Supabase Storage, indexes text and extracted image captions into pgvector, and answers questions with source citations that link back to the original PDF/document.
For agent tasks, start with AGENTS.md and the task navigator. The documentation index distinguishes maintained guides, generated views and historical evidence.
- Use Node.js 24.x with npm 11.x. CI runs on Node 24, and
.nvmrc/.node-versionpin the same runtime for local version managers. CI also runsnpm run check:edge:functions, which requires Deno v2.x. - Install dependencies:
npm ci --include=devThis is the clean-checkout and validation install contract. Use npm install
only when intentionally changing dependencies and regenerating
package-lock.json.
Codex Desktop worktrees use npm run setup:codex-worktree. The local bootstrap
reuses dependencies only from a complete worktree with a byte-identical lockfile,
then validates the installed metadata. It falls back to the locked install above
when no safe local donor exists. Do not configure Windows Desktop worktrees to run
the Cloud-only Bash setup script.
For Codex Cloud, start with the current-host guide and actual task capabilities. The older repository-managed bootstrap is archived and applies only when explicitly selected. Do not impose its profiles, command shims or startup checks on another host setup.
- For offline app development, use a credential-free
.env.localcontainingNEXT_PUBLIC_DEMO_MODE=true. Use the synthetic corpus; leave Supabase and OpenAI credentials unset and do not start the ingestion worker. Preserve any existing environment file rather than overwriting it. Demo mode is an app setting, not a security boundary for workers or arbitrary scripts. - For separately authorised connected development, copy the full
.env.exampleto a new.env.localand supply credentials only for the approved target and workload. Retain its worker/upload defaults, but do not assume those defaults isolate production. Confirm the Supabase target:
This is a provider-backed check. Obtain the required explicit authorisation before running it; it is not a prerequisite to documentation or other offline-only work.
npm run check:supabase-projectThe expected live project is PsychSift Production:
NEXT_PUBLIC_SUPABASE_URL=https://sjrfecxgysukkwxsowpy.supabase.co
SUPABASE_PROJECT_REF=sjrfecxgysukkwxsowpy
SUPABASE_PROJECT_NAME=PsychSift ProductionDo not use the older unused Supabase project Database
(qjgitjyhxrwxsrydablr). Local checks and runtime guards warn or fall back to
demo mode if that stale ref appears in .env.local.
- Database bootstrap:
- Existing
PsychSift Productionproject: this is the live project. Normal local development does not require a SQL editor bootstrap step. Current schema and migration status require the approved live checks; this README is not proof that a particular migration has been applied. - New staging or fresh database: with explicit authorisation for the target and migration application, link the Supabase CLI to that approved project, then apply committed migrations when local and remote histories align. Replace the placeholder below with that project's ref; the live ref above is not a staging target:
npx supabase link --project-ref <approved-staging-project-ref>
npx supabase migration list --linked
npx supabase db pushTreat supabase/schema.sql as a reconciled reference mirror, not the primary
onboarding path. For drift, repair policy, and live-only caveats, see
docs/supabase-migration-reconciliation.md and the retrieval RPC section in
docs/process-hardening.md.
- Install Deno v2.x to run Edge Function type checks
(
npm run check:edge:functions). CI installs Deno automatically viadenoland/setup-deno. For local use, follow the Deno installation guide and ensuredeno --versionreports a 2.x release. - Install optional PDF/OCR worker dependencies:
python -m pip install -r worker/python/requirements.txt- Start the demo app:
Run the Next.js app:
npm run devThe dev command uses a stable project-specific localhost port derived from this
folder path, so it does not silently reuse common ports such as 3000, 3001,
or 3002 from another local project. It prints the exact URL every time, for
example http://localhost:37xx. If the stable project port is already busy, it
uses the next free localhost port and prints that fallback URL.
For chat-driven work, use:
npm run ensureThis checks whether PsychSift is already running, verifies the local server
belongs to this project, and starts the dev server in the background if needed.
When you say run in this chat, Codex should use this command and return the
printed URL.
- Connected ingestion only: after explicit approval for the database, workload, provider calls and spending, start the worker in a second terminal:
npm run workerThe Next.js API stores uploads and queues ingestion jobs. The worker performs
heavy parsing, OCR, image captioning, chunking, embedding, and database inserts.
It uses the worker defaults from .env.example when those vars are set in
.env.local. These defaults do not prevent live database claims or provider calls.
Docker Compose starts only the app; the worker is opt-in.
docker compose --env-file .env.local up --build builds and starts the app tier
only. Compose has no default Supabase URL: it fails fast unless
NEXT_PUBLIC_SUPABASE_URL is supplied (--env-file, the shell or .env; the
optional .env.local env_file alone does not feed ${...} interpolation).
It does not create an isolated local Supabase database.
The ingestion worker sits behind the worker profile because production
credentials would let it consume production jobs. Start it only with explicit
connected-workload approval for the target:
docker compose --env-file .env.local --profile worker up --build.
The worker container serves /health on internal port 3901 for its Compose
healthcheck (nothing is published). The Compose app mapping is
http://localhost:3000; stop the stack with docker compose --env-file .env.local --profile worker down.
This mapping does not replace the project-identity checks for development servers above.
package.json requires Node >=24.15.0 <25 and npm 11.x. The version-manager,
container and CI pins must remain compatible with that contract; Node 22 is not
a supported downgrade. The official Node.js release schedule
lists Node 24 end of life as 2028-04-30. A future runtime migration needs an
intentional dependency/toolchain change and the applicable local and release
checks; this documentation correction changes no runtime pins.
Use the current Cloud policy and host readiness evidence. Provider-free work remains provider-free; it does not require a particular historical profile. The archived bootstrap retains its own toolchain and acceptance contract for environments that explicitly select it.
SUPABASE_SERVICE_ROLE_KEYis server-only. Never expose it in the browser.SUPABASE_PROJECT_REFmust staysjrfecxgysukkwxsowpyfor the livePsychSift Productionproject.- Documents and extracted images are stored in private Supabase buckets.
- Initial assumptions are guideline/reference documents only, not patient identifiable records.
- OpenAI receives extracted document text/images for embeddings, image captions, and grounded answer generation.
MAX_UPLOAD_MB,CHUNK_SIZE, andCHUNK_OVERLAPare deliberately conservative defaults for local-first indexing.
- This project is a clinical reference prototype, not validated clinical decision support.
- Demo documents are synthetic and are not clinical guidance.
- Do not upload patient-identifiable documents unless local governance, privacy, and data-processing approvals explicitly allow it.
- Generated answers and copied drafts must be verified against linked source documents, source status, local policy, and patient context before clinical use.
- Production deployment needs clinical governance review, source approval rules, and TGA Software as a Medical Device screening where applicable.
- See
docs/clinical-governance.mdfor the deployment governance checklist.
This repo ships workspace Supabase MCP config in .cursor/mcp.json and agent
skills under .cursor/skills/supabase*. Use them for database inspection,
advisors, and docs lookup — not as a replacement for committed migrations.
- Open Cursor Settings → Tools & MCP and enable the
supabaseserver. - Complete the one-time OAuth flow in your browser. Choose the Supabase org that
owns PsychSift Production (
sjrfecxgysukkwxsowpy). - Reload the window, then verify with a prompt such as: "List tables using Supabase MCP."
- Keep manual tool-call approval enabled. Review SQL and migration actions before they run on live data.
- Run
npm run check:supabase-projectafter any Supabase env or MCP config change.
Defaults in .cursor/mcp.json:
project_ref=sjrfecxgysukkwxsowpy— scoped to the livePsychSift ProductionSupabase project onlyread_only=true— safer default for exploration and reviews
Keep this production MCP URL read-only. Run schema experiments only on an explicitly
identified local or scratch database with synthetic data and separate configuration.
Production write capability is not a setup step: any live database or settings change
requires Josh's explicit permission for that specific change under the
database-change approval rule.
Use reviewed committed migrations for durable schema changes; merging a migration
to main applies it to production and requires the applicable approved window.
Cursor cloud agents are prohibited for this repository (see AGENTS.md). Other
hosted agents do not inherit desktop OAuth; authenticate MCP where that agent
runs and start a fresh session.
Never put SUPABASE_SERVICE_ROLE_KEY or other secrets into MCP config. The
hosted Supabase MCP server uses OAuth, not repo secrets.
Use the shared Context7 guide for library resolution,
version matching, MCP/CLI authentication and query privacy. The checked-in
Cursor integration is local @upstash/context7-mcp@3.2.5; a selected hosted
connector has separate authentication. For Next.js APIs, read the installed
node_modules/next/dist/docs/ as required by AGENTS.md. Never include patient
information or private document content in documentation queries.
The Cursor Figma plugin plus .cursor/mcp.json (https://mcp.figma.com/mcp)
give design ↔ code access (capture live UI, read/write frames, Code Connect).
Enable the plugin / MCP server, complete browser OAuth once, then verify with a
prompt such as: "Call Figma whoami and report only handle and plan tier."
Cursor Cloud Agents are prohibited for this repository. Use
Cursor Desktop (or Codex with its Figma plugin) for Figma MCP. Repo
.cursor/mcp.json helps the IDE only. Details:
docs/agents-guide.md, docs/codex-cloud.md.
Process and freshness (Documentation agent): docs/DOCS-SYSTEM.md — pipeline, doc classes, recheck triggers, PsychSift registry.
Full categorized index: docs/README.md (maintained docs vs point-in-time
records vs archive). The most load-bearing entries:
docs/codebase-index.md— architecture and module map (start here)docs/site-map.md— generated route map (npm run docs:update)docs/process-hardening.md— verification gates, CI expectations, known limitsdocs/testing.md— local test safety, focused/live commands, Playwright ownership, flake policydocs/codex-cloud.md— current-host Cloud guide and explicit legacy-bootstrap selectiondocs/clinical-governance.md— deployment and source governance checklistdocs/deployment-architecture.md— app/worker/Supabase deployment topologydocs/supabase-migration-reconciliation.md— migration drift and repair policy
Run npm run docs:check-links to verify repo paths referenced from the
maintained docs still resolve.
Verification gates (see package.json for the full chain):
npm run verify:cheap # ordinary offline gate: check:installed-lock-parity
# + Codex hook tests + check:diff-integrity + lint
# + typecheck + test
npm run verify:full # static/consistency gates (check:runtime through
# check:offline-pack; `npm run check:gate-manifest`
# lists them from verify:full:internal) then lint +
# typecheck + test — does not invoke the cheap script
npm run verify:pr-local # risk-routed PR mirror: focused docs/workflow contracts
# for recognised light scope; fail-closed lint/typecheck/
# full unit (+ build/domain) for executable or unknown
# scope. Inspect with `-- --dry-run --files <paths>`
npm run verify:ui # check:runtime + required production Chromium journeys
npm run verify:release # check:runtime + lint + typecheck + test + build + test:e2e
# + check:production-readiness + governance:release
# + eval:quality:release (needs live Supabase + OpenAI keys)Use npm run verify:pr-local -- --dry-run --files <comma-separated paths> to
inspect which checks a change would trigger without running them.
CI is risk-scoped (.github/workflows/ci.yml): a changes job classifies
changed paths, static-pr always runs a small baseline (runtime alignment,
installed-lock parity, the CI-scope and verification-plan self-tests, diff
integrity, and the changed-file format check) and selects the rest — the
action-pin check, lint, typecheck, and the other static gates — by change
scope, and pr-required is the single
always-reporting required aggregate (required PR checks are Gitleaks plus that
aggregate). One full unit run with coverage, build, safety/config checks, the
production Chromium gate, the repo-owned Supabase db-reset-verify migration
replay, and both Docker image builds run only when their file scopes apply; a
failed applicable container build therefore fails pr-required. UI PRs also
get one non-blocking advisory Chromium invocation. The full Playwright browser matrix
(release-browser-matrix) runs on release/*, manual dispatch, and a weekly
schedule, and on main when the diff is in UI, performance or lockfile scope. It is
not part of pr-required, so it is a post-merge signal rather than a merge gate. Live drift and live eval canary checks remain provider-gated;
Docker image builds also run independently on main/release pushes, schedule,
and manual dispatch. They are not required for source-only PRs outside the
container scope.
npm run dev # Next.js UI/API on this project's stable localhost port
npm run ensure # check/start this project's dev server in the background
npm run start # production preview on the same safe port selection
npm run worker # local ingestion worker
npm run check:supabase-project
npm run check:production-readiness # run production readiness validation preflight
npm run check:production-readiness:ci # CI-safe readiness preflight (env-absent tolerant)
npm run samples # generate synthetic upload corpus
npm run samples:check
npm run lint
npm run typecheck
npm run test
npm run test:focused -- --files tests/a.test.ts,tests/b.test.ts # replace with real paths
npm run test:live # requires ALLOW_PROVIDER_TESTS=true
npm run test:coverage
npm run test:e2e
npm run test:e2e:pr
npm run test:e2e:advisory
npm run test:e2e:all
npm run test:e2e:accessibility
npm run test:e2e:chromium
npm run test:e2e:visual
npm run check:deployment-readiness
npm run format
npm run format:check
npm run buildYou can still override the port explicitly when needed:
PORT=4200 npm run dev
npm run dev -- --port 4200On Windows PowerShell:
$env:PORT = "4200"; npm run dev
npm run dev -- --port 4200When multiple chats or projects are open, use the URL printed by the command
instead of assuming a shared address such as http://localhost:3000.
Codex should also run npm run ensure before browser QA or before handing you a
local app link after meaningful frontend changes.
npm run ensure starts its dev server detached, so it keeps running after the
task/session that launched it ends. To stop these from accumulating, that
server self-exits after 45 minutes with no request or build activity by
default. Override with DEV_SERVER_IDLE_MINUTES (a plain npm run dev you
run interactively is unaffected unless you set it yourself); 0 disables the
idle shutdown entirely.
Run npm run samples to generate synthetic documents under
sample-documents/. They cover PDF, DOCX, XLSX, TXT, PDF image extraction, and
a scanned-style PDF for OCR fallback testing. Upload those files through the UI
and start npm run worker to index them. The sample content is deliberately
synthetic and must not be used as clinical guidance.
sample-documents/ is generated local test output and is intentionally ignored
by Git. The smaller public/demo-documents/ set is tracked because the app uses
it for demo-mode source and image rendering when live Supabase setup is
unavailable.
Report vulnerabilities privately — see SECURITY.md. Do not open a public issue for
a security problem. Threat models and the privacy assessment live under docs/
(rag-injection-threat-model.md, audit/tenancy-defense-in-depth-review.md,
privacy-impact-assessment.md).
Copyright (c) 2026 BigSimmo, for material owned by or validly assigned to the Repository Owner. Other rightsholders retain their respective rights. All rights reserved.
This repository is publicly visible for inspection, but Repository Owner-controlled material is proprietary, is not open source, and is not in the public domain. No permission is granted to use, run, copy, modify, redistribute, deploy, commercialise, scrape, or use that material for AI or machine-learning development except as required by GitHub's applicable terms, applicable law, or express prior written permission.
See LICENSE for the proprietary rights notice,
THIRD_PARTY_NOTICES.md for the ownership boundary
and embedded licences, and CONTRIBUTING.md for the signed
assignment requirement that applies before an external contribution may be
merged. The "license": "UNLICENSED" declaration in package.json is
intentional.