mcpField
T
terra-models

terra-models

github.com/tryterraOther055 installsUpdated 1d ago
Repository

About terra-models

terra-models is a skill for running Terra API wellness models on connected users’ data and interpreting their results. It covers sleep schedules, cycle indicators, and reconstructed metrics, with guidance on unsupported data and errors.

Key features

  1. 01Runs three documented wellness models
  2. 02Explains model inputs and outputs
  3. 03Distinguishes unsupported, no-data, and errors
  4. 04Tracks model runs and credit use
  5. 05Provides CLI and MCP administration guidance

Use cases

  1. 01Generating a sleep schedule insight
  2. 02Reviewing cycle indicators across a date range
  3. 03Filling gaps in recorded health metrics

MCP support

The skill describes using Terra’s admin MCP server for account commands, including model catalogs and run logs. Model execution itself uses the Terra API endpoint.

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/tryterra/agent-skills --skill terra-models

After installing, type/terra-modelsin Claude Code to confirm it loaded.

Bundled filesmetadata.jsonREADME.md

Details

From the project README

Terra API Models

Run one of Terra API's health models over a connected user's data for a date range and get a ready-to-use insight back: one request in, one insight out. No model to host. Every model is a wellness indicator, not a medical or diagnostic tool; never present its output as clinical.

Account tools: CLI or MCP

Models has account commands of its own, including the run log that says why a run did not return what you expected:

terra models catalog list                                           # the models available, account-wide
terra models runs list --env <dev-id> --status error                # failed runs
terra models runs list --env <dev-id> --user-id <uuid> --model <model>
terra models runs list --env <dev-id> --run-id <run_id>             # one run, by id

Two things about that log. It holds 30 days by default, so an older run is not there and an empty page is not evidence a run never happened. But --run-id widens the lookup to the full retained history, so a run you have an id for is never cut off by the window.

Because a run costs a credit whether or not it returns an insight, runs list --status error is also the fastest read on credits being spent on runs that never produced anything.

