Skip to content

Latest commit

 

History

History
 
 

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

omi-cli

Talk to Omi from your terminal. Designed for humans and agents.

omi-cli is the command-line interface to the Omi developer API. It exposes scoped, agent-friendly verbs for the four primary nouns Omi maintains about you:

  • memories — facts and learnings the system knows about you
  • conversations — captured & processed audio/text exchanges
  • action items — tasks and follow-ups
  • goals — tracked progress metrics

It's intentionally small, scriptable, and JSON-first — everything you need to plug Omi into shell pipelines, CI jobs, agent harnesses, or just your own personal automation.

Install

pipx install omi-cli            # recommended — isolated install
# or
pip install omi-cli

After install, the binary on your $PATH is named omi:

omi --version
omi --help

The PyPI distribution name is omi-cli (the bare omi slot belongs to an unrelated package). The console command is omi regardless.

Quickstart

# 1. Log in. With no flags, omi-cli asks how you want to authenticate:
omi auth login
# → 1) Browser — sign in with Google or Apple (recommended for humans)
# → 2) API key — paste a developer key from app.omi.me (recommended for agents/CI)

# 2. Start using it:
omi memory list
omi conversation list --limit 5
omi action-item list --open
omi goal list

Pass --json to any command (as a global flag, before the verb) to get machine-readable output, ready for jq, agent harnesses, or whatever else:

omi --json memory list | jq '.[] | {id, content}'

Pretty output displays returned text literally, including square brackets and emoji-like codes such as :warning:. Styling applies to the table layout, not to the contents of your memories or conversations.

Auth

Two auth methods, both fully wired:

Method Best for How to use
Dev API key (omi_dev_*) Agents, CI, headless, scoped permissions omi auth login --api-key ... or env var
Firebase OAuth (Google/Apple) Humans on a laptop omi auth login --browser

The browser flow opens your default browser for OAuth, captures the code on a localhost callback, and stores a Firebase ID token + refresh token. The ID token is auto-refreshed before each request when it's near expiry — you shouldn't need to think about it.

omi auth login                  # interactive picker (browser or key)
omi auth login --browser        # force OAuth (default provider: google)
omi auth login --browser --provider apple
omi auth login --api-key K      # force API-key path
omi auth login < key.txt        # piped key, useful in CI
omi auth status                 # show profile + masked credential + expiry
omi auth whoami                 # round-trip to verify the credential works
omi auth refresh                # force a Firebase refresh (no-op for API keys)
omi auth logout                 # wipe the credential

An API-key login candidate is checked before replacing the saved credentials. If verification rejects it with HTTP 401 or 403, the existing profile and active profile selection remain unchanged. Other HTTP errors retain the existing store-and-warn behavior. A transport failure leaves saved credentials unchanged; browser OAuth is a separate flow.

You can also set OMI_API_KEY in the environment to bypass on-disk config entirely — handy in containers and CI:

export OMI_API_KEY=omi_dev_...
omi memory list

Profiles

State lives at ~/.omi/config.toml (overridable via $OMI_CONFIG). The file holds one or more named profiles, each with its own auth method and API base. Saving configuration preserves unknown settings at both the root and profile levels, so editing a known setting does not discard extensions from newer clients. Switch between them with --profile:

omi config profile use work
omi auth login                  # logs in the active profile (work)
omi --profile personal memory list

Common config:

omi config show
omi config path
omi config set api_base https://api.staging.omi.me
omi config set local_api_url http://127.0.0.1:47778
omi config set local_token ...
omi config profile list
omi config profile delete old-account --yes

Local Omi Desktop API

omi local talks to a running Omi Desktop local API. Configure the active profile once, or use env vars for ephemeral agent sessions:

omi local configure --url http://127.0.0.1:47778 --token ...
export OMI_LOCAL_API_URL=http://127.0.0.1:47778
export OMI_LOCAL_TOKEN=...

Common local tools:

omi --json local status
omi --json local tools
omi --json local call search_screen_history --args-json '{"query":"pricing page","days":7}'
omi --json local search-screen "pricing page" --days 7 --app Safari
omi --json local screenshot 123 --output /tmp/omi-shot.jpg
omi --json local recap --days-ago 1
omi --json local sql "SELECT appName, COUNT(*) FROM screenshots GROUP BY appName"
omi --json local task search "taxes" --include-completed

Agent screen-history workflow:

  1. Check availability with omi --json local status; look for screen_history_available, screenshot_count, and indexed_screenshot_count.
  2. Discover tool schemas with omi --json local tools.
  3. Search OCR/screen history with omi --json local search-screen "query" --days 7 or run exact SQL against screenshots when you need app/window filters.
  4. Use a returned screenshot_id with omi --json local screenshot <id> --output /tmp/omi-shot.jpg.
  5. Validate the file before handing it to vision tooling, for example file /tmp/omi-shot.jpg.

When semantic search returns no results, JSON mode also tries a literal substring search across app names, window titles, and OCR text. In this fallback, % and _ in the query or --app filter match those characters literally, rather than acting as SQL wildcards.

