Metadata-Version: 2.5
Name: opencosmo-portal
Version: 1.2.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.

## 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.
