원클릭으로
mental-health-dashboard
Practitioner dashboard — patient list, assessment library, Create With AI dialog, navigation bar.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Practitioner dashboard — patient list, assessment library, Create With AI dialog, navigation bar.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Create narrated walkthrough videos and screencasts for the Hermes Mental Health practitioner tutorial. Record, narrate, and publish to GitHub Pages.
Patient profile area — clinical summaries, markdown rendering, demographics editing, consent, assessments, results, invites, and file-based persistence. Synthesize assessment history, severity trends, and progress notes into narrative summaries in English.
Manage assessment invite lifecycle — generate 32-char tokens, create invite links to /a/<token>, track pending/completed status, and manage the invite table.
Review and interpret DSM-5-TR assessment results — score submissions, map severity bands, select and render result charts, detect data-quality issues, and produce clinical interpretations in English.
Draft, audit, and manage patient care plans — synthesize assessment results into structured treatment plans, and evaluate existing plans for clinical gaps, safety concerns, and grounding issues.
Practitioner slash-command workflows for Hermes Mental Health — /assess, /intake, /progress, /safety-check, /privacy-audit.
| name | mental-health-dashboard |
| description | Practitioner dashboard — patient list, assessment library, Create With AI dialog, navigation bar. |
| version | 0.1.0 |
| author | hermes-mental-health |
| license | MIT |
| metadata | {"hermes":{"tags":["mental-health","dashboard","ui"],"category":"mental-health","related_skills":["mental-health-core","mental-health-patient-summary","nextjs-patterns"]}} |
Use when working with the practitioner dashboard UI or when the practitioner asks about:
/patients/[id]data/patients/<id>/profile.json files (see below)useMemo to slice the patients array. Page resets to 1 when page size changes.A "+" button on the dashboard opens a dialog to add new patients. Implementation:
Server action — lib/actions/create-patient.ts (marked "use server"):
FormData with name, ageRange, gender, clinicalBackgroundsanitized-name-<timestamp36>patientSchema via Zoddata/patients/<id>/profile.json (creates directory if needed){ success, patient } or { success: false, error }Dialog component — app/(dashboard)/_components/create-patient-dialog.tsx:
useActionState or plain useState + createPatient() callFilesystem scan — listAllPatients() in lib/data/patients-server.ts (server-only):\n - Reads data/patients/ directory for */profile.json files\n - Parses and validates each, merges with SEED_PATIENTS\n - Deduplicates by id (seed patients win on collision)\n - Marked with \"server-only\" import to prevent fs leaking to client bundle\n - Client-safe patients.ts contains seed data only, no fs
Dashboard page — app/(dashboard)/page.tsx:
listPatients() (now includes filesystem patients)PatientTable/patients/[id])After clicking a patient row, the profile page renders with tabs, clinical summary, and
result detail navigation. Full documentation is in mental-health-patient-summary.
Key entry points from the dashboard:
PatientProfile at app/patients/[id]/_components/patient-profile.tsx — uses
useHydrateAtoms([[activePatientIdAtom, patientId]]) to set active patient synchronously
before first render (avoids 0-count flash on badges)suppressHydrationWarning — localStorage may differ from server seed data?tab= is deferred to useEffect to avoid hydration mismatchThe dashboard shows two assessment sections, in this order:
data/shared/assessments/ via listCustomAssessments(). Shown FIRST, above Available Assessments.data/shared/templates/json/ via listMeasures().Each card shows title, description, slug (monospace), field count badge, chart type badge, scoring type badge, and version badge. Links to editor (/editor/[slug]).
Custom assessment cards (the grid passed custom prop) show a delete button on hover (bottom-2 right-2, opacity-0 group-hover/card:opacity-100). Position at bottom-2 NOT top-2 — the card header has an item count badge at top-right that would overlap. Clicking opens a confirmation Dialog. On confirm, calls deleteCustomAssessment(slug) from lib/actions/assessment-files.ts (server action that deletes data/shared/assessments/<slug>.json), shows toast, and router.refresh().
Dashboard header shows combined count: measures.length + customAssessments.length.
An Agent button (Bot icon, emerald) sits in every page header (Dashboard, Editor, Patient, Result Detail). It is a simple <Link> with context-specifying query params — NOT a modal dialog. Clicking navigates to a dedicated full-route chat page at /agent where users type messages directly (no select options, no prompt picker).
Link hrefs with query params:
// Dashboard
<Link href="/agent?dashboard" ...>Agent</Link>
// Patient profile
<Link href={`/agent?profile&patientId=${patientId}`} ...>Agent</Link>
// Editor
<Link href={`/agent?editor&slug=${slug}`} ...>Agent</Link>
// Result detail
<Link href={`/agent?result&patientId=${result.patientId}&resultId=${result.resultId}`} ...>Agent</Link>
The query params tell the chat page's back button where to navigate (resolved via useSearchParams in the chat component).
Patient sub-page Agent links are dynamic via usePathname() in PatientHeader:
/patients/<id>/assessments → ?assessments&patientId=<id>/patients/<id>/results → ?results&patientId=<id>/patients/<id>/sessions → ?sessions&patientId=<id>/patients/<id>/notes → ?notes&patientId=<id>/patients/<id> (profile) → ?profile&patientId=<id>Nested routes like /patients/<id>/results/<resultId> are handled by pathname.includes("/results/").
Link styling (same className used in all pages):
className="inline-flex items-center gap-1.5 h-7 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] text-emerald-400 hover:text-emerald-300 hover:bg-emerald-500/10 transition-colors"
The /agent page (app/agent/page.tsx) is a full chat interface with:
mental-health-development skill)/api/agent/chat which wraps the Hermes gateway run APIui-content-page-agent-chat, ui-header-agent-chat, ui-content-section-agent-sidebar, ui-content-section-agent-messages, ui-content-card-agent-empty/loading/error, ui-bottom-agent-input — all visible when "UI Labels" checkbox is toggledThe old prompt catalog (lib/prompts.ts) and AGENT_SKILLS mapping still exist in the codebase but are not wired to any UI button.
The /agent page quick-action buttons (below the chat input) inject pre-built prompts via inject*Prompt functions in app/agent/_components/agent-chat.tsx:
| Button | Function | File |
|---|---|---|
| Safety Check | injectSafetyPrompt | agent-chat.tsx |
| Care Plan | injectCarePlanPrompt | agent-chat.tsx |
| Session Note | injectSessionNotePrompt | agent-chat.tsx |
| Progress Report | injectProgressReportPrompt | agent-chat.tsx |
When the user says "change the prompt when I click X in the agent chat", edit the inject*Prompt function in agent-chat.tsx — NOT lib/prompts.ts. The lib/prompts.ts file feeds the old AgentModal dialog (mostly unused) but has NO effect on the /agent chat page buttons.
The dashboard page (app/(dashboard)/page.tsx) shows collapsible green HermesPromptHint components next to section headings (English prompts). Each hint has a close button (X icon) that collapses the green box but keeps the trigger button visible so it can be reopened:
assessment-review)assessment-review)These hints are client components (DashboardPatientsHint, DashboardMeasuresHint from _components/dashboard-hints.tsx). The HermesPromptHint component itself lives at components/hermes-prompt-hint.tsx.
The Agent button (above) is a simple <Link href="/agent"> that navigates to the full chat page — no dropdown, no prompt selection.
The editor route (/editor/[slug]) now supports both template measures and custom assessments:
getMeasure(slug) first (template catalog)loadCustomMeasure(slug) from lib/data/custom-assessments.ts (reads data/shared/assessments/<slug>.json)MetadataForm accepts both slug and measure props — uses the full measure object for custom assessments when template metadata (getMeasureTitle/getMeasureMeta) returns nullmeasure prop directly (already supports custom assessments)Uses the Hermes Gateway API server (hermes gateway) at http://127.0.0.1:8642:
/api/assessments/generate → Hermes Gateway API (POST /v1/runs + poll GET /v1/runs/{id}) → validate → savemake hermes-gateway (sets HERMES_HOME to project .hermes/, API_SERVER_ENABLED=true)/goal command as the input field, with the schema spec as instructionsdata/shared/assessments/<slug>.json via terminal Python one-liner (API-mode agent does NOT have write_file tool)measureSchema, fixes slug, rewrites clean copydata/shared/templates/index.json — filesystem-only from data/shared/assessments/make hermes-gateway-curl-testREADME-CREATE-WITH-AI.md<html class="dark"> is unconditionalreferences/nextjs-pitfalls.md — Jotai hydration, SSR boundaries, MDX Editor dark theme, fs isolationWhen the user asks to change a prompt triggered by a quick-action button in the /agent chat page (Care Plan, Session Note, Safety Check, Progress Report), the prompt text lives in app/agent/_components/agent-chat.tsx as inject*Prompt functions. Do NOT edit lib/prompts.ts — that file feeds the old modal dialog and is not wired to the chat page. Editing it has zero effect on the agent chat buttons.
// ✅ RIGHT — edit the inject*Prompt function in agent-chat.tsx
const injectCarePlanPrompt = () => {
setInput(`Audit the existing care plans...`);
};
// ❌ WRONG — lib/prompts.ts has no effect on the /agent chat page
When adding a close button to the green HermesPromptHint box, the X button should ONLY collapse the green box (setExpanded(false)) — NEVER dismiss the entire component or hide the trigger button. The trigger must stay visible so the user can re-expand the box. Do NOT use a dismissed state that makes the component return null — just toggle expanded.
The lib/prompts.ts file and AGENT_SKILLS mapping are ONLY used by the legacy AgentModal dialog. The /agent chat page has its own hardcoded inject*Prompt() functions in app/agent/_components/agent-chat.tsx. When updating the "Care Plan", "Session Note", "Progress Report", or "Safety Check" buttons, edit the corresponding function in agent-chat.tsx — do NOT edit lib/prompts.ts or agent-modal.tsx.
Prompt format preference: AUDIT pattern (evaluate existing content against patient data, return score/strengths/gaps/revisions) — not GENERATE pattern (draft new content from scratch). Use "Audit" verb, not "Review". Include specific output structure: quality score, strengths, clinical gaps, measurable-goal issues, missing interventions, safety concerns, recommended revisions.
Do NOT nest <Button> inside <DialogTrigger asChild> — both render <button>,
causing a hydration error: "In HTML, <button> cannot be a descendant of <button>."
// ❌ WRONG
<DialogTrigger asChild>
<Button>Open</Button>
</DialogTrigger>
// ✅ RIGHT — use onClick on Button directly, no DialogTrigger wrapper
<Button onClick={() => setOpen(true)}>Open</Button>
When a shared module (e.g., lib/data/patients.ts) imports fs, it leaks into client
components that transitively import it. Fix by splitting server-only code into a
separate module:
lib/data/patients.ts ← client-safe (seed data, no fs)
lib/data/patients-server.ts ← server-only (scans filesystem, imports fs)
The server module starts with "server-only" (npm package) to enforce the boundary.
Server components (pages) import from patients-server; client components stay on
patients.
references/screenshot-capture.md — Camera-ready screenshot capture for docs: AppleScript bounds + screencapture -D2 for Edge browser on secondary display, scrolling, multi-screenshot strategy, window managementreferences/screenshot-analysis.md — Pixel-level UI debugging: OCR + PIL color inspection for detecting active tabs, buttons, and layout when vision analysis fails.references/nextjs-pitfalls.md — Recurring Next.js + shadcn + Jotai patterns: hydration fixes, Recharts quirks, server-only modules, patient data architecture, inline editing.references/mdx-editor-dark-mode.md — MDX Editor (@mdxeditor/editor) dark mode integration: required global CSS (hashed class selectors, portal popups, combobox trigger buttons), z-index for shadcn Dialog, plugin setup, text visibility gotchas, SSR guard pattern.references/agent-chat-prompts.md — Agent chat quick-inject button prompts and skills mapping (Care Plan audit, Session Note audit, Progress Report, Safety Check).references/screenshot-capture.md — macOS screenshot capture workflow: display-level capture with screencapture -D2, browser navigation script, multi-section page strategy.references/docs-generation-workflow.md — Batch screenshot capture, prev/next nav links, logo embedding for docs/*.md pages.