gosset
v1.1.0
Published
Wearable research studies without the app build — study builder, participant enrollment, HealthKit data collection, and a CLI to run it all from the terminal.
Maintainers
Readme
Gosset
Wearable research studies without the app build. Gosset is the layer between researchers and subjects: design a study, screen and consent participants, and collect Apple Watch / HealthKit data (HRV, ECG, sleep, SpO₂, activity and more) — through one shared iOS app and one API, with no custom development per study.
What's in this repo
| Path | What it is |
|---|---|
| src/worker.js | Cloudflare Worker API — auth (sessions + API keys), routing, participant endpoints, agent docs |
| src/ops.js | Researcher operations shared by REST and MCP (studies, dashboards, exports, guardrails) |
| src/mcp.js | MCP server (Streamable HTTP) — agent tools over the same ops |
| src/draft.js | Plain-English → study definition via the Claude API (structured outputs) |
| src/sim.js | Server-side simulated-cohort generator (flagged rows, removable) |
| migrations/ | D1 (SQLite) schema |
| public/ | Web app: researcher console + participant join flow (/j/CODE), plain JS, no build step |
| ios/ | SwiftUI + HealthKit companion app source (XcodeGen project) |
Researcher console — email/password accounts; a five-step study builder (basics → HealthKit data streams → surveys → screening & consent → publish); live dashboards (enrollment, diary compliance, cohort daily means, per-participant drill-down); CSV/JSON export; one-click simulated cohort for demoing dashboards before real data arrives.
Participant join flow — the published link (/j/JOINCODE) runs a
Typeform-style one-question-at-a-time flow: eligibility screening (re-checked
server-side), informed consent with typed e-signature (version recorded per
participant), baseline survey, then an enrollment key for the iOS app.
iOS app — participants paste their enrollment key once; the app requests HealthKit read access for exactly the streams the study declared, uploads daily summaries (foreground + background task), and runs scheduled surveys natively. One App Store build serves every study — definitions are fetched at runtime.
AI study drafting — "New study" accepts a plain-English description and
drafts the entire definition (data streams, screening, consent, surveys) via
the Claude API; the builder is the review surface. Requires one secret:
wrangler secret put ANTHROPIC_API_KEY (key from console.anthropic.com).
Without it, everything else works and the button explains what to configure.
API & agents (MCP) — researchers mint scoped API keys (grk_…, full or
read-only) from the console. The same Worker speaks MCP at /mcp, so Claude
Code / Claude Desktop / any MCP client can design studies (from a definition
or a plain-English brief), publish, monitor dashboards, and export data:
claude mcp add gosset --transport http https://<your-host>/mcp \
--header "Authorization: Bearer grk_..."Guardrails are structural: API keys can never delete a study, and consent /
eligibility on a published study are immutable through the API — an agent
cannot silently alter what participants agreed to. REST docs (agent-readable
markdown) are served at /api/docs.
CLI
The npm package doubles as a command-line client and a self-hosting kit — the whole framework (Worker, console, migrations) ships inside it:
npm install -g gosset # from a clone: npm install -g .Run gosset with no arguments and it takes over the terminal:
Gosset v1.1.0 — wearable research studies
connected to https://my-lab.example.workers.dev
3 studies (2 enrolling)
gosset › use SLEEP-2026
Selected Night Shift Sleep Study [Live]
gosset SLEEP-2026 › adherence
Daily diary — Daily at 19:00 (overall 78%, 2 lapsed)
CODE DONE RATE LAST STATE
P-0001 21/24 88% 2026-07-26 on track
P-0007 9/24 38% 2026-07-18 LAPSEDThe first run asks for your instance URL and API key and saves them.
use <id|join code|title> selects a study so the other commands stop
needing an ID; tab completion covers commands and study codes.
Every command also works one-shot for scripts and CI:
gosset init my-lab # scaffold an instance, then wrangler deploy
gosset config set-host https://my-lab.<you>.workers.dev
gosset config set-key grk_... # minted in the console under API & agents
gosset create --brief "8-week sleep study in ICU nurses…"
gosset publish <id>
gosset export <id> --format csv -o data.csvAny command takes --json for machine-readable output. Governance actions
(go-live with the ethics attestation, pausing enrollment) are console-only
by design — the CLI tells you where to go. Config lives in
~/.gosset/config.json; GOSSET_HOST / GOSSET_API_KEY override it in CI.
Go live (≈15 minutes + Apple review)
Everything runs on a free-tier Cloudflare account. No other services, no API keys in code.
npm install
npx wrangler login # opens browser to your CF account
npx wrangler d1 create gosset-db # prints a database_id
# → paste the database_id into wrangler.toml
npm run db:migrate:remote # create tables
npm run deploy # https://gosset.<you>.workers.devThen create your researcher account at the deployed URL — the first signup is just a normal account; there is no seed step.
iOS app (the only part that needs Apple credentials): see
ios/README.md — set your team ID and the deployed API URL,
archive, and submit. Web enrollment, dashboards and exports work before the
app ships; watch data starts flowing once participants install it.
Local development
npm install
npm run db:migrate:local
npm run dev # http://localhost:8787 with a local D1Architecture notes
- Auth: researcher sessions are HttpOnly cookies backed by hashed tokens in D1; passwords are PBKDF2-SHA256 (100k iterations, per-user salt). Participants authenticate with a bearer enrollment key (only its SHA-256 is stored).
- Data model: study definitions are versionless JSON documents; samples and
survey responses are relational rows keyed by participant code. Simulated
demo rows carry
is_simulated=1and are excludable/deletable. - Ingestion contract:
POST /api/participant/samplestakes batches of{metric, day, ts, value, unit}; metrics are validated against the study definition. The dashboard aggregates per day in SQL. - Exports: long-format CSV and nested JSON, keyed by participant code — no direct identifiers beyond the consent signature, which is never exported.
Compliance foundation
Built in and on by default:
- Append-only audit trail — sign-ins (including failures), study changes, consent versions, publishes, enrollments, exports, erasures, key usage, and retention purges; browsable per-account in the console (Audit log).
- Immutable consent versioning — publishing snapshots consent+eligibility as v1; console edits to a live study create v(n+1). Every participant record pins the exact version they signed, and their data export includes it.
- Data-subject rights — participant self-service export (portability) and erasure (samples/answers deleted, anonymized stub + audit record retained); researcher-side per-participant erasure from the console.
- Retention enforcement — per-study
retentionDays(default 365 after study end), enforced by a daily cron that purges expired data and audits it. - Account hardening — TOTP two-factor auth, rate-limited auth endpoints,
email verification (configure
RESEND_API_KEY+EMAIL_FROMsecrets; publishing is gated on verification once email is configured), security headers/CSP on the web app.
Still organizational, not code: lawyer-reviewed privacy policy/ToS/DPA, a BAA with your infrastructure provider before handling PHI (verify D1 is in Cloudflare's HIPAA-eligible services, or migrate the datastore first), SOC 2 if enterprise customers ask, and per-study IRB approval — which is always the researcher's, not the platform's. Gosset's job is making that approval easy: the consent-version history and audit trail are exactly the artifacts an IRB asks for.
