Metadata-Version: 2.5
Name: opencosmo-portal
Version: 1.3.0
Summary: CLI and local MCP server for the OpenCosmo platform
Requires-Python: >=3.11
Requires-Dist: click>=8.1.0
Requires-Dist: filelock>=3
Requires-Dist: httpx>=0.28.1
Requires-Dist: joserfc>=1.6.1
Requires-Dist: jsonschema>=4.26.0
Requires-Dist: mcp<3,>=2
Requires-Dist: packaging>=25.0
Requires-Dist: pydantic>=2.0
Description-Content-Type: text/markdown

# OpenCosmo Portal CLI (`ocp`)

Command-line client and local MCP server for the
[OpenCosmo Portal](https://github.com/ArgonneCPAC/OpenCosmoPortal): query
cosmological simulation datasets at DOE Leadership Computing Facilities from
your terminal or from an AI assistant.

```bash
pip install opencosmo-portal      # in a checkout: cd cli && uv sync, then prefix commands with `uv run`
```

## Quick start

```bash
ocp auth login                    # Globus device-code flow; --browser for a local redirect flow
ocp task list
ocp task info <slug>
ocp task run <slug>               # interactive; or --input/--file JSON
ocp run status <run-id> --watch
ocp run results <run-id>
```

Shipped profiles: `production` (`https://cosmoexplorer.alcf.anl.gov`,
default), `staging` (`https://opencosmo-test.cels.anl.gov`, internal network),
`dev` (`http://localhost:8000`). Pass `--profile <name>` or set a default
with `ocp config set-profile`. Shipped profiles cannot be removed but their
URLs can be overridden with `ocp config add-profile`; former official URLs
migrate automatically on upgrade, overrides are kept.

Config and tokens live in `~/.opencosmo/` (`config.json`, `tokens/<profile>.json`).
Output is `table` or `--format json`. After interactive commands the CLI
checks PyPI for a newer release at most once per 24 h and shows active
portal announcements (outages, new features, deprecations) cached for
5 minutes per portal — both stderr-only, bounded by a shared one-second
deadline, and never affecting the command. `OPENCOSMO_DISABLE_UPDATE_CHECK=1`
and `OPENCOSMO_DISABLE_ANNOUNCEMENTS=1` turn them off. `ocp announcements`
lists active announcements on demand.

## Commands

`ocp --help` and `ocp <group> --help` list everything. Overview:

| Group        | Commands                                                                                                             |
| ------------ | -------------------------------------------------------------------------------------------------------------------- |
| `ocp auth`   | `login`, `logout`, `status` (refreshes unless `--no-refresh`), `consent` (grant flow authorizations some tasks need) |
| `ocp config` | `list`, `show`, `add-profile`, `set-profile`, `remove-profile`                                                       |
| `ocp task`   | `list`, `info <slug>`, `run <slug>`                                                                                  |
| `ocp run`    | `list`, `status <id> [--watch]`, `logs`, `results`, `cancel`, `archive`                                              |
| `ocp docs`   | Browse portal documentation                                                                                          |
| `ocp whoami` | Current user                                                                                                         |
| `ocp announcements` | Active portal announcements |
| `ocp mcp`    | `start` — local stdio MCP server                                                                                     |
| `ocp admin`  | `tasks`, `datasets`, `docs`, `announcements`, `service-accounts`, `users`, `runs`, `audit-logs`, `stats`                              |

Interactive `ocp task run` shows leaf fields of the task's nested input as a
numbered table with their currently active constraints, re-evaluates the
schema's conditional rules after every edit (repairing or flagging values that
became invalid), and validates the complete input against the task schema
before submitting. `--input`/`--file` payloads are validated as supplied, with
no repair. `ocp task info` lists parameters by dotted path
(`filters.sod_halo_mass.minval`), matching the nested JSON those options take.

`ocp run status` renders the server's run-diagnostics projection (failure
code and phase, guidance, warnings, bounded traceback, evidence state,
correlation IDs); against an older server it falls back to the summary view.

## MCP server for AI assistants

```bash
ocp mcp start
```

Claude Desktop (`claude_desktop_config.json`):

```json
{
  "mcpServers": { "opencosmo": { "command": "ocp", "args": ["mcp", "start"] } }
}
```

This stdio server supports both legacy and modern MCP handshakes and calls the
portal API with the profile's CLI token. It is distinct from the hosted remote
endpoint at `<portal-origin>/mcp`, which is modern-protocol-only and has its
own OAuth token; `ocp auth logout` does not clear a remote MCP client's token.

The server offers one `run_<task>` tool per task, loaded when it starts. If
that fails, for example because the portal is unreachable or the login has
expired, the server retries on each later tool request and tells the client
that its tool list changed once the tasks load, so no restart is needed.

For an unattended setup, set `OPENCOSMO_API_KEY` in the server's environment
(the `"env"` object of the `mcpServers` entry). The server then exchanges the
key for a short-lived token, exchanges it again when that token expires, and
needs no `ocp auth login` or token file. Without the variable it uses the
stored login.

## Administration

All `ocp admin` commands require admin permissions. For CI, set
`OPENCOSMO_API_URL` and `OPENCOSMO_API_KEY` (a service-account key); the CLI
exchanges the key for a JWT per run and persists neither. `OPENCOSMO_API_KEY`
takes precedence over stored profile tokens.

**Content deployment** — categories, datasets, task adapters, and user docs are
complete desired-state payloads. Each command accepts `dir <path>`,
`url <archive-url> --subdir <dir>` (`--header "PRIVATE-TOKEN:..."`), or
`gitlab --host --project --ref --job --subdir [--gitlab-token-env]`; archives
may be `.zip`, `.tar`, `.tar.gz`, `.tgz`. Discovery is non-recursive: only
direct children of the selected directory are read (for tasks, `*.json`; for
docs, Markdown at the root plus one subdirectory level, root `index.md`
required — pass the directory containing `index.md` inside a docs checkout
or extracted artifact, not the checkout root). Deploy in this order:

```bash
ocp admin tasks categories sync build/categories.json --yes
ocp admin datasets sync build/datasets.json --yes
ocp admin tasks install dir build/tasks --strict
ocp admin docs deploy dir <docs-checkout>/content/documentation --yes
```

Every command dry-runs server-side first and shows the planned
create/update/delete actions; without `--yes` it asks for confirmation
(defaulting to no when anything would be deleted). `tasks install --strict`
exits 1 on any warning (for example an unregistered category slug) before
sending real installs; installs are idempotent, so re-running after fixing
the registry is safe. Dataset sync validates binding tags, so task installs
fail on a fresh instance until datasets are synced; deleting a dataset that
installed tasks still reference warns rather than fails.

**Service accounts:**

```bash
ocp admin service-accounts create ci-task-manager --profile task-manager --description "CI"
ocp admin service-accounts rotate-key ci-task-manager      # create/rotate print the key once
ocp admin service-accounts revoke-key ci-task-manager KEY_ID --yes
ocp admin service-accounts disable ci-task-manager --yes
```

Enabled service accounts are valid through `urn:opencosmo:service-account`;
the `task-manager` profile additionally needs
`urn:opencosmo:service-account:task-manager` in the backend's `AUTH_ADMINS`.

## Releasing

Run the **Release** workflow in GitHub Actions with `component=cli` (or
`all` for a major bump); the resulting `cli-v*` tag triggers
`publish-cli.yml`, which tests, verifies the tag matches `pyproject.toml`, and
publishes to PyPI via trusted publishing. No manual tagging.
