Metadata-Version: 2.4
Name: turoeducate-biobank
Version: 0.2.0
Summary: CLI and Python SDK for the TuroEducate Biobank — query specimens, build cohorts, and chat with Turo from the terminal.
Project-URL: Homepage, https://turoeducate.turocrates.ai
Project-URL: Documentation, https://github.com/TurocratesAI/TuroEducate/tree/main/packages/biobank-cli
Project-URL: Source, https://github.com/TurocratesAI/TuroEducate/tree/main/packages/biobank-cli
Project-URL: Issues, https://github.com/TurocratesAI/TuroEducate/issues
Author-email: Turocrates AI <founders@turocrates.ai>
License: Proprietary
Keywords: biobank,cli,cohort,pathology,sdk,turoeducate,wsi
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Healthcare Industry
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Requires-Python: >=3.10
Requires-Dist: click>=8.1
Requires-Dist: httpx>=0.26
Requires-Dist: prompt-toolkit>=3.0
Requires-Dist: pydantic>=2.5
Requires-Dist: rich>=13.7
Provides-Extra: dev
Requires-Dist: mypy>=1.7; extra == 'dev'
Requires-Dist: pytest>=7.4; extra == 'dev'
Requires-Dist: respx>=0.20; extra == 'dev'
Requires-Dist: ruff>=0.1; extra == 'dev'
Provides-Extra: keyring
Requires-Dist: keyring>=24.0; extra == 'keyring'
Description-Content-Type: text/markdown

# turoeducate-biobank

Programmatic access to the **TuroEducate Biobank** — a CLI plus a Python SDK
for querying specimens, building cohorts, exporting CSV, and chatting with
**Turo** (the biobank assistant) from your terminal or scripts.

```text
$ pip install turoeducate-biobank
$ biobank login
$ biobank specimens list -f "Stain Types contains Ki-67" -f "Diagnosis Category eq Breast"
$ biobank ai
```

> Built for pathology research workflows. Currently in **beta**.

---

## Install

```bash
pip install turoeducate-biobank
```

Python ≥ 3.10. Installs a `biobank` command + the `turoeducate_biobank`
Python package.

## Auth

```bash
biobank login
```

`login` walks you through host + email + password, then mints a long-lived
**API token** (`bb_live_…`) and stores it under `~/.config/turoeducate-biobank/credentials.json`
at 0600.

You can also point at a backend with environment variables (CI-friendly):

```bash
export TUROEDUCATE_BIOBANK_HOST=https://app.turoeducate.com
export TUROEDUCATE_BIOBANK_TOKEN=bb_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

### Token scopes

```bash
biobank tokens create --name ci-readonly --scope read --expires-in-days 30
biobank tokens list
biobank tokens revoke <id>
```

Scopes are `read`, `write`, `admin`. A `read` token can list/get/search/export
but can't mint new tokens or modify data.

## CLI cookbook

### Schema

```bash
biobank schema
```

Lists every field in your org's biobank schema, with type + enum choices +
which fields are part of the keyword-search index.

### Specimens

```bash
# list with filters (multi-field)
biobank specimens list \
  -f "Gender eq female" \
  -f "Age at Collection between 40,70" \
  -f "Stain Types contains Ki-67"

# fetch one
biobank specimens get <specimen-id>

# keyword search
biobank specimens search "MMR-deficient"

# export the matching cohort to CSV
biobank specimens export \
  -f "Diagnosis Category eq Breast" \
  -f "Report Date between 2026-04-01,2026-04-30" \
  -o breast-april.csv
```

### Filter mini-DSL

`field op value` — ops: `eq ne gt gte lt lte in contains between`.
- `in` and `between` take comma-separated values:
  `--filter "Diagnosis Category in Breast,GI"`,
  `--filter "Age between 40,60"`.
- Field names that contain spaces (e.g. `Stain Types`) are fine — the parser
  matches the rightmost op token.

### Cohorts

```bash
biobank cohorts list
biobank cohorts create --name "Breast Ki-67" \
  -f "Diagnosis Category eq Breast" \
  -f "Stain Types contains Ki-67"
biobank cohorts apply <cohort-id>          # show matching specimens
biobank cohorts apply <cohort-id> --json
biobank cohorts delete <cohort-id>

# export a saved cohort
biobank specimens export --cohort <cohort-id> -o cohort.csv
```

### Slides

```bash
biobank slides list <specimen-id>
```

### Notes

```bash
biobank notes list <specimen-id>
biobank notes add  <specimen-id> "needs re-cut for IHC panel"
biobank notes delete <note-id>
```

### Chat (one-shot)

```bash
biobank chat ask "histogram of TAT days by diagnosis category"
biobank chat ask "now only the breast cases" --thread-id <id>
biobank chat threads list
biobank chat threads delete <id>
```

### Interactive AI mode

```bash
biobank ai
```

A REPL with rich Markdown rendering, dim-cyan tool-use chips, inline chart
summaries, and slash commands:

| Command                | What it does |
| --- | --- |
| `/threads`             | list saved chats |
| `/open <id-prefix>`    | switch to a chat (resumes its filters) |
| `/new`                 | start a fresh thread |
| `/cohort`              | show the active filter context |
| `/clear`               | clear the cohort context |
| `/save <name>`         | persist the current filters as a named cohort |
| `/export`              | write the current cohort to `./cohort.csv` |
| `/help`                | print all slash commands |
| `/exit`                | leave (Ctrl+D works too) |

Each turn carries the cohort context so multi-turn narrowing works the same
as in the web app:

```
you »  describe the cohort by age and grade
→ filter_specimens(filters=[1 clauses])
→ aggregate(metric=count, group_by=Grade, chart_type=bar)
[Markdown summary + ASCII bar chart]

you  [3 filters] »  now only her2 positive
→ filter_specimens(filters=[3 clauses])
[narrowed cohort + chart]
```

### Self-check

```bash
biobank validate
```

Verifies auth + schema fetch + a single specimen read.

## Python SDK

```python
from turoeducate_biobank import BiobankClient

client = BiobankClient.from_env()                # uses env vars
# or
client = BiobankClient(host="https://app.turoeducate.com",
                       token="bb_live_xxxxxxxx…")

# Browse
schema = client.schema()
for spec in client.specimens.iter_all(filters=[
    {"field": "Stain Types", "op": "contains", "value": "Ki-67"},
    {"field": "Diagnosis Category", "op": "eq", "value": "Breast"},
]):
    print(spec.slide_id_value, spec.metadata.get("Test Code"))

# Save a cohort
ch = client.cohorts.create(
    name="Breast Ki-67",
    filters=[
        {"field": "Stain Types", "op": "contains", "value": "Ki-67"},
        {"field": "Diagnosis Category", "op": "eq", "value": "Breast"},
    ],
)
print(ch.matching_count, "matching")

# Ask Turo programmatically
turn = client.chat.send("describe this cohort", cohort_filters=[
    {"field": "Diagnosis Category", "op": "eq", "value": "Breast"},
])
for m in turn.new_messages:
    if m.role == "assistant":
        for block in m.content:
            if block.get("type") == "text":
                print(block["text"])
```

## Config locations

| Path | Purpose |
| --- | --- |
| `~/.config/turoeducate-biobank/credentials.json` | host + API token |
| `~/.config/turoeducate-biobank/history/ai.history` | `biobank ai` REPL history |

Override the root with `TUROEDUCATE_BIOBANK_HOME=/some/dir`.

## Versioning + changelog

Semver. Breaking CLI/SDK changes only on a major bump. See the project root
[CHANGELOG.md](../../CHANGELOG.md).

## License

Proprietary — © Turocrates AI.
