npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@theplato/tiro-cli

v0.6.8

Published

Tiro AI notes & transcripts — agent-first command line

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.

npm version Node.js


Quick start

npm install -g @theplato/tiro-cli
tiro auth login                                 # browser opens; OAuth + PKCE
tiro notes search "Q3 Planning" --since 7d --json

Already authenticated through MCP? Reuse your token:

TIRO_TOKEN=... tiro notes list

Why 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.
  • 📁 --output writes to disk — stdout becomes a single line of metadata. Agents stay context-light.
  • 🪞 Same JSON shape as MCP — tiro notes transcript --format json mirrors get_note_transcript exactly. Switch surfaces without changing parsers.
  • 🕸️ Workspace wiki — tiro wiki search / page / mentions / graph read the auto-extracted knowledge graph; --workspace targets a specific workspace.
  • 🧵 NDJSON streams by default — pipe to jq, head, xargs. No buffer-in-memory surprises.
  • 🤖 Agent-aware — TTY detection auto-selects pretty vs JSON. error.suggestion field 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 --version

From source (during alpha)

git clone [email protected]:plato-corp/tiro-client.git
cd tiro-client
corepack enable
yarn install --immutable
yarn workspace @theplato/tiro-cli build
node services/cli/dist/bin/tiro.js --help

Homebrew (planned for v1.0)

brew install plato-corp/tap/tiro

System 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 the stored keychain credential

Tokens are stored in the OS-native credential manager:

  • macOS — Keychain
  • Linux — Secret Service (requires gnome-keyring or kwallet)
  • Windows — Credential Manager

For CI / headless / agent use, prefer a process-scoped TIRO_TOKEN:

TIRO_TOKEN=... tiro notes list
op run --env-file ./tiro.env -- tiro notes list

TIRO_TOKEN overrides the keychain. If it is set, tiro auth login stops before opening a browser because the new keychain credential would not be used. Run unset TIRO_TOKEN first (PowerShell: Remove-Item Env:TIRO_TOKEN) to switch to keychain authentication.


Usage

List recent notes

tiro notes list                                              # pretty table in TTY
tiro notes list --json                                       # NDJSON for pipes
tiro notes list --keyword "OKR" --since 30d                  # Reorder by keyword relevance
tiro notes list --folder <id> --limit 100 --cursor <token>
tiro notes list --workspace <guid>                           # scope to one workspace

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'
tiro notes search "release" --workspace <guid>               # scope to one workspace

--since / --until accept ISO-8601 (2026-04-01T10:00:00Z) or relative (7d, 24h, 30m).

Workspace scoping. notes list / notes search resolve their workspace in this order: explicit --workspace <guid> first, then the workspace your API key is bound to (workspace-scoped keys), then — for an unbound credential (a personal key or an OAuth login) — across every workspace you belong to, with a one-line warning to stderr. Unlike wiki, notes are never silently pinned to a single "default" workspace. Run tiro wiki workspaces for guids, or tiro auth status to see which workspace your credential is bound to.

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 paragraphs

Get 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 JSON

In 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}).

Browse workspace folders

tiro folders list                                            # flat list (id, sharingType, title)
tiro folders list --workspace <guid> --json
tiro folders tree --workspace <guid>                         # hierarchy, indented by depth

Folders are workspace-scoped. The workspace resolves from --workspace, else your API key's bound workspace. Unlike notes, folders have no cross-workspace path — an unbound credential must pass --workspace (run tiro wiki workspaces for guids). Use a folder id with tiro notes list --folder <id>. sharingType is one of PRIVATE / ALL_MEMBER_VIEWER / ALL_MEMBER_EDITOR / LIMITED.

List word memories

tiro word-memories list                                      # custom transcription vocabulary
tiro word-memories list --workspace <guid> --json

Word memories are the custom vocabulary that biases a workspace's transcription. Read-only and workspace-scoped (same resolution as folders).

Explore the workspace wiki

The wiki is Tiro's auto-extracted knowledge graph (entities, concepts, and their links) over your notes. These commands are read-only and mirror the MCP wiki tools. Wiki is a paid, opt-in feature — calls against an ineligible or not-activated workspace return the backend's upgrade message and a non-zero exit.

tiro wiki workspaces                                         # which workspaces? (guid + wiki on/off)
tiro wiki search "Ontology" --workspace <guid>               # find pages by keyword
tiro wiki page <pageGuid> --workspace <guid>                 # body + mentions + links
tiro wiki mentions <pageGuid> --workspace <guid>             # where the page is grounded in notes
tiro wiki graph <pageGuid> --mode around --workspace <guid>  # neighborhood graph
tiro wiki graph --mode seed --type CONCEPT --workspace <guid> # overview graph (no pageGuid)
tiro wiki graph --mode seed --folder <folderId>              # overview scoped to one folder's notes

