Skip to main content

Stimulir Console CLI and Python SDK — prompts, models, inference, realtime voice, BYOK, usage, lab and compute.

Project description

stimulir

Command-line interface and Python SDK for the Stimulir Console platform — workspaces, API keys, BYOK credentials, usage/billing, prompts, models, inference, realtime voice, and HybrIE lab/compute.

Built with Python 3.11+, Typer, Rich, and httpx. The optional realtime extra adds a websocket voice client (websockets).

Install

Once published to PyPI:

uv tool install stimulir
stimulir --help
# or run without installing:
uvx stimulir --help

From this repo (development):

uv tool install ./cli          # isolated tool from the local source
# or, for live-editing development:
cd cli && uv venv && uv pip install -e .

Conda/miniconda note: if you use plain pip install -e instead of uv, Anaconda Python builds skip the __editable__.*.pth hook, so the editable install silently fails to import (ModuleNotFoundError: stimulir_cli). uv avoids this entirely.

Python SDK

For application or backend code, add the package to that project's runtime environment instead of installing it as an isolated CLI tool:

uv add stimulir                 # core SDK
uv add 'stimulir[realtime]'     # + the realtime voice client (adds websockets)

Then import the SDK from the public package:

import os

from stimulir import StimulirClient

client = StimulirClient(
    api_base=os.getenv("STIMULIR_API_BASE", "https://api.stimulir.com"),
    api_key=os.environ["STIMULIR_API_KEY"],  # hyb_...
)

The hyb_* key is the normal customer/runtime auth path. Stimulir derives the workspace and allowed platform scope from the key, so application code does not need to pass a workspace id for normal prompt, data, eval, or inference calls.

Configuration & auto-resolution

StimulirClient() and the realtime client resolve everything from the environment when you omit it, so most apps construct them with no args. The same resolvers are exposed for direct use:

from stimulir_cli import config Resolves from (in order) Default
config.get_api_base() STIMULIR_API_BASE https://api.stimulir.com
config.get_api_key() STIMULIR_API_KEYHYBRIE_API_KEY → credentials file
config.get_inference_base_url() STIMULIR_INFERENCE_BASE_URLHYBRIE_MANAGED_BASE_URL {api_base}/api/v1/inference
config.get_realtime_url() STIMULIR_REALTIME_URLHYBRIE_REALTIME_URL {api_base}/api/v1/inference/realtime?provider=vertex (https→wss)
config.get_realtime_model() STIMULIR_REALTIME_MODELHYBRIE_REALTIME_MODEL canonical Vertex Live model
config.get_model_preference() STIMULIR_MODEL_PREFERENCEHYBRIE_MODEL_PREFERENCE [] (caller supplies its own list)

Legacy HYBRIE_* names are a deprecated fallback, always below the STIMULIR_* name. Use config.resolve_env(primary, *legacy, default=...) for your own keys.

Prompts

Versioned prompts that render themselves ({{var}} and {var}; None""):

prompt = client.prompts.get("aca.assessment.agent", label="prod")
text = prompt.render({"category": "AI fluency", "name": "Tosin"})
print(prompt.lineage)  # {"prompt_key": ..., "prompt_version": ..., "prompt_label": ...}

Models

models = client.models.list()  # normalized list[str] of advertised model ids

Realtime voice (stimulir[realtime])

The realtime client lives behind the realtime extra — a plain import stimulir never loads websockets. It speaks the managed gateway's voice protocol and enforces the once-only setup invariant: a second setup on a live connection is swallowed, not forwarded (which is what keeps a voice session from fragmenting into one trace per turn).

from stimulir.realtime import RealtimeClient, AudioDelta, ResponseDone

rt = RealtimeClient(  # url / key / model auto-resolve from config if omitted
    instructions="You are a friendly interviewer.",
    temperature=0.7,
)

async with rt.connect() as conn:           # Bearer-only auth
    await conn.setup()                      # once per connection (idempotent)
    await conn.send_audio(pcm16_16k_mono)   # stream input audio
    await conn.commit()
    await conn.create_response()
    async for ev in conn.events():          # typed events
        if isinstance(ev, AudioDelta):
            play(ev.pcm16)                   # 24k mono PCM16 out
        elif isinstance(ev, ResponseDone):
            break

Reconnection policy is the caller's: each connect() is one connection, and the once-only setup guard resets per connection (which is correct — a reconnect needs exactly one fresh setup).

Login