If pixels are not available, JSON-mode errors preserve Desktop's structured fields such as status_code, error, reason, hint, and screenshot_id. For example, screenshot_pending means the frame is still in the active video segment; retry shortly or choose an older screenshot ID from search results.

Task writes should only run after the user clearly asks for that change:

omi --json local task complete task_123
omi --json local task delete task_123 --yes

Command surface

The full tree (run omi --help for the live version):

omi
├── auth
│   ├── login [--browser] [--api-key KEY]
│   ├── logout
│   ├── status
│   ├── whoami
│   └── refresh
├── config
│   ├── show
│   ├── path
│   ├── set <key> <value>
│   └── profile
│       ├── list
│       ├── use <name>
│       └── delete <name>
├── memory
│   ├── list [--limit N] [--offset N] [--categories ...]
│   ├── get <id>
│   ├── create <content> [--category ...] [--visibility ...] [--tag ...]
│   ├── update <id> [--content ...] [--category ...] [--visibility ...] [--tag ...]
│   └── delete <id> [-y]
├── conversation
│   ├── list [--limit N] [--start-date ...] [--end-date ...] [--include-transcript]
│   ├── get <id> [--include-transcript]
│   ├── create [--text ...] [--text-source ...] [...]
│   ├── from-segments <file.json> [--source ...]
│   ├── update <id> [--title ...] [--discarded/--no-discarded]
│   └── delete <id> [-y]
├── action-item
│   ├── list [--completed/--open] [--conversation-id ...] [...]
│   ├── get <id>
│   ├── create <description> [--due-at ...]
│   ├── update <id> [--description ...] [--completed/--open] [--due-at ...]
│   ├── complete <id>
│   └── delete <id> [-y]
├── local
│   ├── configure --url URL --token TOKEN
│   ├── status
│   ├── tools
│   ├── call <tool> [--args-json JSON]
│   ├── search-screen <query> [--days N] [--app NAME]
│   ├── screenshot <id> [--output PATH]
│   ├── recap [--days-ago N]
│   ├── sql <query>
│   └── task
│       ├── search <query> [--include-completed]
│       ├── complete <id>
│       └── delete <id> [-y]
└── goal
    ├── list [--limit N] [--include-inactive]
    ├── get <id>
    ├── create <title> --target N [--type ...] [--current N] [--unit ...]
    ├── update <id> [--unit ... | --clear-unit] [...]
    ├── progress <id> <value>
    ├── history <id> [--days N]
    └── delete <id> [-y]

conversation from-segments reads JSON files as UTF-8 (with or without a BOM), UTF-16, or UTF-32, independently of the system's default text encoding.

Global flags

--json                 Emit JSON to stdout (machine-readable, agent-friendly).
--profile, -p NAME     Use a specific profile.
--api-base URL         Override the API base URL.
--verbose, -v          Log HTTP traffic to stderr.
--no-color             Disable colored output (also honors $NO_COLOR).
--version              Print the version.
--help                 Show contextual help.

Exit codes (stable contract)

0  success
1  usage error (bad flags, missing args, validation)
2  auth error (no creds, expired token, insufficient scope)
3  server error (5xx, connection failure)
4  rate limited (429) — retry recommended
5  not found (404)

For agents

The CLI is built so an LLM can use it without a wrapper:

  • --json returns valid JSON to stdout. Nothing else writes to stdout in JSON mode (errors go to stderr as {"error": "...", "detail": "..."}).
  • Stable exit codes (above) let an agent disambiguate retryable vs terminal errors.
  • Successful resource delete --yes commands preserve the API response in JSON mode. A successful response without a body is emitted as JSON null.
  • Rate-limit errors include a Retry-After window in the message and surface the policy name (dev:conversations, etc.) so an agent can back off intelligently.
  • OMI_API_KEY and OMI_API_BASE env vars work without any prior auth login.
  • OMI_LOCAL_API_URL and OMI_LOCAL_TOKEN override profile-local Desktop API settings for omi local.

See examples/agent_quickstart.md for a worked example.

Rate limits

The dev API enforces per-policy hourly limits:

Policy Limit
dev:conversations 25/hour
dev:memories 120/hour
dev:memories_batch 15/hour

The CLI retries 429 automatically with exponential backoff and honors the server's Retry-After hint where present. After all retries are exhausted you get exit code 4 plus a message telling you how long to wait.

Datetime options

Conversation and action-item datetime options accept ISO timestamps with Z (UTC), numeric offsets, and optional fractional seconds, for example --due-at 2026-09-08T12:30:00Z or --start-date 2026-09-08T12:30:00.123456+05:30. Offsets are preserved in API requests. Date-only values and timestamps without an offset remain supported; the CLI does not assign a timezone to those inputs.

Development

# Editable install with dev extras
pip install -e .[dev]

# Run the test suite
pytest -q

# Lint
black --check --line-length 120 --skip-string-normalization sdks/python-cli/
mypy omi_cli

# Build a wheel + sdist (no upload, no tag)
bash release.sh --build-only

License

MIT — see LICENSE.