@theplato/tiro-cli
v0.4.0
Published
Tiro AI notes & transcripts — agent-first command line
Maintainers
Readme
tiro CLI
AI notes & transcripts — an agent-first command line for Tiro. The "feet" to MCP's "hands": filesystem-heavy, pipe-friendly, context-economical.
Quick start
npm install -g @theplato/tiro-cli
tiro auth login # browser opens; OAuth + PKCE
tiro notes search "Q3 Planning" --since 7d --jsonAlready authenticated through MCP? Reuse your token:
TIRO_TOKEN="$(your_token)" tiro notes listWhy tiro CLI
Tiro already ships an MCP server for Claude Desktop, Cursor, and Code. So why a CLI?
| | MCP | tiro CLI | |---|---|---| | Result lands in | Agent context window | Filesystem (or stdout pipe) | | Token cost / session | thousands (schema injected) | dozens (per call) | | Hosts | MCP-aware only | Any shell — CI, cron, ad-hoc agents | | Best for | small reads, multi-turn reasoning | bulk export, file ops, scripting |
The CLI is not a replacement for MCP. It's the same data through a different surface optimized for filesystem-heavy and shell-native workflows.
→ Background reading: MCP vs API vs CLI — the hands and feet of agents (TBD)
Features
- 🔐 OAuth Authorization Code + PKCE — no copy-paste tokens, no secrets in shell history. Tokens live in OS Keychain.
- 📁
--outputwrites to disk — stdout becomes a single line of metadata. Agents stay context-light. - 🪞 Same JSON shape as MCP —
tiro notes transcript --format jsonmirrorsget_note_transcriptexactly. Switch surfaces without changing parsers. - 🧵 NDJSON streams by default — pipe to
jq,head,xargs. No buffer-in-memory surprises. - 🤖 Agent-aware — TTY detection auto-selects pretty vs JSON.
error.suggestionfield for auto-recovery. - 🚫 No voice in v1 — intentionally matches MCP feature parity (audio uploads belong elsewhere).
Installation
npm install -g @theplato/tiro-cli # npm
pnpm add -g @theplato/tiro-cli # pnpm
yarn global add @theplato/tiro-cli # yarn
bun add -g @theplato/tiro-cli # bun
tiro --versionFrom source (during alpha)
git clone [email protected]:plato-corp/tiro-cli.git
cd tiro-cli
npm install
npm run build
npm link
tiro --helpHomebrew (planned for v1.0)
brew install plato-corp/tap/tiroSystem requirements: Node.js 20+. macOS / Linux / Windows.
Authentication
tiro auth login # opens browser, OAuth Authorization Code + PKCE
tiro auth status # shows current account + token expiry
tiro auth logout # clears keychain + DCR client cacheTokens are stored in the OS-native credential manager:
- macOS — Keychain
- Linux — Secret Service (requires
gnome-keyringorkwallet) - Windows — Credential Manager
For CI / headless / agent use, set TIRO_TOKEN:
export TIRO_TOKEN=... # overrides keychain
tiro notes listUsage
List recent notes
tiro notes list # pretty table in TTY
tiro notes list --json # NDJSON for pipes
tiro notes list --keyword "OKR" --since 30d # OpenSearch reorder by keyword
tiro notes list --folder <id> --limit 100 --cursor <token>Deep keyword search (returns notes + their primary documents)
tiro notes search "Q3 Planning" # positional keyword
tiro notes search "OKR" --since 2026-04-01 --until 2026-05-01
tiro notes search "Acme Corp" --folder <id> --json | jq '.[] | .guid'--since / --until accept ISO-8601 (2026-04-01T10:00:00Z) or relative (7d, 24h, 30m).
Get one note → stdout
tiro notes get <guid> # markdown to TTY
tiro notes get <guid> --format json # JSON to stdout
tiro notes get <guid> --include transcript # include speaker-attributed paragraphsGet one note → file (agent-friendly)
tiro notes get <guid> --output ./meeting.md --include transcript
# stdout: {"ok":true,"data":{"saved":"./meeting.md","size":12450,"format":"md","guid":"...","title":"..."}}This is the killer pattern for agents — the actual content goes to disk; only metadata returns to the context window.
Raw transcript only
tiro notes transcript <guid> # md by default in TTY, txt in pipe
tiro notes transcript <guid> --output ./transcript.md
tiro notes transcript <guid> --output ./clean.md --no-timestamps # strip ### time headers
tiro notes transcript <guid> --format json --output ./paragraphs.json # MCP-shape JSONIn markdown, the timestamp now appears once per paragraph as a ### mm:ss
header instead of being attached to every speaker line. Use
--no-timestamps to omit them entirely (handy for raw saving / LLM ingest).
--format json returns the exact shape MCP's get_note_transcript emits ({noteGuid, title, participants, createdAt, recordingDurationSeconds, paragraphs[]} with each paragraph carrying segments[] of {content, speaker:{label,name}|null}).
Connect to Claude Code (MCP)
tiro mcp install
# prints: claude mcp add --transport http tiro https://mcp.tiro.ooo/mcp
tiro mcp info --json # endpoint, transport, install commandThe CLI is the agent's feet (read, save, browse). The hosted MCP at
mcp.tiro.ooo is the agent's hands (interactive
tool calls inside the loop). See AGENTS.md for the full
agent contract.
Commands
tiro auth login Sign in via OAuth (browser-based, PKCE)
tiro auth status Show current account and scopes
tiro auth logout Clear stored credentials
tiro notes list List notes (lightweight metadata)
tiro notes search Deep keyword search (notes + documents hydrated)
tiro notes get Get a single note (stdout or file)
tiro notes transcript Get the full transcript (matches MCP get_note_transcript)
tiro mcp info Show hosted MCP endpoint info
tiro mcp install Print one-line claude-mcp-add command
# Coming in v0.4:
tiro notes export Bulk-export search results to a directory
tiro templates list/get Document templates
tiro share-links {C/R/D} Manage note share links
tiro folders search Search user / team folders
tiro schema [<command>] Print JSON Schema (for agents)Full sample of every command: tiro <command> --help.
Agent contract: AGENTS.md.
Release history: CHANGELOG.md.
Global options
--hostname <url> API base URL (default: https://api.tiro.ooo)
--json Force JSON output (NDJSON for lists)
--pretty Force pretty (human) output
--quiet Suppress non-error output
--verbose Verbose logging to stderr
--no-color Disable ANSI colors
-h, --help Show help
-v, --version Print versionEnvironment variables
| Variable | Purpose |
|---|---|
| TIRO_TOKEN | Bearer token (overrides keychain — for CI / agents) |
| TIRO_HOSTNAME | API base URL |
| TIRO_OUTPUT_DIR | Default --output-dir for export commands |
| NO_COLOR | Disable colors (no-color.org) |
Exit codes
| Code | Meaning |
|---|---|
| 0 | success |
| 1 | generic error |
| 2 | usage error |
| 4 | auth required |
| 64 | EX_USAGE |
| 65 | EX_DATAERR |
| 78 | EX_CONFIG (no token, run tiro auth login) |
For AI agents
If you're an agent (Claude Code, Cursor, ChatGPT) calling tiro CLI from a shell:
- Default to
--json: predictable shape, NDJSON for streams. - Always use
--outputfornotes get/notes transcript— keeps the actual content out of your context window. The stdout response is one line of metadata. tiro notes transcript --format jsonmatches MCP'sget_note_transcriptJSON exactly. Reuse your MCP parser.- Pipe instead of buffer:
tiro notes search "..." --json | jq -c '.[] | select(.recordingDurationSeconds > 600)'. - Read errors as JSON:
error.code,error.errorType,error.suggestionare stable. Thesuggestionfield is designed for auto-recovery (e.g."tiro auth login"→ run that next). - Respect exit codes:
4= auth needed,78= no token configured.
Worked example — 30 days of "Acme Corp" meetings:
# 1. Search → metadata + hydrated documents (NDJSON)
tiro notes search "Acme Corp" --since 30d --json > /tmp/acme.jsonl
# stdout: ~12 lines of NDJSON, ~3KB total
# 2. Pull guids without loading bodies
cat /tmp/acme.jsonl | jq -r '.guid' > /tmp/guids.txt
# 3. Download transcripts to disk; agent reads paths instead of content
xargs -I{} tiro notes transcript {} --output ./out/{}.md < /tmp/guids.txt
# Context cost so far: ~80 tokens (paths + counts).
# Disk: 12 markdown files ready for grep / Read tool.Real participant names rendered in markdown will look like:
**[Yeoul, 00:12]** Let's start with the Acme deal pipeline.
**[Evan, 00:18]** They just signed the LOI.Development
npm install
npm run dev -- --help # tsx live-reload
npm run typecheck # tsc --noEmit
npm run test # vitest run
npm run build # tsup → dist/bin/tiro.jsStack: TypeScript ESM (Node 20+), commander for parsing, zod for response validation, @napi-rs/keyring for OS keychain, open for browser launch.
See CLAUDE.md for working with this repo via Claude Code.
Architecture
The CLI sits on the public Tiro API alongside the MCP server, sharing the same OAuth provider:
┌──────────────────────────────┐
│ Tiro Backend (Kotlin) │
│ /v1/external/* + /v1/mcp/* │
└──────────────┬────────────────┘
│
┌────────────────────┼────────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ tiro CLI │ │ Tiro MCP │ │ Web app │
│ (this repo) │ │ (mcp.tiro) │ │ │
└──────────────┘ └──────────────┘ └──────────────┘
(filesystem, (in-context, (humans)
bulk, pipe) schema-typed)OAuth Authorization Code + PKCE flow:
- Dynamic Client Registration (RFC 7591) — no preconfigured client_id needed
- Loopback redirect on an ephemeral
127.0.0.1:<port> - PKCE S256 challenge, no client secret stored
- JWT issued for 180 days, stored in OS Keychain
- Same token works on
/v1/external/*and/v1/mcp/*(audience-list overlap)
Roadmap
- ✅ v0.1 — Auth (
login,status,logout) +--help - ✅ v0.2 — Notes core (
list,search,get,transcript); MCP-shape transcript JSON; first test suite - ⏳ v0.3 —
notes export(bulk → directory + manifest.jsonl) - ⏳ v0.4 — Templates, share-links, folders,
schema - ⏳ v1.0 — Stable. Public docs, license decision, Homebrew tap.
- 🔮 v1.x — Device Flow (RFC 8628), shell completions, self-update
See SPEC.md for the full v1 design and CHANGELOG.md for release history.
Contributing
This repo is currently private alpha. Feedback and bug reports go to the internal Slack #tiro-backend channel; once we open up, this section will list public contribution guidelines.
License
Proprietary. © ThePlato. All rights reserved.
Once we ship v1.0, the license decision (MIT / Apache 2.0 / proprietary) will be revisited.