stimulir login uses a browser-based device authorization — no password is ever typed in the terminal. It prints a link and a short code, you approve in the console, and the CLI receives a revocable stim_cli_ token:

stimulir login
# 1. CLI prints a link + a short user_code, e.g.
#      Go to https://console.stimulir.com/cli and confirm it shows: ABCD-1234
# 2. Approve in the browser (already signed in) — confirm the code, pick a workspace
# 3. CLI receives an opaque stim_cli_ token, stored in
#    ~/.stimulir/credentials.json (0600), with the workspace pre-selected

Bare stimulir (when logged out) offers to run this same flow inline before starting the agent.

The stim_cli_ token is opaque, revocable, non-refreshable, with a 30-day TTL, pinned to your user and the workspace you selected. To rotate it, just log in again. A 401 from the server means the token expired or was revoked — re-run stimulir login.

(Non-production environments can override the API/auth endpoints via STIMULIR_API_BASE env var or ~/.stimulir/config.json.)

Already have a token from the console web app? Paste it as an escape hatch:

stimulir login --token <token>

Inspect or end your session with:

stimulir whoami           # opaque token: shows local email + prefix, plus
                          # server-confirmed identity, workspace, and expiry
stimulir logout           # clears the local credentials file
stimulir logout --remote  # revokes the server-side token, then clears locally

Select a workspace

Most commands are scoped to a workspace (business profile):

stimulir workspace list
stimulir workspace use <workspace-id>

Commands

Agent — the AI engineer in your terminal

Bare stimulir (no subcommand, in a TTY) launches the interactive Stimulir agent against the active workspace. The agent runs server-side (Pi through code-runtime) and executes its tool intents — bash, file reads/writes, glob search — on your machine, with approval prompts. The conversation lives server-side, so the same session shows up in the Engineering traces panel.

# Start the agent (or pass an opening task)
stimulir
stimulir agent "Add a /health endpoint and wire it into the router"

# Resume an existing session
stimulir agent --session <session-key>

# Attach this machine as the local executor for a session started in the app
# (the chat composer's "Continue in: Local" dropdown)
stimulir attach [<session-key>]

Approvals stay on your machine — destructive commands (rm -rf, sudo, force push, key revocation) always prompt even under an "always allow" grant.

API keys (hyb_* inference keys)

stimulir keys create --name cli --env prod --expires-in-days 90 --save
stimulir keys list --include-revoked
stimulir keys revoke <key-id>

The plaintext key is shown exactly once; --save stores it in ~/.stimulir/credentials.json so stimulir infer can use it.

BYOK provider credentials

Providers: openai, anthropic, google_gemini, mistral, aws_bedrock, azure_openai, together_ai, nebius.

stimulir byok add --provider anthropic --label "prod key"   # secret prompted without echo
stimulir byok list
stimulir byok verify <credential-id>
stimulir byok remove <credential-id>

Workspace prompts

Versioned prompt management — every save creates a new immutable version, and labels (e.g. prod) move between versions so you can promote or roll back without editing application code.

stimulir prompts list
stimulir prompts get <key> [--label prod|--version N]
stimulir prompts versions <key>
stimulir prompts create --key <key> --file ./prompt.md --label prod --notes "<change notes>"
stimulir prompts update <key> <version> --notes "<change notes>"
stimulir prompts archive <key> <version>
stimulir prompts label <key> <version> <label>

Data assets

Curate datasets for the training loop, including from agent traces:

stimulir data list
stimulir data upload ./dataset.jsonl --stage raw --target sft
stimulir data from-trace <trace-id> --source agent --target sft
stimulir data stage <asset-id> <raw|cleaning|clean_view|snapshot|lab>
stimulir data unstage <asset-id>
stimulir data bulk-stage --ids <asset-id>,<asset-id> --stage lab --target sft
stimulir data update <asset-id> --name "<name>" --target sft
stimulir data snapshot <asset-id>
stimulir data remove <asset-id>

The typical flow is from-tracestage … labsnapshot — turn an agent run into staged data, promote it, then pin a snapshot a training run consumes.

Usage & billing

stimulir usage --window 30d --group-by model
stimulir billing snapshot

Inference

Uses a hyb_* API key (stimulir keys create --save or STIMULIR_API_KEY):

stimulir infer chat "Summarise IFRS 16 in one paragraph" --model hybrie-mid
stimulir infer chat "Write a haiku about ledgers" --model hybrie-small --stream

HybrIE lab (training + eval)

