IrisBooks Manual
Chapters
Manual / CLI command reference
Chapter 08

CLI command reference

Every iris command, grouped by purpose. The CLI has two surfaces:

  • File-mode commands operate on a local book folder. With no path argument they walk up from the current directory to find the book, so you can run them from anywhere inside the book tree.
  • Cloud commands (iris api …) talk to the IrisBooks server and operate on a book ID, not a path. They need you to be signed in (iris api login) or to set IRIS_API_TOKEN.

Run iris <command> -h for the authoritative, up-to-date flags of any command. iris -h lists everything; iris api -h lists the cloud subcommands.

Keeping this page honest: the command list mirrors the commands table in iris/cmd/iris/main.go. If you add or rename a command there, update this page (and its Japanese mirror).

Setup

iris init

Create a new book. Bare iris init runs a guided wizard; flags skip the prompts.

iris init [flags] [path]
FlagMeaning
--nameBook display name
--regionRegion code (JP, US; default JP)
--languageLanguage (ISO 639-1)
--entity-kindindividual / company / partnership / trust
--chartChart variant: general / it / food (default general)
--currencyCurrency (ISO 4217; default per region)
--fiscal-start-monthFiscal-year start month 1–12
--sampleSeed ~40 demo journals to explore
--postingPosting policy written into LLM-GUIDE.md: approve (default — you review and post) / auto (your assistant posts everything that validates)
--book-idPre-link to an existing server book (advanced)

iris onboard

Wire this machine’s AI assistant to the book: register iris mcp serve with MCP clients and write the Claude Code skill. Claude Code’s project config (.mcp.json) is always written; Claude Desktop, the Codex CLI, Cursor, Gemini CLI, and VS Code are registered when detected on the machine, or forced with their flag.

iris onboard [--book PATH] [--claude-desktop] [--codex] [--cursor] [--gemini] [--vscode] [--install-path] [--no-skill] [--dry-run]
iris onboard --status [--json]    # read-only report: what is registered where

--status reports each client’s registration state (including whether the registered binary still exists — the stale state re-running iris onboard fixes). --json makes the report machine-readable. Re-running iris onboard is always safe: registrations are updated in place, never duplicated.

iris offboard

The inverse of iris onboard: remove the irisbooks MCP registration from every client config (including leftovers from clients no longer installed) and the Claude Code skill. Does not touch the book’s data or your sign-in. Idempotent — safe to run before a clean reinstall.

iris offboard [--book PATH] [--keep-skill] [--remove-path] [--dry-run]
FlagMeaning
--keep-skillKeep the Claude Code skill (when other books still use it)
--remove-pathAlso remove the binary installed by onboard --install-path and revert its PATH entry
--dry-runPrint what would be removed without removing anything

iris uninstall

Remove iris itself from this machine: the iris binaries, your sign-in and local config (~/.config/irisbooks — the CLI session is revoked server-side first), the Claude Code skill, machine-level MCP registrations (Claude Desktop, Codex CLI), and the PATH entry from iris onboard --install-path. It always prints the exact list of what it found on this machine and asks for confirmation before deleting anything.

Your books are never touched — they are plain files you own. Per-book agent wiring (.mcp.json inside a book) is also left in place; run iris offboard --book PATH first if you want that removed too.

iris uninstall [--yes] [--dry-run]
FlagMeaning
--yesSkip the confirmation prompt
--dry-runPrint the deletion plan without removing anything

iris clone

Fetch a server book to disk (the lifecycle peer of init). Requires sign-in. Works immediately on a brand-new book created in the web app or with iris api books new — server-created books are born with config/book.yaml and a starter chart of accounts.

iris clone <book-id> [dest] [--force]

Inspect & validate

iris status

Print a book’s identity, fiscal-year start, archive flags, and how many draft drafts exist (drafts are excluded from reports).

iris status [--json] [path]

iris validate

Validate a book’s structure and entries: YAML, double-entry balance, account existence, date consistency, status values, and (JP taxable books) tax classification.

iris validate [--v] [--json] [path]

--v prints every file scanned; --json emits issues + counts and exits 1 on errors.

iris hash

Print the canonical content hash of a single file (useful when comparing local bytes against what the server accepted).

iris hash [--raw] <file>

iris organize

Bring a book’s layout into canonical shape. Dry-run by default.

iris organize [--apply] [--fix fy-folders,extensions,empty-raw,config-typos] [--json] [path]

iris balance

Trial balance as of a date (posted entries only).

iris balance [--as-of YYYY-MM-DD] [path]

iris report

Financial statements. Subcommands:

iris report tb [--as-of YYYY-MM-DD] [path]               # trial balance
iris report pl [--from D] [--to D] [path]                # profit & loss
iris report bs [--as-of YYYY-MM-DD] [path]               # balance sheet
iris report ledger --account PATH [--as-of D] [path]     # general ledger for one account
iris report sum --by KEY[,KEY...] [--from D] [--to D] [--year YYYY] [path]
                                                         # group-by sums over journal lines

