Metadata-Version: 2.4
Name: cosmo-cli
Version: 0.1.2
Summary: Set up Cosmo once; the Cosmo SDKs and your coding agent pick it up
Author: Socratic AI Inc.
License-Expression: Apache-2.0
Project-URL: Homepage, https://askcosmo.ai
Project-URL: Repository, https://github.com/socratic-ai/cosmo-ai
Keywords: cosmo,cli,realtime,voice
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click<9,>=8.1
Requires-Dist: tomli-w<2,>=1.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pyright>=1.1.350; extra == "dev"
Requires-Dist: ruff>=0.6; extra == "dev"
Dynamic: license-file

# `cosmo`

Set up Cosmo once. The Cosmo SDKs — Python, TypeScript, Swift — pick up the
credential from disk, so an app you run locally needs no key in its source,
its environment, or its config.

```bash
cosmo init       # sign in, install the Cosmo skill, print what to do next
```

That is the whole setup. Underneath it are four commands you can also run on
their own:

```bash
cosmo login      # opens your browser; pick a workspace
cosmo whoami     # who you are and where
cosmo logout     # revoke the stored key and remove it from this machine
cosmo version
```

`cosmo init` reuses a credential that already works rather than replacing one
the SDKs are using; only `cosmo login` retires and re-mints unconditionally.

## The Agent Skill

`cosmo init` also installs the Cosmo [Agent Skill](https://agentskills.io) to
`~/.claude/skills/cosmo/`, which teaches a coding agent the current SDK API
across all three languages. Skip it with `cosmo init --no-skill`.

Two routes, in order:

1. `skills add socratic-ai/cosmo-ai --skill cosmo --global --yes` — through a
   `skills` executable if one is on PATH, else through `npx`. Both flags are
   load-bearing: without `--skill` the installer takes every skill the
   repository contains, and without `--global` it writes them into the
   current working directory. Named this way, a source that cannot supply
   `cosmo` installs nothing at all.
2. The copy bundled in this package, whenever the fetch does not leave a
   `SKILL.md` at the target — including the exit-0-but-installed-nothing
   case, which is why the check is the file rather than the exit code.

Route 2 is why this never requires Node, and it is the route in use today.

The bundled copy is `cosmo/skill_data/`, a copy of
`sdks/cosmo-realtime/skills/cosmo/`. Edit the skill in the SDK tree and
re-copy; `tests/test_skill.py` asserts the two are byte-identical, so drift
fails in CI rather than shipping one version to npm and another to PyPI.

There is no session and nothing running in the background. `cosmo login`
mints a workspace API key, writes it to `~/.cosmo/credentials`, and exits.
Every later read is a file read. The key expires, and you sign in again.
`cosmo logout` is a revocation, not just a file delete: it retires the key
server-side (against the backend the profile names), then removes the
profile — other profiles, and anything another tool wrote, are preserved.
If the server can't be reached the credentials are left in place, so a live
key is never forgotten locally while it still works.

## The credentials file

`~/.cosmo/credentials`, mode `0600`:

```toml
version = 1

[default]
slug       = "acme"
api_key    = "cosmo_..."
api_key_id = "8d1f1f16-0f5e-4a1a-9a1b-2c3d4e5f6a7b"
base_url   = "https://platform.askcosmo.ai"
expires_at = "2026-11-01T20:11:39Z"
```

Each table is a **profile**. `default` is used unless `COSMO_PROFILE` or
`--profile` says otherwise — the environment variable matters because the SDKs
read this file from inside your own process, where a CLI flag cannot reach
them.

This file is a contract, not an implementation detail — several SDKs read it,
so the shape is pinned by tests in `tests/test_credentials.py`.

- **`version` is file-level.** A reader checks it once and then knows how to
  interpret every profile. A file from a newer CLI is refused rather than
  guessed at.
- **Profiles are named credential sets.** `default` is used unless a caller
  asks for another. A writer preserves profiles it does not recognise, so one
  SDK cannot drop another's data.
- **`base_url` is an origin with no path.** SDKs append their own API paths;
  a stored `/api` suffix would double up.

If another tool already owns a profile name and keys it differently, the
file is copied to `credentials.bak` (`.bak.1`, `.bak.2`, …) before that
profile is replaced, so nothing is overwritten without a copy.

Override the location with `COSMO_CREDENTIALS_FILE` — useful for tests and for
keeping work and personal credentials apart.

## Install

```bash
pipx install cosmo-cli
```

Or into any Python 3.11+ environment: `pip install cosmo-cli`.

## Development

```bash
python -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/pytest
.venv/bin/pyright
```

Runtime dependencies are `click` and `tomli-w` — both pure Python, neither
with transitive dependencies of its own. A Homebrew formula needs a `resource`
block per transitive dependency, so each addition is recurring packaging work,
and a compiled one drags a build toolchain into the formula. For scale: typer
+ rich would be 8 blocks, and pydantic ships a Rust extension.

Reading TOML is stdlib (`tomllib`); only writing it is not.
