GET /api/version now reads the latest version from Docker Hub image tags (the
actual update channel clinics pull), falling back to the GitHub release if
Docker Hub is unreachable, with a shorter 1h cache and a `?refresh=1` bypass.
Settings → About & updates gains a "Check for updates" button that forces a
fresh, cache-bypassing lookup.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Register `fr` in the i18n config (resources + supportedLngs) and add a full
French translation (locales/fr/translation.json) with exact key parity to
English (1661 keys; placeholders and plural suffixes preserved). Also adds the
shared `common.pagination.*` keys, `settings.version.checkNow`, and
`settings.profile.language.*`, and drops the now-unused `patients.pagination.*`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add GET /api/activity/patient/:fileNumber (every audited change on one chart,
newest first, readable by any clinic member) and surface it as a Record
history timeline in the patient detail sheet. Add a Download summary action
that builds a clean, printable one-page clinical summary in the browser
(Save as PDF) — no PDF dependency, nothing leaves the server.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the COSS Pagination primitive and page the patients list at 10 rows/page
(search resets to page 1; the page is clamped at render so a shrinking list
never strands you past the last page). Replace the flat "secondary" status
badge with semantic colours: active → success, inpatient → info, discharged →
outline. Includes the i18n keys for pagination, the AI setup notice, and the
patient record-history / PDF export features.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resolve the backend URL from the current host at runtime (lib/backend-url.ts)
so one build works on localhost and any clinic LAN IP without a rebuild; used
by the API client, auth client, and socket. Wire the AI-chat mic to the Web
Speech API with graceful fallback. Add a Settings "About & updates" panel
(current/latest version, update command, shareable network address) and an
optional dismissible update banner.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The "Import from a patient app → QR" code baked the web app's own
API_BASE_URL (typically http://localhost:4000) into the pairing URI, so a
real phone could never reach the relay and "Scan to connect" silently
stalled. Use the backend's server-resolved, device-reachable relay URL
instead (PUBLIC_RELAY_URL, else the request host), surface it on the
WalletPairing type, and document PUBLIC_RELAY_URL in .env.example.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Backend: nullable wallet_number on wallet_share_requests (migration 0029);
createPairingRequest + POST /api/patients/wallet/pair; applyShareResponse
binds the authenticated wallet on QR (pairing) requests
- Frontend: Import dialog gains a "Show QR" mode rendering a temetro-pair QR
(react-qr-code) the patient scans; requestWalletPairing helper; i18n keys
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- auth: forgot-password now has Email/Username tabs; new public
/api/auth-helpers/reset-by-username resolves a username and hands off to the
existing reset flow (real email or admin-notify fallback)
- messages: conversations expose isSystem; System notices are read-only (no
composer, no call button) and styled distinctly (shield icon + badge)
- meetings: compact, larger control bar; self tile shows real initials and an
avatar (not black) when the camera is off; delete-room UI with confirm
- sidebar: username-only accounts show @username instead of a synthetic email
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Chat: history pill now shows a History icon + a Start-new-chat (SquarePen)
button; removed the duplicate chat-history list from the sidebar.
Email: deployment-wide email provider config (Resend/Postmark/SendGrid/SMTP) in
Settings → Developers, with encrypted API key and a Send-test action. sendEmail
dispatches via the chosen provider (REST via fetch; SMTP via nodemailer).
Forgot password with no provider: alert the clinic admin(s) via a "System"
message card in Messages + a bell notification (seeded system user + per-clinic
System conversation); clicking deep-links to /settings?tab=careTeam&member=<id>.
Admins can set a member's password directly from the employee dialog
(PATCH /api/staff/:id/password via Better Auth's internal context — no admin
plugin needed).
Patient Portal: "New patient" booking path registers a demographics-only patient
then books; bookings reject double-booked slots (409).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New chrome-less (portal) route group with /portal/[clinic], a card-style choice
of "Book an appointment" vs "View my results", and step flows wired to a new
public backend router (src/routes/portal.ts):
- GET /api/portal/:clinic -> clinic name
- POST /api/portal/:clinic/appointments (verifies name+file#, books a confirmed
appointment that appears on the doctor's Appointments page)
- GET /api/portal/:clinic/results (minimal, safe status — no clinical values)
Excluded /portal from the auth proxy redirect so the kiosk loads without a
session. PHI exposure is intentionally minimal (see docs).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backend: GET /api/settings/records/export downloads the clinic's full patient
archive as JSON; POST /api/settings/records/import creates new patients (skips
existing file numbers, drops cross-clinic provider links). Both admin-gated.
Frontend: Records settings now has a working Export button and an Import flow
(choose file -> preview count -> apply) wired to the new endpoints.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backend: add tasks.assignee_user_id (nullable, fk user) + migration; persist
it through create/update and surface tasks to the assigned person in listTasks.
Frontend: New Task dialog gains a three-way Assignee control
(Myself / Department / Person) with a provider picker from /api/staff/providers;
task card + detail show the assignee's name when set.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- settings: keep tab nav on its own row so "Developers" no longer wraps
- chat: show the "Veil active" chip once per conversation, not every turn
- chat: record cards only offer "Click for more" when they have detail
- chat: chat-history panel (pill + sheet) top-left of the AI chat with
"Start new chat"; rename sidebar "New chat" -> "Ask temetro" (Sparkles)
- meetings: disable past dates, add an Upcoming Meetings list, and use the
Empty component for empty days; scheduler can be pre-targeted via ?with
- messages: add a call button left of each inbox row -> Meetings (?with)
- toast: add a dismiss (x) button; call invites now ring 30s with "Accept"
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Live invite: ring a clinic member into a room (socket call:invite + a bell
notification); the invitee gets a toast with a Join action. Notifications of
type "meeting" deep-link to /messages/meetings?room=, which auto-joins.
- Scheduling: new scheduled_meetings table + /api/meetings/events (list mine,
create, delete); a Calendar tab on the Meetings page with a month picker
(meeting-day dots), the day's agenda, and a Schedule-meeting dialog
(title/date/time/participants).
- Redesign: rounded control bar with tooltips (mic/cam/screen/invite + separated
red Leave), speaking ring on tiles (Web Audio), and live room-occupancy counts
via call:presence broadcasts. Migration 0025.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Chat patient cards are now compact previews (header + key stat + "Click for
more"); cards size to content (items-start) instead of stretching to the tallest;
Edit record moved into the summary detail dialog
- AI citations render once per source per message (collapses per-word spam) and the
prompt now asks the model to cite sparingly (once per paragraph, not per list item)
- Sidebar sub-items use exact-match active state so Meetings no longer lights Inbox
- Analysis defaults to All Time, drops the 12m option, and clamps the chart window
to >=2 points so 30d/Today render instead of collapsing
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backend: meeting_rooms table + /api/meetings (list/create/delete, org-scoped),
and WebRTC mesh signaling over the existing authed Socket.io (call:join with a
≤4 cap and org authorization, call:signal relay, peer-joined/left, disconnect
cleanup). Migration 0024.
Frontend: Messages nav is now expandable (Inbox + Meetings); new
/messages/meetings page with a room list and a Discord-style call UI — a
useWebRtcMesh hook (camera/mic, screen share via replaceTrack, ≤4 mesh) and a
tile grid with a mic/camera/screen/leave control bar. New lib/meetings + i18n.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Retrieval tools now register a PHI-free sourceId per record/list and stream a
data-source part with the real clinician-facing title; the system prompt asks
the model to cite facts inline as [[src:id]]. The chat renders those markers as
numbered inline citation chips (PreviewCard hover) via a Streamdown link
override, with a Sources footer fallback when the model omits markers.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New staff_profile table (org + user, unique) holding a clinician's clinical
specialty. GET /api/staff and /api/staff/providers now include specialty; new
PATCH /api/staff/:userId (member:update) upserts it. Migration 0023.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Fix clinic onboarding loop: refresh session after setActive before navigating,
surface setActive errors, and guard AppAuthGuard's onboarding redirect race (#1)
- Add a mobile-only floating top-right SidebarTrigger so the sidebar is reachable
when the offcanvas sidebar is closed on phones (#5)
- Make notifications clickable: navigate to the source (conversation/patient) and
mark read; MessagesView/PatientsView honor ?conversation= / ?file= deep links (#6)
- Analysis page: add an Overview header with a time-range segmented control and a
Customize popover that shows/hides sections; range slices month-based charts (#10)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Approval state lived only in each card's local React state, so after
committing (or after reloading a saved conversation) the Add / Review &
add / Import buttons reappeared active and the same records could be
added again. Persist the resolution onto the message data part via a
chat-panel handler (setMessages), and initialize each card's status from
data.resolved so committed/discarded proposals stay locked across
re-render and history reload.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The import preview only showed counts + skipped-row errors with no way to
fix anything. Now every parsed record is editable before import:
- backend: shared validatePatientImport() (used by the previewImport tool)
+ POST /api/ai/import/validate for dry-run re-validation; the import
preview payload now carries the original records (and the source record on
each invalid row) so the UI can edit them.
- frontend: the import card gets a "Review & edit" dialog listing every
record with a ready / needs-fixing badge; opening one reuses the full
PatientFormDialog in a new non-persisting review mode (editable file
number) and re-validates on save, so skipped rows can be fixed and
included.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a real file-storage layer to the backend and wire upload UI into the
frontend.
backend:
- new `attachments` table (org-scoped, links to a patient file number and
optionally a lab result) + Drizzle migration
- `/api/attachments` route: upload (multer → disk under UPLOAD_DIR),
list, stream/download, delete; gated by patient:write OR lab:write via
a new requireAnyPermission helper so lab staff can attach analyses
- UPLOAD_DIR env (default ./uploads) + a persistent docker volume
frontend:
- lib/attachments.ts client (multipart upload, list, delete, preview URL)
- staged file picker in the patient Add/Edit dialog (uploaded after save)
and the lab Add-result dialog (linked to the result)
- a Files section in the patient sheet that lists attachments and opens
them in a preview dialog (images inline, others via download)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The "Enable AI assistant" toggle already disabled the AI for everyone
(including owners/admins) at the policy layer, but the copy read as an
employee-only control and the Analysis surface stayed visible. Clarify
that the master switch covers admins too, and close the gaps: hide the
Analysis nav/command entry and redirect /analysis (alongside the chat
home) to /patients when AI is disabled. The employee-only toggle remains
the secondary option that keeps AI for owners/admins.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The single proposal card crammed every proposed record into comma-joined
summary lines — an inventory import became an unreadable wall of text.
Render inventory/invoice records as a compact scrollable item list, and
add an Edit button (single card + per-row in the batch review) that opens
a per-kind edit dialog so the clinician can adjust the data — whole record
or individual items — before it is committed.
New RecordEditDialog is schema-driven (EDIT_SCHEMAS) per action kind,
including add/remove rows for invoice line items and inventory items.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The record graph was a cramped React Flow box wedged inside a sheet
section. Redesign it Obsidian-style — round nodes with the label
underneath, a soft glow, and a hover-focus that highlights a node plus
its neighbours while dimming the rest.
Move it out of the inline section: the sheet now shows an "Open graph"
button (closes the sheet, opens the graph in a large dialog) and a
clickable list of the patient's records (problems + visits); clicking a
record opens a detail dialog.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CLINICAL_RESOURCES includes "lab" but the employee detail dialog only
mapped patient/appointment/prescription/task, so the lab row rendered as
the raw i18n key with no icon. Add a FlaskConical icon and a
"Lab results" label.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The composer's SELECT is now a clinician-facing mode picker instead of a list
of LLM vendors (the model still comes from Settings → AI and continues to drive
the Veil consent gate). The mode travels with each send:
- backend appends an Analysis/Graph directive to the agent's system prompt
- Graph mode renders an Obsidian-style RecordGraph for the /patient fast-path
(new data-recordGraph message part reusing the shared graph component)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- replace the attach "+" menu (whose programmatic fileInput.click() was dropped
by user-activation gating, so files never attached and no chip appeared) with
a native <label> paperclip + a direct appointment button
- shared-appointment cards are now clickable for both parties, opening an
AppointmentDetailDialog with the full snapshot (when/type/provider/patient/status)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- "Mark paid" button (settles invoice + all installments) when not paid/void
- per-installment Pay button + Paid badge; auto-marks invoice paid when the
last installment clears
- overdue badge on past-due unpaid installments; due-through timeframe hint
- installments + split control hidden once the invoice is paid
All via the existing PUT /api/invoices/:id (no backend change).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The realtime "Live" hospital card is dropped in favour of a six-month patient
visits area chart, aggregated client-side from real appointments. Renames the
analysis.live.* i18n block to analysis.area.* and removes the dead
live-hospital-chart component.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- deletePatient() lib fn (DELETE /api/patients/:fileNumber already existed)
- confirmed delete button in the patient sheet (full-clinician only)
- aggregate appointments/prescriptions/invoices into the sheet (by file #)
- new shared RecordGraph (@xyflow/react + d3-force) linking problems↔visits,
added as a "Record graph" section + reusable by AI Graph mode
- i18n keys for delete + new sheet sections
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- chat composer: attach works with text (sr-only file input); lighter
bordered input box
- messages: defer "+" menu actions past close so file/appointment pickers fire
- tasks: top-level New task button
- chat: condensed appointment card with "View in calendar" deep-link;
appointments page auto-opens the month calendar from ?calendar=&date=
- lab: work-queue rows expand to show task detail + complete
- inventory: clickable item detail dialog
- pharmacy: Dispense action records a dispense + "Recently dispensed" feed;
expiring badge uses endDate and only flags <=2 days left
- prescriptions: keyboard nav in patient search, inventory-backed medication
combobox (free-text fallback), optional start/end dates; thread dates through
- sidebar: whole nav scrolls as one
- i18n keys for all new strings
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- new org_ai_policy table + GET/PUT /api/ai/policy (read for any member,
write owner/admin only); migration 0018
- /api/chat hard-blocks (403) when AI is off for the caller
- Settings → AI "Availability" section: enable AI, or disable for
employees only (owners/admins keep access); read-only for non-admins
- sidebar, command palette and route guard hide/redirect the AI chat
when it's disabled for the current user
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- add a `status` field to tasks (backend schema/validation/service/types
+ frontend types), kept in sync with the legacy `done` flag
- migration 0017 adds the column and backfills done tasks to "done"
- rewrite the tasks page as a three-column board: per-column add buttons,
draggable cards, and a status mover in the detail sheet
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Chat fixes (#1/#6/#7):
- chat-input passes raw File[] up instead of inlining file text
- chat-panel sends files as FileUIPart and renders them with the
ai-elements Attachments component (no more raw text dumps)
- backend extracts text-like file content for the model in routes/chat
- Chain-of-Thought now defaults to collapsed
- file upload works regardless of whether the input has text
AI add-to-inventory (#2):
- new proposeInventory tool (validates items, streams an approval card)
- system prompt distinguishes stocking inventory vs. billing a patient
- ActionPreviewCard commits inventory via POST /api/inventory
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
real Live card, persistent chat history
Analytics & earnings:
- Analytics now carries real money computed from invoices (billed/paid/
outstanding + by-month); new Earnings section on the Analysis page drawn with
the project's Bklit chart components (shared EarningsChart).
AI agent reaches the whole clinic:
- new read tools getClinicInfo / getAnalytics / listInventory render clinic,
analytics (with a Bklit earnings chart) and inventory cards in chat
- proposeInvoice turns an uploaded purchase/medication list into an invoice
(new "invoice" action-preview kind → createInvoice); invoices/appointments
auto-create/link a patient (ensurePatient) so they hit the Patients page
Live card:
- plots real data — patients checked in today — via GET /api/analytics/live
(polled); value pill clamped and margins widened so nothing spills the card
Persistent AI chat history (Claude-style):
- ai_chat_threads + ai_chat_messages (migration 0016); per-user, org-scoped
thread CRUD under /api/chat/threads
- chat panel owns a thread id, loads /?thread=<id>, and auto-saves after each
exchange; sidebar lists past chats (open/delete), "New chat" starts fresh
Verified with backend typecheck + frontend tsc + next build.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1. Chat input toolbar was clipped in the empty state: the form's overflow-hidden
made its flex min-height resolve to 0, so the vertically-centered layout
squeezed it and hid the bottom toolbar (attach/add-patient/model/mic/send).
Add `shrink-0` to the form; let the empty-state column scroll.
2. AI-imported appointments now create/link a patient: services.ensurePatient
reuses a same-name patient or creates one (auto file number, source "ai");
appointments.createAppointment calls it when the booking has no file number,
so imported people appear on the Patients page.
3. Many proposals collapse into one BatchActionPreviewCard → a review dialog
with per-row remove and "Add all" (commits sequentially), instead of one
Add/Discard card per record.
Plus: widen the Live chart right margin so the value pill stays inside the card.
Verified with `next build`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The ai-elements `reasoning.tsx` imports `streamdown`/`@streamdown/*`, which are
not installed (it's a dormant component). Importing it into chat-panel made the
whole chat fail to render — taking the input toolbar (attach, add-patient, model
picker, mic, send) down with it.
Render the reasoning block with a self-contained COSS Collapsible + Shimmer
instead (no streamdown). The other AI-elements I wired in (tool, queue,
suggestion, shimmer) have their deps installed and stay. Verified with a full
`next build`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wire the existing ai-elements into the chat:
- collapsible tool-call cards (name, params, result, status) for native tool
parts on the streamed path
- a reasoning block (shimmer while thinking, "Thought for Ns") when the model
emits reasoning; backend forwards it via toUIMessageStream({ sendReasoning })
- a message queue: typing + Enter while the assistant is responding queues the
message (shown above the input, removable) and auto-sends when it goes idle
- starter suggestion chips on the empty state, each tied to a tool
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backend (new `invoice` RBAC resource, granted to clinicians + reception):
- invoices table (line items + installments as JSONB), types, zod validation,
service (CRUD + splitIntoInstallments + auto invoice numbers), org-scoped
REST routes mounted at /api/invoices, activity logging (migration 0015)
Frontend:
- lib/invoices.ts API client + money/date helpers
- /invoices page: list with KPIs and search, create/edit dialog (searchable
patient combobox, inline line-item editor, live total), detail sheet to split
a bill into equal monthly installments, delete, and Download PDF
- dependency-free PDF via a print-styled window (browser "Save as PDF")
- sidebar "Invoices" entry under the Patients group; "Added by AI" badge honored
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- the inline chat error now has an X to dismiss it, and is the single surface
for errors (dropped the duplicate toast) so failures show once and clearly
- the import preview card caps the skipped-rows list (scrolls, one line each
with a "+N more" tail) so a file full of validation errors no longer renders
a giant card
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Live card no longer streams on mount: a "Go live"/"Pause" toggle starts/stops
the 1s simulation, so the page stays idle by default (perf). Widen the live
chart's left margin so the y-axis values sit inside the card.
- Weekly-appointments bar chart: drop the misused <BarYAxis>, which printed the
weekday categories down the left and overflowed the card (vertical bars only
need the x-axis).
- Patient-growth area chart: one x tick per month so every point is labelled.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- new reusable <Combobox> (Base UI Autocomplete): arrow-key + Enter navigation
- New Appointment dialog: patient search and provider are now searchable
comboboxes (provider sourced from /api/staff/providers) instead of a hand-
rolled dropdown and a free-text input
- appointment rows are clickable and open an <AppointmentDetailSheet> to edit
date/time/type/provider/status or delete; "Added by AI" badge shown on rows
and in the sheet for source="ai" records
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Stop blocking AI imports/proposals on missing non-critical fields. Records
the chat agent drafts now save with safe placeholders, auto-generated file
numbers, and a source="ai" marker that surfaces an "Added by AI" badge so a
clinician can review/edit them later.
Backend:
- add `source` (manual|ai) column to patients/appointments/prescriptions
(migration 0014) + canonical types, services, validation schemas
- relax patient/appointment validation: empty file number allowed, demographic
+ type/provider/initials fall back to placeholders (initials derived from name)
- patients.generateFileNumber() auto-assigns an MRN when one is missing
- proposeAppointment accepts a name when no file number resolves; AI commits +
/api/ai/import stamp source="ai"
Frontend:
- `source` on Appointment/Patient/Prescription types; AI commits send source="ai"
- reusable <AiBadge> shown on the Patients table/detail and prescriptions list
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The placeholder only mentioned patient lookup, but the chat now answers
plain-language questions, displays records, adds, and imports. Update it to
"Ask anything, or type /patient 10293".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make the chat feel alive and let the agent act on the clinic — safely.
UX (frontend):
- Stream `data-step` parts from each tool into an inline Chain-of-Thought
trace, plus a "Thinking…" shimmer while a request is in flight (works even
on the non-streamed external+Veil path).
- Replace the modal Veil consent Dialog with an inline, once-per-session
"Veil" confirmation above the input (with a "Use local model" option).
- Render new list + action-preview cards; chat-input now uses COSS tokens.
Agent (backend):
- Add display tools (listAppointments / listTasks / listPrescriptions) and
propose tools (proposeAppointment / proposeTask / proposePrescription) that
validate as a dry run and stream an approval card — nothing is written until
the clinician approves, via the existing RBAC-gated create endpoints.
- previewImport now also covers single-patient add + migration.
- System prompt: display + add only, never edit/delete or alter the schema;
stronger migration guidance. ToolContext carries the viewer for task scoping.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>