--workspace is optional — omit it to use the default workspace for your API key. If your account belongs to multiple workspaces, run tiro wiki workspaces first and pass the guid of the one whose wiki is enabled. graph results are capped (default 50 nodes); a truncated: true flag signals you to narrow the query.

Connect to Claude Code

tiro plugin install    # recommended — one step: adds the Tiro plugin to Claude Code
                       # (auto-wires the Tiro MCP server + ships Tiro workflows)

Prefer the manual MCP-only path? It still works:

tiro mcp install
# prints: claude mcp add --transport http tiro https://mcp.tiro.ooo/mcp

tiro mcp info --json   # endpoint, transport, install command

The 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.

Stay up to date

tiro update --check          # is a newer version available? (JSON for agents/CI)
tiro update                  # self-update to the latest published version
tiro update --dry-run        # print the upgrade command without running it
tiro update --pm pnpm        # force a package manager (default: auto-detected)

tiro update upgrades by running your global package manager (npm, pnpm, yarn, or bun — auto-detected). In a TTY a banner also appears when a newer version is published; agents and CI should poll tiro update --check (it exits 0 and reports updateAvailable). Disable the banner with NO_UPDATE_NOTIFIER=1.


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 plugin install        Install the Tiro plugin into Claude Code (recommended)
tiro mcp info              Show hosted MCP endpoint info
tiro mcp install           Print one-line claude-mcp-add command

tiro update                Self-update to the latest version (--check / --dry-run)

tiro wiki search/page      Read the workspace knowledge graph
tiro wiki mentions/graph   Page mentions and graph slices
tiro folders list/tree     Browse workspace folders (flat or hierarchy)
tiro word-memories list    List custom transcription vocabulary

# Coming later:
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 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 version

Environment variables

| Variable | Purpose | | ----------------- | --------------------------------------------------------------------------- | | TIRO_TOKEN | Process-scoped bearer token (overrides keychain; unset before auth login) | | 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:

  1. Default to --json: predictable shape, NDJSON for streams.
  2. Always use --output for notes get / notes transcript — keeps the actual content out of your context window. The stdout response is one line of metadata.
  3. tiro notes transcript --format json matches MCP's get_note_transcript JSON exactly. Reuse your MCP parser.
  4. Pipe instead of buffer: tiro notes search "..." --json | jq -c '.[] | select(.recordingDurationSeconds > 600)'.
  5. Read errors as JSON: error.code, error.errorType, error.suggestion are stable. The suggestion field is designed for auto-recovery (e.g. "tiro auth login" → run that next).
  6. 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

corepack enable
yarn install --immutable
yarn workspace @theplato/tiro-cli dev --help
yarn workspace @theplato/tiro-cli typecheck
yarn workspace @theplato/tiro-cli test
yarn workspace @theplato/tiro-cli build

Stack: TypeScript ESM (Node 20+), commander for parsing, zod for response validation, @napi-rs/keyring for OS keychain, open for browser launch.

See AGENTS.md for the repository's shared agent guidance.


Architecture

The CLI sits on the public Tiro API alongside the MCP server, sharing the same OAuth provider:

                    ┌──────────────────────────────┐
                    │ Tiro Backend                  │
                    │  /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:

  1. The official CLI uses Tiro's persistent public client (no client secret)
  2. Loopback redirect on an ephemeral 127.0.0.1:<port>
  3. PKCE S256 challenge, no client secret stored
  4. JWT issued for 180 days, stored in OS Keychain
  5. The token is bound to /v1/external/*; MCP uses a separate resource token

Roadmap

  • ✅ v0.1 — Auth (login, status, logout) + --help
  • ✅ v0.2 — Notes core (list, search, get, transcript); MCP-shape transcript JSON; first test suite
  • ✅ v0.5 — wiki command group (workspace knowledge graph, read-only)
  • ✅ v0.6 — folders and word-memories (workspace-scoped, read-only)
  • ⏳ next — notes export, templates, share-links, 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 can be sent to [email protected]; 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.

Folder authentication

tiro folders list and tiro folders tree require a user identity: OAuth or an account API key. Workspace and organization system keys cannot list folders, even with all scopes enabled. With an unbound account credential, pass --workspace <guid> (tiro wiki workspaces lists them).

Check tiro auth status for the active credential source and user. TIRO_TOKEN overrides the keychain; remove it before tiro auth login. If the server reports insufficient_scope, sign in again and grant the required permission, or update your API key permissions. An unknown scope in status is not proof of missing scope.