In a coding agent (Claude Code, Codex, Cursor and the like, on the user's machine or in the cloud), use the CLI, and offer to install it if it is missing: curl -fsSL https://cli.tryterra.co/install.sh | sh on macOS and Linux, irm "https://cli.tryterra.co/install.ps1" | iex in Windows PowerShell, or Homebrew or npm where the user already uses them. In a chat assistant (claude.ai, Claude Desktop, ChatGPT), use the Terra API admin MCP server, even when it can run code: its sandbox cannot install the CLI or sign in. Each admin command is a tool whose name and method spell it (terra users list is users_read with method: "list"). Only the CLI has terra data-api, terra admin-api and terra examples, and --select and --jq have no MCP equivalent. The terra-cli and terra-mcp skills carry the guardrails (confirming changes, keeping credentials out of transcripts), the errors, and a playbook per task. They administer the integration; they do not replace the API calls this skill describes.

When to use this

Building anything that calls GET /v2/models or GET /v2/models/run, prices model_run usage, or turns a user's Terra API data into a sleep-schedule, menstrual-cycle, or gap-filled-metrics insight.

Connect the user first

Models run for a user you have connected through the Unified API (see the terra-unified-api skill), over a date range you choose. A model cannot always return an insight for a given user and range; when it cannot you get either an unsupported result or an error, and the run still costs a credit either way (see Reading the result and Pricing).

The three models (generally available)

model idReturnsNeeds
sleep_windowA recommended bedtime, wake time and in-bed duration, a 0–100 consistency score with a band, and the single change that would most improve itOvernight sleep sessions from across the user's history
cycle_phase_trackerA per-day menstrual cycle phase, plus the period onsets and fertile windows detected in overnight physiology, each with a confidence bandAt least 30 days of overnight sleep carrying heart rate and HRV
graph_imputeSmart Fill: one day's metrics for a chosen table, marking which the device recorded and which the model reconstructedRecorded history for that user in the table you ask for

sleep_window, cycle_phase_tracker and graph_impute are GA and documented. Treat any other model id as pre-GA and unstable: it may be runnable, but its response shape can change without notice.

cycle_phase_tracker is a wellness indicator, not a medical or contraceptive tool, and it detects onsets from physiology alone – it neither needs nor reads a user's logged period dates.

Making a run

GET https://api.tryterra.co/v2/models/run

Query params: model, user_id, start_time, end_time (all ISO 8601). Headers: x-api-key and dev-id (your own keys; this is not a privileged endpoint).

graph_impute needs one more param: table, one of sleeps, dailies or activities. The endpoint refuses the run without it rather than choosing a table for you, so a request built from the generic param list alone returns 400. The three tables carry different metrics.

curl --request GET \
  'https://api.tryterra.co/v2/models/run?model=sleep_window&user_id=USER_ID&start_time=2026-04-01T00:00:00Z&end_time=2026-07-01T00:00:00Z' \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'dev-id: YOUR_DEV_ID'

Fetch https://docs.tryterra.co/models/models.md for the exact params and the full per-model response schema before you build request or response types; the response shape differs per model and evolves. Ask terra docs ask (or docs_ask over MCP) before fetching a page: it answers from the docs and cites its sources. Append .md to any docs URL for markdown.

Reading the result (the part agents get wrong)

  • Unsupported device is a 200, not an error. When the user's device or provider cannot produce the model, the run returns HTTP 200 with unsupported: true (plus unsupported_reason and supported/supported_devices) in place of an insight. Handle that as a normal outcome and surface it to the user, not as a failure.
  • A genuine error is a real error. Bad or missing inputs return 4xx, and a run that cannot be computed (for example too little data in the range) can return 5xx. These come back as RFC 7807 problem+json (title, detail, and errors[] for validation), for example 400 unknown model, 404 invalid user id. This is not the graceful unsupported case above; do not swallow it.
  • Every run bills, including failures. A run is metered before it computes, so an unsupported or errored run still costs a credit. Validate the model id, the user, and that the device is supported up front rather than probing blindly.
  • Empty is not always unsupported. sleep_window uses unsupported/unsupported_reason for a device it cannot serve and no_data/no_data_reason for a user it has too little history for. cycle_phase_tracker only ever uses no_data/no_data_reason. Handle both keys; do not branch on unsupported alone.
  • The shape is per-model. sleep_window returns a window object (recommended_bed/recommended_wake are local clock times; approximate: true means the schedule was estimated from limited history), a sleep_regularity object (score 0–100 and a band of Low/Fair/Good/Excellent), and, unless the user is already consistent, a recommendation object (change, reason, moves_to, gain) naming the single biggest change that would raise the score. cycle_phase_tracker returns results plus periods and fertile_windows. graph_impute returns table, features and results.
  • sleep_window ignores the range you pass. It reads the user's whole sleep history, so start_time and end_time do not change its answer. Do not build a UI that implies picking a window changes the schedule.
  • cycle_phase_tracker's results is not a list of answers. It carries one row per calendar day of the range you asked for, including days the model had no data for – so results.length is never a coverage signal. Branch on each row's available. Read the *_confidence bands (low/medium/high), never a raw probability, and note a period day is never also a fertile day.
  • For graph_impute, computed and reported are the whole point. Each entry in a day's fields carries reported: true if the device actually recorded the value and computed: true if the model reconstructed it, with a confidence on the reconstructed ones. Never present a computed value as recorded.
  • The response's data_type is not the catalog's data_type. The catalog reports the data a model reads (sleep_window → sleep); a run response reports its own value (sleep_window → sleep_window). Do not assert one from the other.
  • truncated: true means the run hit the per-request data cap; the insight is still valid but computed over a bounded slice of the range.
  • Model outputs are modest-confidence indicators. Do not present a single result as authoritative.

Pricing

Usage-based: $0.01 per model run, drawn from your plan's monthly credit allowance. One run is one model over one user for one date range, regardless of how much data the range covers; running two models, or the same model on two users, is two runs. A run started from the Terra API dashboard and one made through this API bill through the identical path. Details: https://docs.tryterra.co/unified-api/pricing

Boundaries

  • Not the Unified API. Connecting users, webhooks, and historical data are the Unified API (terra-unified-api); a model run analyzes a connected user's data and returns an insight.
  • Not Health Scores. Health Scores are continuous physiological scores; Models return a discrete, on-demand insight from a single call.

Comments

Markdown supported