AI Workflows

Run your own LLM tool — Claude Code, Codex, Cursor, a script — when something happens in NxVET

Last updated: October 8, 2026

Overview

NxVET is the place where a clinic's conversations, recordings, tasks and whiteboard already live, and it tells you the moment any of them changes. An AI workflow is a small loop on top of that: an event happens → your LLM tool is started with the event and its record → the tool does the work through the NxVET MCP tools (or the REST API) → it writes the outcome back (a comment, a status, a new task) so staff and the next run see it.

You bring the tool. Claude Code, OpenAI Codex, Cursor, an in-house script — anything with a command line or a webhook receiver. NxVET brings the events, the data, the tools the model calls, and the place where people approve and see the result.

A. In the clinic — NxVET Agent app

The agent runs on a clinic PC, signed in, on the organization's event stream. workflow-add points a command at events; the agent runs it with the event and record as JSON.

No public endpoint, no server. Best when the tool should run where the clinic's own files and systems are.

B. In the cloud — webhooks

Your endpoint receives signed events; your worker fetches the record and spawns the tool (or calls a model API) with MCP as its tool surface.

Best when you already run a service, or want one workflow for many clinics.

C. Interactive — MCP

Connect any MCP client and just ask: "what did the badges ask for today?", "confirm it", "file the follow-ups from this visit".

Best for people; the same tools the automated paths use.

The voice-assistant hand-off

The first workflow most clinics build. An NxHUB badge in assistant mode is a personal assistant: hold the button, speak, hear the answer. When the person asks for something to be done — "add a task to write me a prescription for gabapentin for Bella" — the assistant files a task on the organization's Voice assistant board in NxVET as Needs confirmation and says so (the turn, its transcript, reply and per-step timings are readable: GET /api/nxhub/voice-turns, MCP list_voice_turns).

  1. Spoken. The task is a request: status needs_confirmation, task_created fires. Do not act yet.
  2. Confirmed. A person moves it to any other non-dismissed status on the NxVET Tasks page (or an MCP client does with update_task). task_updated fires — the hand-off.
  3. Done by your tool. The workflow runs; the model reads the task, does the work (through MCP, your PIMS, your files), and comments on the task.
  4. Visible. Staff see the comment and move the task to Completed; the badge's owner never left NxVET.

A task is the assistant's when its fields.turn_id is set (the voice turn that filed it); fields.badge names the Clip. Status ids are stable even when a clinic renames the columns.

A. In the clinic: the NxVET Agent app

The NxVET Agent (headless or desktop) already runs in clinics to push recordings into scribes and PIMS. Its workflows run any command on the organization's events:

# 1. Give your LLM tool the NxVET MCP tools (once per tool). --with-key prints the agent's own key.
#    mcp-config PRINTS the registration; you run it. For Claude Code it is --scope user, so the
#    workflow runs (which start in your home directory) see it, not only the directory you ran it in.
nxvet-headless mcp-config --claude --with-key
#    → claude mcp add --scope user --transport http nxvet https://mcp.nx.vet/mcp --header "Authorization: Bearer …"
nxvet-headless mcp-config --codex --with-key      # a [mcp_servers.nxvet] block for ~/.codex/config.toml

# 2. A workflow from a template — the command is yours to edit
nxvet-headless workflow-add --name "Confirmed tasks" --template claude-code --on voice_task_confirmed
#    runs: claude -p "Read the NxVET event in $NXVET_EVENT_FILE … Do what the task asks using the
#          nxvet MCP tools, then add a short comment on the task saying what you did."
#          --allowedTools "Read,mcp__nxvet__get_task,mcp__nxvet__list_task_comments,mcp__nxvet__add_task_comment,mcp__nxvet__update_task"

# 3. Try it on a real task now; then leave the agent running (run / agent) — it fires on its own
nxvet-headless workflow-test "Confirmed tasks" --task <taskId>
nxvet-headless workflow-runs

Authorize the tools. Registering the MCP server does not approve its tools: unattended, claude -p refuses any call that would need a permission prompt. The template's --allowedTools is that approval — the event file and the four NxVET task tools, no shell, no file edits. A workflow that needs more (say mcp__nxvet__list_labels to read a transcript) adds it to its own command; mcp__nxvet alone would allow every NxVET tool. Codex's --full-auto approves its tools itself.

workflow-add --run '<any command>' takes anything: codex exec --full-auto "…", python3 on-event.py, a PowerShell script. The command runs through the shell, in --cwd, killed after --timeout seconds (default 600); two at a time, the rest queue; the last 4 KB of output and the exit code are kept (workflow-runs, GET /workflow-runs on the control API). The agent's own key is passed to the command only with --with-key.