Report output is JSON (amounts in minor units — the same shape the web API serves). There is no text-table mode: terminal column alignment is unreliable for Japanese account names, your AI consumes JSON anyway, and the web app is the formatted view for humans. A --json flag is still accepted as a no-op for compatibility.

report sum groups posted journal lines by the keys you choose — account, unit, payee, month, or a dotted field like tax.category — and returns debit/credit/net totals plus a line count per group (e.g. --by tax.category,tax.rate --year 2026 for consumption-tax figures). Lines missing a key form an explicit empty-keys group, so unclassified lines are visible rather than dropped. --year uses the fiscal year (begins-in convention); --from/--to take arbitrary inclusive dates.

Find journals by any combination of filters (combined with AND). Deterministic and offline.

iris search [--from D] [--to D] [--min N] [--max N] [--payee S] \
  [--status draft,posted,closed] [--account S] [--tag S] [--json] [path]

The status column shows the effective status: a journal dated inside a sealed fiscal year displays as closed regardless of what its file says, and --status closed filters on exactly those.

iris show

Cross-references for a path: for a document, the journals that cite it; for a journal, the documents it cites plus siblings.

iris show [--json] <path> [path]

iris export

Export journals, trial balance, ledgers, or assets as CSV (UTF-8 with BOM).

iris export [--out DIR] [--year YYYY] [--as-of YYYY-MM-DD] [path]
iris export assets [--out DIR] [path]

Fixed assets

iris asset

Fixed-asset depreciation and reporting.

iris asset schedule [path]                  # print each asset's depreciation schedule
iris asset depreciate --month YYYY-MM [path]  # generate that month's entries (status: draft)
iris asset depreciate --year YYYY [path]      # one FY-total entry per asset, dated the FY's last day

Pick one cadence per fiscal year: depreciate refuses to write annual entries into a year that already has monthly ones, and vice versa (mixing them would double-count).

Editing & promoting

iris post

Promote journals from draft to posted, then sync (if linked). If the book owner turned on posting approval (web app → Settings), posting is web-only: iris post refuses locally and the server rejects any pushed status flip with APPROVAL_REQUIRED. Validates each file is non-empty and balanced first. A journal dated inside a sealed fiscal year is refused (“FY <n> is sealed (closed period) — run iris reopen <n> to amend it, then re-seal”).

iris post [--dry-run] <file>...
iris post [--dry-run] --all

--all posts every draft draft in the book instead of naming files — including drafts you didn’t author (phone/connector drafts, email-ingested entries, generated depreciation). Drafts that fail validation are reported and left as drafts. This is the ritual for books with the auto posting policy.

iris diff

Show what would be pushed — local changes versus the last-synced snapshot.

iris diff                # list all pending changes
iris diff <relpath>      # line-level diff for one file
iris diff --paths        # names + kind only

Sync & conflicts (cloud)

iris sync

One explicit pass: push local changes, pull remote changes, report per-file accept/reject. Needs the book linked to the cloud and you signed in.

iris sync [--quiet] [--json] [--allow-bulk-delete] [path]

Exit codes: 0 clean · 1 rejections/conflicts/IO · 2 usage/setup · 3 terminal disconnect (book deleted, access revoked, session expired).

If a sync would delete most of the book’s cloud files at once, the server refuses those deletions (BULK_DELETE_REFUSED) as a safety net. When the mass deletion is really what you want, re-run with --allow-bulk-delete.

iris conflicts

When a push conflicts (409), the server version takes the canonical path and your version becomes a .conflicted sidecar.

iris conflicts list [path]
iris conflicts resolve <path> --keep mine|cloud [path]

The usual resolution is to merge by hand (edit the canonical file, delete the sidecar, iris sync). See Troubleshooting.

iris attention

Manage the local queue of server-side rejections.

iris attention list [path]              # show path + code + issues
iris attention retry [path]             # drop suppression and ask the engine to re-push
iris attention retry [path] --path <relpath>   # just one file

iris yearend

Write the next fiscal year’s opening-balances journal (期首残高) from a year’s closing balances — the accounting half of a year-end close (the compliance half, locking and archiving, is iris api seal). Balance-sheet accounts carry forward at their closing balance; income and expense reset to zero; net income folds into the equity account named by opening_balance_equity_account in config/book.yaml (or the book’s sole equity account). The entry lands at journals/<fy+1>/<MM>/0000-opening-balances.md, tagged opening-balance — reports treat the latest such entry as the starting point for balances, which is what makes each fiscal year self-contained.

Safe to re-run while the next year is still open: late corrections to the closed year flow into the entry (identical results are a no-op). Once the next year is sealed, the entry is frozen — a mismatch is reported with remedies, never silently rewritten. Unposted drafts dated in the year are warned about (they don’t carry). Works offline; run iris sync afterwards to push.

iris yearend <fiscal-year> [path]

iris reopen

Unlock a sealed fiscal year for amendment. The seal is unlocked on the server (a sealed period refuses all writes until this runs; edits made while reopened are permanently flagged as post-seal edits). The year’s files never left the working tree — sealing locks and archives, it does not remove files — so there is nothing to restore: edit them directly, run iris sync to push your edits, and iris api seal to close the year again.

iris reopen <fiscal-year> [path]

