Skip to main content
Glama
burrows99

semblekit

by burrows99
README.md
# semblekit _(@burrows99/semblekit)_

[![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg)](https://github.com/RichardLitt/standard-readme) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

CLI, library & MCP server for the Semble practice-management API — usable by any agent, human, or script.

semblekit drives [Semble](https://www.semble.io/) over its public GraphQL API. It models Semble's own
concepts (contacts, patients & relationships, users) rather than any one organisation's usage of them, and
ships four ways to use it: a `semble` CLI, an importable library, an MCP server, and a Claude Code plugin.

> **Not affiliated** with, endorsed by, or supported by Semble Ltd. "Semble" names the API this tool
> interoperates with.

> **Design principle.** Commands map to Semble resources, not workflows. A "Responsible Clinician", for
> example, is not a first-class Semble thing — it is just a patient relationship with a label pointing at a
> contact. So the tool exposes `semble patient relationship …` and leaves the meaning to the consumer.

> **Naming.** The repo and CLI command are `semblekit` / `semble`; the published package is
> **`@burrows99/semblekit`** on the GitHub Packages registry (the bare name `semblekit` is taken on
> npmjs). The Claude plugin is `semble@semblekit`.

## Table of Contents

- [Security](#security)
- [Background](#background)
- [Install](#install)
- [Usage](#usage)
- [API](#api)
- [Maintainers](#maintainers)
- [Contributing](#contributing)
- [License](#license)

## Security

Semble is a practice-management / EHR system, so treat everything it returns as sensitive.

- **Health data.** `patient` data is likely special-category personal data under UK GDPR / the Data
  Protection Act. You remain the controller or processor for anything you move with this tool. Prefer the
  sandbox for development.
- **Credentials.** Supplied via flags, environment variables, or `~/.config/semble/config.json` — never
  hardcoded. Keep them out of version control; the tool never logs credential values.
- **Tracing & data on disk.** Every command appends request *metadata* (no bodies) to `.semble/trace.jsonl`.
  `--trace` / `--trace-full` additionally persist full request **and response bodies — which may contain
  patient data** — to that file. Secrets (tokens) are redacted, patient data is not. `.semble/` is
  git-ignored by default; avoid full tracing against production data unless your obligations allow it.

## Background

Credentials and API URLs come from flags, environment variables, or a config file — never hardcoded — so
semblekit is not coupled to any deployment. It runs on plain Node (built-in `fetch`, Node ≥ 18); no Docker.

It talks to Semble's **public GraphQL API** (`x-token`). The design is object-oriented: typed entities own
their behaviour, thin resources do I/O, and a single fetch chokepoint makes request tracing a one-line wrap.

## Install

Requires **Node ≥ 18**. semblekit is published to the **GitHub Packages** npm registry, which needs a
one-time scope + token setup (a GitHub token with the `read:packages` scope):

```bash
printf '@burrows99:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN\n' >> ~/.npmrc

npm install -g @burrows99/semblekit   # global: the `semble` CLI + `semble-mcp` MCP server
# or, as a library in a project:
npm install @burrows99/semblekit
```

### Dependencies

Node ≥ 18 only (uses the built-in `fetch`). No Docker, no database.

## Usage

Credentials resolve **flags > environment > config file > built-in presets**, and are auto-discovered from
the nearest `.env` / `.claude/.env` walking up from the working directory. See [`.env.example`](.env.example).
For the public API the relevant variables are `SEMBLE_OPEN_URL` and `SEMBLE_TOKEN`.

### CLI

```bash
semble patient search "smith" --limit 5        # find a patient id
semble patient get <patientId> --json
semble contact search "clinic" --json          # find a contact/clinician id
semble user list
semble patient relationship add <patientId> <contactId> --label "Responsible Clinician"
semble help
```

`--json` for machine output, `--trace` for a DevTools-style request log, `--limit` to cap paginated results.
`stdout` is data, `stderr` is messages; exit `0` success · `1` runtime error · `2` usage error.

### Library

```js
import { SembleClient, SembleTracer, loadConfig } from "@burrows99/semblekit";

const client = new SembleClient(loadConfig({ profile: "sandbox" }));
const [patient] = await client.patients.search("smith");
const rels = await client.patients.listRelationships(patient.id);

new SembleTracer(client, (record) => console.error(record)); // optional: trace every HTTP exchange
```

Methods return data or throw `SembleError`; they never call `process.exit` or print. `search` / `list`
paginate automatically and accept `{ limit }`.

### MCP server

semblekit ships a stdio [MCP](https://modelcontextprotocol.io) server so an AI host can drive Semble as
tools — run it with **npx**, no install needed (uses the `.npmrc` set up in [Install](#install)):

```bash
npx -p @burrows99/semblekit semble-mcp
```

Point an MCP host at it:

```jsonc
{
  "mcpServers": {
    "semblekit": { "command": "npx", "args": ["-y", "-p", "@burrows99/semblekit", "semble-mcp"] }
  }
}
```

Inspect it with the MCP Inspector:

```bash
npx @modelcontextprotocol/inspector npx -p @burrows99/semblekit semble-mcp
```

Read-only tools: `semble_patient_search`, `semble_patient_get`, `semble_patient_relationships`,
`semble_contact_search`, `semble_contact_get`, `semble_user_list`, `semble_user_get`.

### Claude Code plugin

```bash
claude plugin marketplace add /path/to/semblekit
claude plugin install semble@semblekit
```

## API

- **`new SembleClient(config?)`** — composes the transport and resources; build `config` with
  `loadConfig(options)`.
- **`client.patients`** — `search(query?, { limit? })`, `get(id)`, `listRelationships(patientId)`.
- **`client.contacts`** — `search(query?, { limit? })`, `get(id)`.
- **`client.users`** — `list({ limit? })`, `get(id)`.
- **`SembleTracer(client, sink, options?)`** — decorates the client's fetch chokepoint; `sink(record)` fires
  per request, with secrets redacted.
- **`SembleConfig` / `loadConfig` / `PRESETS`** — profile resolution; presets name `sandbox` and `prod`.
- **Entities** — `Patient`, `Contact`, `User`, `RelatedAccount`; each `JSON.stringify`s to its API shape.
- **Errors** — `SembleError` and its subclasses `SembleConfigError`, `SembleAuthError`, `SembleApiError`,
  `SembleNotFoundError`, `SembleValidationError`.

## Maintainers

[@burrows99](https://github.com/burrows99) (Raunak Burrows).

## Contributing

Questions and bugs: open an issue at [github.com/burrows99/semblekit/issues](https://github.com/burrows99/semblekit/issues).
PRs are welcome and target `main`. Keep org-specific meaning out of the library — expose the generic Semble
operation.

```bash
npm install        # installs deps, builds via `prepare`
npm run build      # tsc → dist/ + .d.ts
npm run typecheck  # tsc --noEmit
npm test           # placeholder suite
```

Source is TypeScript (ESM, `NodeNext`) in `src/**/*.ts`, compiled to `dist/`. Add a resource by creating its
entity in `src/entities/`, a `src/resources/<resource>.ts`, wiring it onto the client in `src/client.ts`,
and a matching `src/commands/<resource>.ts`.

## License

[MIT](LICENSE) © Raunak Burrows.