Skip to content

Repository files navigation

grain-cli

A comprehensive command-line interface for the Grain API v2 — list and search recordings, pull transcripts and AI summaries, download meeting media, manage webhooks, upload recordings, and export everything about a meeting (summary, video, transcript, and a structured participant list) with a single command.

grain recordings export <id> --out ./meeting
# → ./meeting/summary.md, video.mp4, transcript.json, transcript.txt,
#   participants.json, participants.csv, action-items.json, metadata.json

Install

# from source (this repo)
pnpm install
pnpm build
npm link            # puts `grain` on your PATH

# or run without installing
node dist/index.js --help

Requires Node.js 18+.

Authenticate

Grain supports three token types (see the API docs):

Type Scope Where to get it
Personal Access Token (PAT) acts as you https://grain.com/app/settings/integrations?tab=api
Workspace Access Token (WAT) all workspace data same page (needs workspace access)
OAuth2 acts as the authorizing user register a client with Grain

Store a token

grain auth login                     # prompts for a token (hidden input), stores a PAT
grain auth login --type wat          # store a Workspace token
grain auth login --token grain_pat_… # non-interactive
echo "$TOKEN" | grain auth login     # from a pipe / secret manager

OAuth2 (Authorization Code + PKCE)

grain auth login --oauth \
  --client-id YOUR_CLIENT_ID \
  --client-secret YOUR_SECRET \
  --redirect-uri http://localhost:8976/callback

This opens your browser, runs the loopback flow, and stores the access + refresh tokens. Expired access tokens are refreshed automatically before each command.

Inspect / rotate

grain auth status          # show the resolved profile (token is masked)
grain auth token           # print the resolved access token (for scripts)
grain auth refresh         # force an OAuth refresh
grain auth logout          # forget the active profile's credentials

Tokens can also come from the environment (handy for CI):

export GRAIN_API_TOKEN=grain_pat_…
grain recordings list

Global options

Place these after the command (kubectl-style):

Option Description
--token <token> API token (overrides profile/env)
--profile <name> configuration profile
--base-url <url> override the API base URL
--api-version <version> Public-Api-Version header (default 2025-10-31)
-o, --output <format> table (default in a terminal), json (default when piped), or csv
--fields <list> comma-separated columns to show (table/csv)
--no-color disable colored output (also honors NO_COLOR)
--debug log HTTP requests to stderr
--timeout <ms> per-request timeout
--max-retries <n> / --no-retry control automatic retries on 429/5xx

Recordings

# List (newest first) with filters
grain recordings list --limit 20
grain recordings list --title "all hands" --after 2025-01-01T00:00:00Z
grain recordings list --scope external --team <team-id>
grain recordings list --all -o json                 # every page as JSON
grain recordings list --include participants,ai_summary

# Get one (with optional extra data)
grain recordings get <id> --include all

# Transcript
grain recordings transcript <id>                    # structured segments
grain recordings transcript <id> -f txt             # plain text
grain recordings transcript <id> -f srt --out subs.srt

# Download the media
grain recordings download <id> --out talk.mp4

# Export a whole meeting (summary + video + transcript + participants)
grain recordings export <id> --out ./meeting
grain recordings export <id> --no-video             # skip the media file
grain recordings export --all --after 2025-01-01T00:00:00Z --out ./archive   # bulk

# Upload a local file as a new recording
grain recordings upload ./meeting.mp4               # PAT
grain recordings upload ./meeting.mp4 --user-id <uuid>   # WAT (owner required)

# Manage
grain recordings update <id> --title "New title"
grain recordings tag <id> product-launch
grain recordings untag <id> product-launch
grain recordings share <id> --user <user-id>
grain recordings share <id> --team <team-id>
grain recordings unshare <id> --team <team-id>

What export writes

For each recording it creates a folder containing:

File Contents
summary.md the AI summary (markdown)
video.mp4 / .mov / .mp3 / .m4a the recording media (skip with --no-video)
transcript.json structured transcript segments (speaker, start/end ms, text)
transcript.txt (+ .vtt/.srt) text transcripts (--transcript-format txt,vtt,srt)
participants.json + participants.csv structured participant list
action-items.json AI action items (when present)
highlights.json clips/highlights (when present)
metadata.json the full recording payload

Bulk mode (--all or filters, no id) exports each meeting into its own <slug>-<id8>/ subfolder. A missing transcript or summary for one recording is skipped with a warning; the export continues.

Webhooks

grain hooks list
grain hooks list --type recording_added --state enabled
grain hooks create --type recording_added --url https://example.com/hook
grain hooks create --type recording_added --url https://example.com/hook --include participants,ai_summary
grain hooks delete <hook-id>

Grain sends a reachability test to the URL on creation (it must return 2xx). Event types: recording_added|updated|deleted, highlight_added|updated|deleted, story_added|updated|deleted, upload_status.

Directory

grain users              # list workspace users
grain teams              # list teams
grain meeting-types      # list meeting types

Configuration & profiles

Config lives at ~/.config/grain/config.json (override with GRAIN_CONFIG_DIR or XDG_CONFIG_HOME), written with 0600 permissions. Use profiles to switch between workspaces/accounts:

grain auth login --profile work --type wat
grain config use work            # set the active profile
grain config profiles            # list profiles
grain --profile personal recordings list
grain config path                # print the config file location
grain config show                # dump config (secrets redacted)
grain config set base_url https://api.grain.com

Output & scripting

  • In a terminal you get aligned tables; when piped you get JSON — so grain recordings list | jq … just works.
  • Force a format with -o json|table|csv.
  • Narrow columns with --fields id,title,duration.
  • Human status lines and progress go to stderr; data goes to stdout.
grain recordings list --all -o json | jq '.[].id'
grain users -o csv > users.csv

Environment variables

Variable Purpose
GRAIN_API_TOKEN API token (overrides the stored profile)
GRAIN_BASE_URL API base URL
GRAIN_API_VERSION Public-Api-Version header
GRAIN_PROFILE default profile
GRAIN_CONFIG_DIR config directory
NO_COLOR disable colored output

Rate limits & reliability

Grain allows 300 requests/minute. The client reads x-ratelimit-* headers, and on 429 (or transient 5xx/network errors) it retries with backoff, honoring Retry-After. Disable with --no-retry or tune with --max-retries.

Exit codes

Code Meaning
0 success
1 API error / runtime failure
2 usage / configuration error

Development

pnpm install
pnpm dev -- recordings list     # run from source with tsx
pnpm typecheck
pnpm test                       # vitest (unit + live mock-server integration)
pnpm build                      # bundle to dist/ with tsup

License

MIT

About

Comprehensive command-line interface for the Grain API (v2) — recordings, transcripts, AI summaries, webhooks, uploads, and one-command meeting export.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages