@moda-ai/cli
v1.29.1
Published
CLI for Moda - AI agent analytics and observability
Maintainers
Readme
moda-cli
CLI for Moda -- AI agent analytics and observability.
Query your conversation analytics from the terminal.
Install
npm install -g @moda-ai/cliOr use without installing:
npx -p @moda-ai/cli moda overviewSetup
Run the wizard to authenticate, pick an org, and provision an API key:
moda initOr set the key manually:
export MODA_API_KEY="moda_sk_..."Get your API key from moda.dev/settings.
Usage
Find things by meaning, then drill in:
moda search "user wants a refund" --mode=semantic # Semantic/keyword/hybrid message search
moda search "stripe.charges.create" --mode=keyword # Exact identifiers, incl. tool calls
moda search "checkout" --include-tool-io # Search tool inputs/outputs too
moda context <conversation_id> --msg-index=5 # Read the exact turn
moda audit <conversation_id|trace_id> # Raw span/trace auditProduction intelligence:
moda overview --days-back=30 # Health briefing (KPIs, clusters, activity)
moda ask "what should I fix first?" # Grounded answer with evidence
moda investigate # Ranked issues worth fixing
moda problems # Cross-signal Problems by root cause
moda problem <problem_id> # One Problem: full dossier
moda problem <problem_id> --evidence # ...attribution evidence (keyset paged)
moda problem <problem_id> --reports # ...investigation reports
moda problem <problem_id> --conversations # ...affected conversations
moda problem-feedback <problem_id> --action=mark_fixed # Close the loop from the terminalSignals:
moda emotions --family=confusion # Multi-family emotion detections
moda hallucinations --kind=contradicted # Grounding: contradicted/verified outputs
moda frustrations --include-window --window=1 # Legacy single-family frustration view
moda tool-failures # Tool failure overview
moda tool-failure-detail <tool_name> --include-window
moda step-scores <conversation_id> # Graph-PRM per-step reward curvesConversations, clusters, memory:
moda conversations --search="error" --environment=production
moda clusters # Walk the topic hierarchy
moda clusters --search="billing disputes" # Find a cluster by meaning
moda world-state <conversation_id> # Agent memory (slots/threads/events)
moda world-state <id> --snapshot --msg-index=42 # What the agent believed at turn 42
moda world-state <id> --replay --message-count=50 # State evolution frame by frameLive tail (one JSON line per new item — tail -f for your agent):
moda tail # New conversations, every 15s
moda tail --signal=all --interval=30 # Conversations + emotion detectionsPrompt management:
moda prompts init # Create .moda/prompts.yml
moda prompts status # Read-only local prompt status
moda prompts sync # Upload changed prompt versions
moda prompts promote support.triage --label=prod --version=pver_abc123Feedback:
moda feedback "cluster label looks wrong" --category=bad_cluster_labelOutput adapts to where it runs: piped/CI/agent environments get schema-versioned
JSON (moda.agent.v1), an interactive terminal gets human prose. Force a mode
with --json, --agent, or --human. In JSON modes, pipe to jq:
moda overview | jq '.data.metrics'
moda frustrations | jq '.data.frustrations[].primary_cause'Every command supports moda <command> --help for scoped usage, and
moda manifest --json describes the full machine protocol (commands, exit
codes, event schema) for agents.
Prompt Management
Prompt management is code-first. Keep prompts in prompts/**/*.prompt.md or
prompts/**/*.prompt.json, sync them with the CLI, and render them through the
SDK so LLM spans include prompt metadata.
moda prompts init
moda prompts status
moda prompts syncstatus and diff are read-only. sync uploads changed versions and writes
.moda/prompts.lock.json. promote moves a remote dev, staging, or prod
label.
const rendered = Moda.prompt("support.triage").render({
ticket: { text: userMessage },
});rendered = moda.prompt("support.triage").render({
"ticket": {"text": user_message},
})Anchors and message windows
Rows returned by moda frustrations and moda tool-failure-detail carry
a top-level anchor block naming the exact turn the event fired on:
// frustrations
{ "kind": "frustration", "conversation_id": "...", "msg_index": 12,
"signal": "exasperation", "quote_preview": "...", "all_turns": [...],
"no_anchor": false }
// tool-failure-detail examples
{ "kind": "tool_failure", "conversation_id": "...", "msg_index": 7,
"tool_name": "search", "tool_use_id": "...",
"error_subtype": "SEARCH_NO_RESULTS", "no_anchor": false }msg_index is the 0-indexed turn where the breakage happened. For
frustrations it's derived from key_turns[0] (the same turn the API centers
the embedded window on), falling back to user_quotes[0].turn when
key_turns is empty. no_anchor: true means no anchor could be derived for
that row.
Both commands accept two flags to inline a message window per row:
| Flag | Default | Description |
|------|---------|-------------|
| --include-window | off | Attach a window field with the message slice centered on the anchor |
| --window=N | 1 | Half-width (1–5). --window=1 ⇒ 3 messages total (anchor ± 1) |
Environment Variables
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| MODA_API_KEY | Yes | -- | Your Moda API key (moda_sk_...) |
| MODA_BASE_URL | No | https://moda.dev | Base URL for the Data API |
Documentation
License
MIT
