Metadata-Version: 2.5
Name: dyno-phi
Version: 0.3.0
Summary: Phi — Python SDK and CLI for the Phi protein design API
Project-URL: Homepage, https://design.dynotx.com
Project-URL: Documentation, https://design.dynotx.com/docs
Project-URL: Source, https://github.com/dynotx/phi-api/tree/main/clients/phi
Project-URL: Changelog, https://github.com/dynotx/phi-api/blob/main/clients/phi/CHANGELOG.md
Project-URL: Issues, https://github.com/dynotx/phi-api/issues
Author: Dyno Therapeutics
License-Expression: MIT
Keywords: binder-design,bioinformatics,cli,protein-design,protein-engineering,sdk,structure-prediction
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic>=2.9
Provides-Extra: cli
Requires-Dist: click>=8.1; extra == 'cli'
Requires-Dist: pyyaml>=6; extra == 'cli'
Requires-Dist: rich>=13; extra == 'cli'
Requires-Dist: typer>=0.12; extra == 'cli'
Description-Content-Type: text/markdown

# dyno-phi

Python SDK and CLI for the [Phi](https://design.dynotx.com) protein design API.
The `phi` package exposes synchronous (`PhiClient`) and asynchronous
(`AsyncPhiClient`) clients; the CLI ships behind the `[cli]` extra so the SDK
stays light. It is published to PyPI from `clients/phi` in
[`dynotx/phi-api`](https://github.com/dynotx/phi-api).

## Install

The CLI as an isolated tool on your `PATH`:

```bash
uv tool install "dyno-phi[cli]"
```

`uv tool` provisions its own Python, which covers the client's **Python 3.12+**
requirement on stock macOS, where the system Python is 3.9. Re-run with
`--upgrade` to upgrade. `pip install "dyno-phi[cli]"` into a Python 3.12+ of
your own does the same. From a `phi-api` checkout, `just install-cli` runs the
first form and `just install-cli-dev` installs the working tree.

The SDK inside an existing project, without the CLI's dependencies:

```bash
uv add dyno-phi        # or: pip install dyno-phi
```

Check the install with `phi --version`. `dyno-phi` 0.2.x was an earlier,
unrelated client of a retired API; if `phi --version` prints `0.2.x`, that
client is first on your `PATH` (`which -a phi` lists every match) and
`pip install --upgrade "dyno-phi[cli]"` in the Python that owns it replaces it.
Coming from 0.2.x: the key is `PHI_API_KEY` (or `PHI_KEY`) and the base URL
`PHI_API`, the commands are `phi <group> <command>` as listed under
[CLI](#cli), and Python 3.12+ is required; see
[`CHANGELOG.md`](https://github.com/dynotx/phi-api/blob/main/clients/phi/CHANGELOG.md).

If `uv`'s tool directory is behind another `phi` on `PATH`, sourcing uv's shell
shim is not enough to move it: the shim prepends the directory only when `PATH`
does not already contain it, and on macOS `path_helper` appends inherited
entries behind `/etc/paths.d`, so in a shell that inherits a `PATH` naming the
directory it stays last. Pin the order at the end of `~/.zshrc`:

```zsh
typeset -U path PATH
path=("$HOME/.local/bin" $path)
```

## Authentication

Both the SDK and the CLI read connection settings from the environment, falling
back to `~/.config/phi/config.toml`:

| Variable | Purpose |
|---|---|
| `PHI_API` | Base URL of the API. Its host selects the environment class — `hosted`, `staging`, or `local`. |
| `PHI_KEY` / `PHI_API_KEY` | API key. |
| `PHI_ORG` | Organization ID. Required with a static key. |

```bash
export PHI_API=https://phi-api-staging-917387676927.us-central1.run.app
export PHI_KEY=...     # static staging key
export PHI_ORG=dynotx  # literal static tenant, not the Clerk org
```

With a Clerk key (`ak_...`) the tenant comes from the key, so `PHI_ORG` is
ignored; it is required only for a static key.

Pass `base_url=`, `api_key=`, and `org=` to the client constructor to override
the environment.

## 60-second quickstart

```bash
phi quickstart
```

Creates the `quickstart` project, folds the Trp-cage mini-protein with `ESMFOLD`,
waits, and downloads the results. The manual equivalent is:

```bash
phi jobs submit ESMFOLD --input sequences=@sequence.fasta --wait --out quickstart-output
```

## SDK usage

Submit a job and wait for it, closing the client on exit:

```python
from phi import PhiClient

with PhiClient() as client:
    submitted = client.jobs.submit("ESMFOLD", inputs={"sequences": ["NLYIQWLKDGGPSSGRPPPS"]})
    job = client.jobs.wait(submitted.job_id)
    print(job.status, job.outputs)
```

`AsyncPhiClient` mirrors the same surface for concurrent work:

```python
import asyncio

from phi import AsyncPhiClient


async def fold(sequences: list[str]) -> list[str]:
    async with AsyncPhiClient() as client:
        submitted = await asyncio.gather(
            *(client.jobs.submit("ESMFOLD", inputs={"sequences": [seq]}) for seq in sequences)
        )
        jobs = await asyncio.gather(*(client.jobs.wait(job.job_id) for job in submitted))
    return [job.status for job in jobs]


asyncio.run(fold(["NLYIQWLKDGGPSSGRPPPS", "GSHMKELVLALYDYQEKSPRE"]))
```

Runnable end-to-end scripts live in [`examples/`](examples/): single fold job,
named pipeline, ad-hoc DAG, artifact download, and concurrent async submission.

### Job types and local validation

`client.job_types` lists the job types the API advertises and the JSON Schema for
each one's `params` and `inputs`. Schemas are cached on disk per host for 24 hours;
pass `refresh=True` to refetch.

```python
client.job_types.validate_params("PROTEINMPNN", {"num_seq_per_target": 8})
```

`validate_params` and `validate_inputs` raise `PhiValidationError` on a bad key,
type, enum value, or numeric range. They are a **shallow pre-flight check**:
top-level keys only, with no descent into nested objects or array items. The
server validates fully, so a clean pass locally is not a guarantee the request
will be accepted.

### Knowledge documents

`client.documents` and `AsyncPhiClient.documents` list, read, search, write, and
review tenant-scoped Markdown documents. Use `iter_documents()` and
`iter_versions()` to follow cursor pages. Updates take the active digest as
`if_digest`; a stale value raises `PhiConflictError`. `propose()` creates a draft
that remains outside active reads and search until a document writer calls
`activate()`.

## CLI

Every command reads the same environment and accepts `--json` for scripting.

| Group | Commands |
|---|---|
| `auth` | `login`, `whoami`, `logout`, `profiles` |
| `projects` | `list`, `create`, `show`, `update`, `archive` |
| `datasets` | `list`, `create`, `show`, `update`, `delete`, `copy`, `export`, `sequences` |
| `docs` | `list`, `read`, `search`, `add`, `update`, `history`, `propose`, `activate`, `sync` |
| `models` | `list`, `show`, `schema` |
| `jobs` | `submit`, `list`, `status`, `cancel`, `wait`, `embeddings` |
| `runs` | `submit`, `estimate`, `list`, `status`, `timeline`, `dag`, `cancel`, `resume` |
| `pipeline` | `run`, `validate`, `estimate` |
| `artifacts` | `list`, `download` |
| `export` | `sequences`, `designs`, `structure`, `pae` |
| `logs` | `show`, `download`, `settings` |
| `quota` | (summary), `history` |
| `use` | Set the active project |
| `quickstart` | Run the end-to-end ESMFOLD example |

`phi docs sync <dir> --dry-run` safely plans publication from a clean knowledge
checkout. Without `--dry-run` it publishes only Git-tracked files in the
authored Markdown layer after the checkout's deny-list guard passes, defaults
platform documents to internal access, and skips unchanged content and access.
It does not delete remote-only documents.

## Full reference

See [`docs/sdk-and-cli.md`](https://github.com/dynotx/phi-api/blob/main/docs/sdk-and-cli.md)
for environment and profile resolution, sync/async parity, the complete CLI
reference, the error taxonomy and how a release is cut.