B. In the cloud: webhooks

  1. Register an endpoint: POST /api/organizations/{orgId}/webhooks with eventTypes: ["task_updated", "new_label", …] (signing and retries; a free receiver in ~15 minutes: Cloudflare Workers guide).
  2. On task_updated: GET /api/tasks/{taskId}. If fields.turn_id is set, statusId !== "needs_confirmation" and the board's status category is open or done → a confirmed voice task. Claim it — insert taskId into your own store with a unique key before doing anything; if the insert fails, it was handled already (completion, a comment, a replay). See Idempotency below.
  3. Hand it to your tool on a worker: spawn claude -p / codex exec with the task JSON, or call a model API with the NxVET MCP server (https://mcp.nx.vet/mcp, Authorization: Bearer your key) as its tool surface.
  4. Close the loop: POST /api/tasks/{taskId}/comments with what was done; PATCH /api/tasks/{taskId} to a done status.

The same shape works for recordings (new_label → review the transcript → file follow-ups with POST /api/task-boards/{boardId}/tasks/bulk) and for the whiteboard (whiteboard_due).

C. Interactive: MCP

Connect Claude, Cursor, Claude Code or any MCP client to https://mcp.nx.vet/mcp (how) and ask. The voice assistant adds two tools — list_voice_turns and get_voice_turn — next to the task tools:

  • "What did the badges ask the assistant for today?" → list_voice_turns
  • "Which voice-filed tasks are still waiting for confirmation?" → list_tasks on the Voice assistant board, statusId needs_confirmation
  • "Confirm the gabapentin prescription Dr. Lee asked for." → update_task to confirmed (this fires the hand-off above)
  • "Where does the assistant's time go?" → timingsMs per turn: speech to text, the model, text to speech

Events

EventWebhooks / streamAgent workflowsData
Voice task filed (needs confirmation)task_createdvoice_task_filedtaskId, boardId
Voice task confirmedtask_updated (check the status transition; see Idempotency)voice_task_confirmed (once per task)taskId, boardId
Any tasktask_created, task_updated, task_deleted, task_comment_addedtaskId, boardId[, commentId]
Recordingsnew_label, label_updated, label_deletedlabelId
NxHUB conversationsconversation_created, conversation_completedconversationId, deviceId
Whiteboardwhiteboard_updated, whiteboard_duepatientId, …

What your tool receives (agent workflows)

WhereWhat
stdin, $NXVET_EVENT_FILEone JSON document: { event: {type, taskId?, labelId?, at}, record: {kind: "task" | "label", …} | null, organizationId, organizationName, apiBase, mcp } — the record is fetched for you
NXVET_EVENT_TYPEe.g. voice_task_confirmed
NXVET_TASK_ID, NXVET_LABEL_IDwhen the event is about one
NXVET_API_BASE, NXVET_ORG_IDhttps://app.nx.vet and the organization
NXVET_API_KEYonly with --with-key: the agent's own key, for a tool that calls the REST API itself (an MCP-configured tool does not need it)

Webhook payloads are documented on the Webhooks page; they carry ids only — fetch the record.

Idempotency & safety

  • Confirm once, not on every later change. A confirmed task keeps emitting task_updated: when staff move it to Completed, edit a field, add a comment. "Status is not needs_confirmation" is true for all of those, so a workflow keyed on the current status — or on the webhook event id — runs the action again on completion. Act on the transition into a confirmed state and keep a durable claim per task: a row keyed by taskId in your own store (a database table with a unique key, a file the worker owns), written before the work starts, so a replay, a restart or two deliveries at once find it. The NxVET Agent does this for voice_task_confirmed: every handled task id is kept in its settings, none evicted, written before the workflow starts — and the workflow does not run if it could not be written (confirmed → completed, a replay, a restart never fire it again). A comment on the task is a good receipt for people, not a claim: two runs can both read before either writes.
  • Events repeat. A reconnect replays, webhooks are at-least-once. The claim above is the dedupe; the event id only removes exact duplicates of one delivery.
  • A voice task is a request until confirmed. Never act on task_created / voice_task_filed; act when the status has left needs_confirmation for a status whose category is open or done — read the board's statuses; an unknown category is not a confirmation; dismissed never is.
  • Least privilege. Create a scoped API key for the tool (e.g. tasks:read, tasks:write, nxhub:voice-turns:read); revoke it at app.nx.vet/integrations when the machine or the tool changes.
  • Say what is allowed in the prompt. The model acts with the clinic's key: read records, create and update tasks, comments, webhooks. Keep destructive steps (deleting, re-generating notes) out of unattended workflows.
  • Know where the record goes. The clinic-PC path keeps the runner local, not the data: an LLM tool sends what it reads — the event, the task, a transcript — to its model provider over the network (Claude Code to Anthropic, Codex to OpenAI, under the retention terms of the clinic's plan with that provider; see Claude Code's data-usage documentation). A cloud workflow additionally passes it through wherever your worker runs. Pick the tool and its provider settings with that in mind, scope the key, and keep transcripts out of workflows that do not need them.