stimulir lab train sft --family qwen3-4b --lora-rank 8 --examples 500 --epochs 3 --lr 1e-4 --eval-examples 200 --seed 42 --checkpoint-dir runs/sft
stimulir lab train d2l --family qwen3-4b --examples 500 --epochs 3 --lr 1e-4 --eval-examples 200 --seed 42 --checkpoint-dir runs/d2l
stimulir lab train rl --family qwen3-4b --environment niah --prompts 64 --group-size 8 --policy hypernet --lr 1e-5 --kl-beta 0.05
stimulir lab jobs list
stimulir lab jobs get <job-id>
stimulir lab jobs cancel <job-id>
stimulir lab eval runs
stimulir lab eval get <run-id>
stimulir lab eval create-run --data-asset-id <asset-id> --prompt <key>:<version|label> --execute
stimulir lab eval execute-run <run-id>
stimulir lab eval niah --family qwen3-4b --checkpoint-dir ~/hybrie-mounts/d2l-artifacts/<job>/checkpoint --examples 200 --seed 42
stimulir lab eval adapter --family qwen3-4b --adapter-dir ~/adapters/invoices-lora --examples 200 --seed 42
stimulir lab eval rl --family qwen3-4b --environment niah --policy hypernet --checkpoint-dir runs/rl/<job> --tasks 50 --pass-threshold 0.8
stimulir lab adapters list
stimulir lab adapters get <adapter-id>
stimulir lab adapters load <adapter-id>
stimulir lab adapters unload <adapter-id>

Compute (GPU offers + instances + peers)

stimulir compute offers
stimulir compute up <offer-id> --count 2
stimulir compute list
stimulir compute status <instance-id>
stimulir compute down <instance-id>
stimulir compute peers list
stimulir compute peers add --name lambda-a100 --grpc http://10.0.0.5:9090 --realtime http://10.0.0.5:8011
stimulir compute peers remove <peer-id>

Models

stimulir models

HybrIE routing

lab, compute, and models go through the console proxy ({api_base}/api/v1/hybrie/*, Supabase JWT + workspace header) by default. To talk to a HybrIE runtime directly, pass --endpoint http://host:port on any of those commands, or persist it in ~/.stimulir/config.json as hybrie_endpoint — requests then hit {endpoint}/v1/*.

Scripting

Every command accepts --json to emit the raw API response:

stimulir keys list --json | jq '.api_keys[].prefix'

Configuration reference

File Contents
~/.stimulir/config.json api_base, workspace_id, hybrie_endpoint, supabase_url, supabase_anon_key
~/.stimulir/credentials.json (0600) api_key, cli_token (opaque stim_cli_ from device login), optional access_token, refresh_token, expires_at, email

Common environment overrides: STIMULIR_API_BASE, STIMULIR_API_KEY, SUPABASE_URL, SUPABASE_ANON_KEY. Use stimulir workspace use <id> to persist the active CLI workspace.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

stimulir-0.1.183.tar.gz (75.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

stimulir-0.1.183-py3-none-any.whl (73.4 kB view details)

Uploaded Python 3

File details

Details for the file stimulir-0.1.183.tar.gz.

File metadata

  • Download URL: stimulir-0.1.183.tar.gz
  • Upload date:
  • Size: 75.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for stimulir-0.1.183.tar.gz
Algorithm Hash digest
SHA256 3996f702d000a632b5eeead417456defda971089a2ee12e2ba8e8e3de95dc63c
MD5 0873c5c8ee7a6da8661e44ade70080ae
BLAKE2b-256 6f6e70e213158f391fb92a444feab34451a9a8736abb3e20d6cbbd996734f580

See more details on using hashes here.

Provenance

The following attestation bundles were made for stimulir-0.1.183.tar.gz:

Publisher: release-all.yml on stimulir/stimulir-console

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file stimulir-0.1.183-py3-none-any.whl.

File metadata

  • Download URL: stimulir-0.1.183-py3-none-any.whl
  • Upload date:
  • Size: 73.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for stimulir-0.1.183-py3-none-any.whl
Algorithm Hash digest
SHA256 b2e56fd97706129ce47c34fc39e6de6eb04169e774828a9ebe5e19a3cdf53cb8
MD5 ed6fc0ccd9111a42bb589d66d82f959b
BLAKE2b-256 9bc9ef3d4e0e54587dd164abd2c197d42609552a04bf8b91d95cc3fc280d1b51

See more details on using hashes here.

Provenance

The following attestation bundles were made for stimulir-0.1.183-py3-none-any.whl:

Publisher: release-all.yml on stimulir/stimulir-console

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page