Metadata-Version: 2.4
Name: cosmo-cli
Version: 0.1.0
Summary: Sign in to Cosmo once; the Cosmo SDKs pick up your credentials
Author: Socratic Inc.
License: Apache-2.0
Project-URL: Homepage, https://askcosmo.ai
Project-URL: Repository, https://github.com/socratic-ai/cosmo
Keywords: cosmo,cli,realtime,voice
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
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`

Sign in to 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 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
```

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

Not published yet. From a checkout:

```bash
pipx install --editable ./tools/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.