Prices (Net Worth)

iris price

Record/list unit prices offline, and sync them to the server. User-scoped (not stored in the book).

iris price add --unit BTC --price 9850000 [--currency JPY] [--date YYYY-MM-DD] [--source S]
iris price list [--unit BTC] [--json]
iris price sync

MCP server

iris mcp

Run a Model Context Protocol server that exposes the iris verbs to a BYO agent, pinned to one book.

iris mcp serve [--book PATH] [--http 127.0.0.1:PORT]

Local tools: validate, diff, balance, report, status. Cloud tools (when authenticated): sync, seal, export_from_cloud.

iris version

iris version

Cloud commands (iris api …)

These operate on a book ID and require authentication.

Account-scoped

iris api login

Browser-assisted sign-in. This device gets its own CLI session: signing out of the web app does not affect it, it expires only after 90 days unused (each use renews it), and you can revoke it in the web app under your Settings (avatar menu) → API tokens.

iris api login
iris api whoami     # validate the cached token
iris api logout     # revoke this device's session and remove the token

iris api books

List or create cloud books, or link a local book to one.

iris api books list [--json]
iris api books new [flags] [--json]
iris api books link <book-id> [path]

iris api token

List or revoke your Personal Access Tokens. Minting a new PAT is web-only (your Settings → API tokens); revocation is available here too so an automated run can revoke the PAT it used when it finishes. Requires a signed-in session or a Full-access PAT.

iris api token list [--json]
iris api token revoke <token-id>

iris api config

Show or set per-user preferences (reporting currency, default unit scales). Merged into new books at iris init.

iris api config
iris api config set --base-currency USD
iris api config set --set-unit BTC:8,XAU:4
iris api config set --remove-unit XAG

Per-book

iris api grants

Manage book access (owner-only).

iris api grants list [--json] <book-id>
iris api grants invite --email EMAIL <book-id>
iris api grants role --user USER_ID --to OWNER|BOOKKEEPER|REVIEWER <book-id>
iris api grants revoke --user USER_ID <book-id>

iris api inbox

Inbound email for a book: show the receiving address, manage the sender allowlist, and review quarantined mail. See “Receipts by email”.

iris api inbox show [--json] <book-id>
iris api inbox allow <pattern> <book-id>       # user@host or *@host
iris api inbox disallow <pattern> <book-id>
iris api inbox quarantine [--json] <book-id>

iris api seal

Close a fiscal year (period seal) and build its archive snapshot. A sealed period is locked: every write into it is refused, on every surface — but the year’s files stay in your working tree. To amend a sealed year, run iris reopen <fy> — edits made while reopened are flagged in the audit trail (iris api history) — then re-run this command to close the year again (the new seal supersedes the old one). --preview lists the files the seal’s archive would capture, without sealing. Sealing is refused while the year still contains draft drafts — a sealed year must be fully resolved. Post each draft if it belongs in the year, delete it if abandoned, or change its date into an open year; --preview lists the blockers.

iris api seal --period YYYY [--type yearly] [--preview] <book-id>

iris api archive

Download a sealed fiscal-year archive (triggers the build and waits).

iris api archive download --year YYYY [--out DIR] [--timeout 5m] [--interval 5s] <book-id>

iris api balance / holdings / history

iris api balance [--as-of YYYY-MM-DD] <book-id>              # server-side trial balance (JSON output)
iris api holdings [--as-of YYYY-MM-DD] [--json] <book-id>    # per-unit net positions
iris api history [--path PATH] [--limit N] [--json] <book-id> # durable correction/deletion record

iris api export

iris api export [--out DIR] [--year YYYY] [--as-of YYYY-MM-DD] <book-id>  # CSVs
iris api export audit <book-id>                                          # auditor bundle

With --year, the export is restricted to journals dated in that fiscal year. Sealed years stay in the live tree, so they export like any other year.

iris api price / networth

iris api price add --unit BTC --price 9850000 [--date YYYY-MM-DD] [--source S]
iris api price list [--unit BTC] [--json]

iris api networth [--as-of YYYY-MM-DD] [--json]              # cross-book total
iris api networth --book <book-id> [--as-of YYYY-MM-DD] [--json]
iris api networth settings [--include|--exclude|--reset <id>]
iris api networth history [--months N] [--refresh] [--json]
iris api networth movers [--as-of D] [--compare D] [--json]

Environment variables

VariablePurpose
IRIS_API_TOKENPersonal Access Token; takes precedence over the cached login token
IRIS_BOOKDefault book ID for cloud commands (a positional arg still wins)
IRIS_API_ENDPOINTAPI endpoint override; takes precedence over everything below
IRISBOOKS_APP_BASEApp base URL (default https://irisbooks.jp)
IRISBOOKS_API_BASEAPI base URL (default <app-base>/api)

When none of the endpoint variables are set, commands use the endpoint saved by your last iris api login — so a session signed in to one environment keeps talking to that same environment.

Common exit codes

CodeMeaning
0Success
1Validation errors, rejections, or I/O failure
2Usage or setup error (not in a book, bad flags)
3Terminal disconnect — sync commands only (book deleted, access revoked, session expired)