IrisBooks Manual
Chapters
Manual / Book file-format reference
Chapter 09

Book file-format reference

A book is a folder of plain Markdown and YAML. This page is the reference for what’s in it. You rarely need to hand-write these files — your AI does, and iris validate checks them — but understanding the shape helps.

Folder layout

your-book/
├── config/
│   ├── book.yaml                 # identity, region, fiscal year, currency
│   ├── chart-of-accounts.yaml    # your accounts
│   ├── rules.yaml                # optional categorization hints (may be empty)
│   └── overlays/                 # optional: this book's own overlay layer (rules, recipes)
├── raw/                          # source documents; any structure, type inferred from content
├── journals/
│   └── YYYY-MM/
│       └── YYYY-MM-DD-<payee>-NN.md
├── assets/
│   └── YYYY/<asset-name>.md       # fixed assets (by acquisition year)
├── filings/
│   └── <recipe>.md                # recorded return figures, written by overlay recipes
├── notes/
│   ├── workflow.md  decisions.md  open-questions.md  todos.md
│   └── raw/<mirror of raw/>.md    # parse caches
├── compiled/                      # AI-generated reports (regeneratable)
├── README.md  LLM-GUIDE.md  CLAUDE.md   # human + AI guides
└── .iris/                         # runtime state — never hand-edit

Notes:

  • A book covers one fiscal year (fiscal_year in book.yaml). In journals/YYYY-MM/, the folder is the year and month of the entry’s accounting date (date:) — its first seven characters: 2026-07-15 files under journals/2026-07/. That holds for any fiscal start month: on an April-start book, 2027-02-15 files under journals/2027-02/. The folder always reflects the accounting date, not the period the entry covers.
  • The folder is only a cache of the date in the file — the file is authoritative. Other layouts won’t corrupt anything (reports, seals, and exports read dates, not folders), and iris organize moves misplaced journals back to the canonical layout.
  • The filename is the entry’s permanent identity. Files you or your AI write follow YYYY-MM-DD-<payee>-NN.md; entries created in the web app or through the remote connector are named by the server YYYY-MM-DD-<payee>-jNNN.md, keeping the payee’s own script. Both are valid, and the separate numbering means they never collide.
  • .iris/ holds the local book ID and sync state; it’s machine-local and never synced.

config/book.yaml

schema_version: 1
book_id: lb_...                 # local ID at init; replaced by cloud ID when linked
name: "Acme Design"
region: JP                      # ISO 3166-1; selects the tax/locale rules
overlay: jp@2026.09.1           # region rules version, pinned at init (see below)
language: ja                    # ISO 639-1; chart language follows this
currency: JPY                   # ISO 4217
scale: 0                        # minor-unit exponent — IMMUTABLE (JPY 0, USD 2, BHD 3)
fiscal_start_month: 4           # 1–12
fiscal_year: 2026               # the fiscal year this book covers (2026-04-01..2027-03-31 here)
created_at: "2026-06-20T12:34:56Z"

# Optional:
strict_accounts: false          # false = allow accounts not in the chart (default is strict)

units:                          # non-currency units (forex, crypto, metals, shares)
  - symbol: BTC
    scale: 8
    name: "Bitcoin"

consumption_tax:                # JP only — see Japan tax page
  status: taxable
  accounting: tax_included
  method: general
  business_class: 5

units is optional and starts empty in new books. Known currencies use built-in quantity precision (JPY: 0, USD/EUR: 2, KWD: 3), without entries in this list. An explicit units entry overrides that currency’s quantity precision; custom units such as BTC or shares require a declaration. Unknown symbols must include scale; even whole-unit custom units must explicitly specify scale: 0. Omitting it (or writing null) is rejected by local parsing, synced book uploads, and account unit-template API writes. For example, - {symbol: USD, scale: 4} permits four fractional digits in a USD quantity. It does not change the precision of journal amounts: those use the book’s top-level scale, which defaults from currency when omitted. An explicit top-level scale: 0 remains zero, even for USD. Signed-in iris init copies available account unit templates; --no-user-defaults skips them. Account preferences affect new books only. The BTC entry above is an example, not a preinstalled default.

scale is the number of fractional digits the currency uses, and it is immutable — JPY is 0 (whole yen, no decimals), USD/EUR are 2, the Gulf dinars are 3. Region-specific blocks like consumption_tax ride along opaquely: the universal engine ignores them, and the JP overlay reads them.

fiscal_year is the fiscal year the book covers, named by the year it starts in. iris init sets it to the year holding today (--fiscal-year picks another), and iris yearend sets the next one in the book it creates. It is required: iris validate and the cloud refuse a book.yaml without it, and the cloud refuses a change to it — the next year is a new book, not an edit to this one.

overlay names the region overlay — the versioned set of country-specific checks and computations that iris validate and the server apply to this book (for Japan: toku_rei regime constraints, the ¥3M/yr 少額減価償却 cap, 消費税 税区分/税率 rules). Japan is the first region with an overlay. A book in a region without one has no overlay: line and gets the universal checks only; once an overlay for its region is published, iris overlay upgrade pins it. The pin is written once at iris init from the version built into your iris, so the rules a book is checked against never change silently. Your iris includes every version released before it was built, so a book pinned to any of them works offline. Newer versions are released on their own, without a new iris: iris overlay upgrade moves the pin to the newest one after checking it, and iris overlay fetch downloads a version newer than your iris that a book already pins (for example, a book set up on another computer). Both verify the version’s signature first. For legacy overlay: books, if your iris has neither built in nor downloaded the pinned version, iris validate warns and names the version it used instead. The cloud always checks the version the book pins, and refuses a pin to a version that has not been published.

Pin several published overlays

overlays selects an unordered set of exact versions. Use it instead of overlay; the two forms cannot appear together. For example, a published specialist package could accompany the regional package:

# Illustrative: jp-rsu must be published before this configuration can load.
overlays:
  - jp@2026.09.1
  - jp-rsu@2026.10.1

Every member must be available locally or fetched with iris overlay fetch. An unavailable member stops validation; the plural form never substitutes another version. Duplicate package IDs, incompatible regions or dependencies, and conflicting published rule IDs or field definitions are errors. Pin order does not determine precedence. Each package keeps its own CEL helpers; a recipe records the exact version of the package that owns it.

A package can declare region: JP and exact supported dependency versions in overlay.yaml, for example requires_overlays: {jp: [2026.09.1]}. Packages using the new selectors or parameter contract declare requires_bindings: 2. iris overlay upgrade --dry-run checks the candidate set, golden tests, book-layer compatibility and settings before showing the proposed pins. --to jp-rsu@<version> changes that member; without --to, upgrade checks the latest release of every pinned member together.

Discover field choices and workflow guides

iris overlay list --json exposes pins, rules (including when and assert), parameter schemas, field definitions and guide IDs. Local MCP provides the same information through describe_overlay; a parent-folder server also takes book. These definitions describe the versions this book actually uses.

Published packages may include an optional fields.yaml:

fields:
  line.sales.channel:               # path: target.concern.field
    type: string
    description: {en: Sales channel, ja: 販売チャネル}
    enum:
      - {value: online, label: {en: Online, ja: オンライン}}
      - {value: store, label: {en: Store, ja: 店舗}}

Here online and store are the stored values; the labels are display text. Absent fields are optional unless required: true is declared. A field may also have a CEL when condition. Present values are checked against their types and choices. Older packages without field definitions still expose their rule assertions, including any lists of accepted values; structured metadata requires a new published version or an additional book-local field definition.

A package’s guides/*.md describes its workflow. Read a discovered guide with iris overlay guide <id> [path] or local MCP read_overlay_guide (guide). The text is reference data from the pinned package; it does not grant authority to edit or submit anything.

Configure shared rules and recipes for your book

Rules are validations: they run when and then check assert. A matching rule does not create a report. Derivations propose field values; recipes compute schedules or figures. All three may declare params with a name, type, optional default and optional enum. Rule and derivation expressions read params.<name>; recipe expressions retain their named input variables.

For example, a sales rule could declare an account selector and require a memo:

rules:
  - id: sales.memo-required
    target: line
    params:
      - {name: accounts, type: account_selector, default: {exact: ['収益:Sales']}}
    when: account_matches(line.account, params.accounts)
    assert: line.memo != ''
    message: {en: A selected sales line needs a memo., ja: 対象の売上明細にはメモが必要です}

Book-specific inputs go in config/book.yaml.overlay_settings, under the package ID, then rules, derivations or recipes, then the item ID:

# Illustrative settings for a package defining these items.
overlay_settings:
  jp-sales-demo:
    rules:
      sales.memo-required:
        params:
          accounts: {contains: うりあげ}  # literal, case-sensitive substring
    derivations:
      sales.channel:
        params: {channel: store}         # must be in the declared enum
    recipes:
      monthly-sales:
        params:
          accounts: {exact: ['収益:Sales']}
          from: '2026-09-01'
          to: '2026-09-30'

An account_selector contains exactly one of exact (a non-empty list of account references), subtree (a path and its colon-separated descendants), or contains (a literal substring). It never assumes that うりあげ, 売上 and Sales are synonyms. CEL account_matches tests one reference; select_accounts(journals, selector) supplies selected lines to sums.

Quote dates and timestamps in settings, including inside maps and lists: cutoff: '2026-09-01'. Unquoted YAML dates are rejected before sync. Whole numbers inside map/list parameters use integer arithmetic locally and on the server; fractional values use doubles. A declared scalar double keeps that type.

Unknown settings, absent required rule inputs, wrong types and invalid choices are errors. Recipe invocation values override book defaults. Before a recipe runs, name selectors resolve to sorted exact references found in the journals; no match is an error. Those resolved inputs are saved in provenance. Replay uses the saved inputs even if book defaults later change, while changed journal figures still make a saved filing stale. A monthly-sales computation is a reusable example; it is not itself a statutory tax return.

Journal files — journals/YYYY-MM/*.md

YAML frontmatter, then a free-form Markdown body.

---
schema_version: 1
date: 2026-05-04
payee: EXAMPLE.COM
status: draft                 # draft | posted
tags: [sales, withholding]
attachments:
  - path: raw/2026-05-example-com-invoice.pdf
    type: invoice               # invoice | receipt | bank_statement (a causal source)
    locator: "page=1"           # optional fragment pointer ("L47", "p3")
lines:
  - account: 資産:売掛金
    debit: 89790
  - account: 資産:事業主貸
    debit: 10210
  - account: 収益:売上
    credit: 100000
---

Why this transaction happened (not a restatement of the lines).
FieldRequiredNotes
dateyesYYYY-MM-DD; must match the filename prefix, except generated 0000-opening-balances.md
payeeno (recommended)Native script OK; the filename slug derives from it
statusyesdraft / posted
tagsnoLowercase, free-form, for grouping
attachmentsno{path, type?, locator?}; a type marks a causal source
linesyes2–999; each has account + exactly one of debit/credit
lines[].memonoPer-line note
lines[].quantity + unitnoPhysical quantity for a unit from book.yaml units (always positive; direction comes from debit/credit)
lines[].taxnoJP consumption tax — see below
bodynoFree Markdown after the closing ---

Line count. A journal takes at most 999 lines, and you get a warning from 200 up. Payroll and depreciation entries legitimately run to the hundreds; four figures means something generated them by mistake. If you genuinely need more, split the entry — several journals sharing a date and a tag report identically to one long one.

Amounts are written in the currency’s natural notation, up to scale decimals. At scale: 0 (JPY) write whole yen (1000 = ¥1000, no decimals); at scale: 2 write dollars-and-cents (12.34 = $12.34, and bare 12 = $12.00, not $0.12). Internally everything is integer minor units.

Validation: debits equal credits; every account exists in the chart (or matches an alias); the date matches the filename; status is valid; YAML parses. Reports include only posted entries.

Per-line tax (JP 課税事業者 only):

tax:
  category: taxable_purchase   # taxable_sale | taxable_purchase | exempt_sale |
                               # exempt_purchase | export_sale | out_of_scope | securities_sale
  rate: "10"                   # 10 | 8r | 8o | 5 | 3 | 0
  invoice: true                # holds a qualifying invoice (purchase side)
  business_class: 5            # 簡易課税 事業区分 1..6 (overrides book default)

See Japan tax & compliance.

Defaults and inferred values

Keep shared settings in config/book.yaml. An ordinary journal records its date, status and account/amount lines; optional payee, evidence and notes add context. The following values do not need to be repeated on every line:

ValueWhat IrisBooks usesWhere you specify it
Amount currencyThe book’s currencyOnce in config/book.yaml
Amount precisionThe book’s scale; if omitted, the currency’s built-in precisionSet at book creation; it is immutable afterward
Quantity precisionAn explicit units entry, otherwise built-in precision for known currenciesDeclare custom units once in config/book.yaml; include scale: 0 for whole units
DirectionThe debit or credit keyUse exactly one on each line; quantity stays positive
Journal identityThe filenameNo journal ID field is needed

For money-only lines, omit both quantity and unit. For a commodity holding, add both to the line that moves it. For example, in a JPY book with FUND declared at scale: 0 and the two accounts in the chart, save this as journals/2026-10/2026-10-20-fund-01.md:

---
schema_version: 1
date: 2026-10-20
status: draft
lines:
  - account: Assets:Investments
    debit: 100000
    quantity: 10
    unit: FUND
  - account: Assets:Bank
    credit: 100000
---

This records ten units bought for ¥100,000. Currency, quantity direction and unit precision need no extra journal attributes. The date and status remain explicit; the draft stays out of ordinary reports until posted.

For portfolio analytics, acquisition lot identities can be derived from the purchase lines, so a simple purchase needs no lot label. FIFO is the default for disposal cost allocation: the earliest acquisitions are consumed first, independently per account and commodity. An explicit matching inventory.params.method takes precedence; otherwise analytics keeps the method in opening inventory, then falls back to FIFO. Supported methods are fifo, specific and moving-average. Specific identification requires a lot selection on each disposal. Missing acquisition history or opening basis leaves acquisition cost unknown.

Local report comparisons calculate disposal cost and adjust gain/loss without editing or posting journals. If a cost adjustment is needed, specify the gain account once in config/book.yaml:

inventory:
  params:
    gain_account: Income:Gain

The account must exist in a strict book’s chart. The method may be omitted for FIFO; set method: moving-average to change it, including in a selected view. An omitted accounts.exact selector covers commodity asset accounts; add it to restrict the scope. The optional commodity filter restricts the unit. Use iris report pl --mode comparison to inspect the calculated ledger. Comparison JSON lists selection.inventoryMethods; portfolio SQL exposes inventory_method, and Net Worth shows the method beside each commodity account. Ordinary validation and approved reports use the recorded ledger; computed comparisons stay unapproved.

To complete a sale draft, record the proceeds and quantity, and mark its cost as credit: null. With the gain account above configured and the purchase above posted, save this as journals/2026-10/2026-10-21-sale.md:

---
schema_version: 1
date: 2026-10-21
status: draft
lines:
  - account: Assets:Bank
    debit: 70000
  - account: Assets:Investments
    credit: null
    quantity: 5
    unit: FUND
---

Run iris autocomplete journals/2026-10/2026-10-21-sale.md to preview a ¥50,000 inventory credit and a ¥20,000 gain credit. Apply the preview with --apply and its --revision. The automatically included default overlay supplies inventory completion without additional journal attributes. Fees, when present, remain explicit expense postings. An ordinary money-only journal can similarly leave one balancing amount as debit: null or credit: null. Completion keeps drafts unposted; validation checks the resulting recorded amounts. See iris autocomplete.

Chart of accounts — config/chart-of-accounts.yaml

schema_version: 1
accounts:
  - path: 資産:普通預金        # hierarchical, colon-separated; this is the identity
    type: asset               # asset | liability | equity | income | expense
    code: "1010"              # optional external code
    aliases: [bank, 銀行, Assets:Bank]
  - path: 収益:売上
    type: income
    aliases: [sales]
  - path: 資産:事業主貸
    type: asset
    owner: true               # the owner's own money — left out of Net Worth
  - path: 資本:元入金
    type: equity
    retained_earnings: true   # optional — where `iris yearend` folds net income

The account’s normal side is derived from its type. aliases let journals reference an account by another name or language. Add accounts here before referencing them in a journal.

owner: true marks the owner’s personal draw and contribution accounts — for a Japanese sole proprietor, 事業主貸 and 事業主借. They keep their type (so the balance sheet lays out the way the 青色申告決算書 expects), but they hold the owner’s own money moving in and out of the business, not something the business owns or owes, so Net Worth leaves them out. The Japanese starter charts set it.

retained_earnings: true marks the equity account iris yearend folds the year’s net income into — 資本:元入金 for a sole proprietor, 純資産:繰越利益剰余金 for a company. At most one account may set it, and it must be type: equity; iris validate and the cloud refuse a chart that breaks either rule. When no account sets it, iris yearend uses the chart’s only equity account, so the starter charts (which have exactly one) leave it out. Set it once your chart has more than one equity account.

Asset files — assets/YYYY/*.md

---
schema_version: 1
name: "MacBook Pro 16"
category: equipment.computer       # free-form
acquisition_date: 2026-04-15
acquisition_cost: 480000
salvage_value: 1
useful_life_months: 48
method: straight_line              # straight_line | declining_balance | expensed
asset_account: "資産:工具器具備品"
depreciation_expense_account: "費用:減価償却費"
accumulated_depreciation_account: "資産:減価償却累計額"
acquisition_journal: "[[2026-04-15-apple-01]]"   # optional wikilink
schedule:                          # optional recorded table — see below
  - period: 2027-03                # YYYY-MM, the month the charge lands
    amount: 250000
  - period: 2028-03
    amount: 187500
schedule_source:                   # present when an overlay recipe wrote the table — see below
  overlay: jp@2026.09.1
  recipe: jp.teiritsu
  bindings: 1
  params: {cost: 480000, life: 4, rate: 0.500, guarantee: 0.12499, revised: 1.000, start: 2027-03}
disposal:                          # optional, until disposed
  date: 2029-05-10
  proceeds: 50000
  journal: "[[2029-05-10-apple-disposal-01]]"
---

JP-specific fields (用途区分, 特例, 償却資産税 flags) ride along opaquely and are read by the JP overlay.

Book the purchase of an asset described here to its asset_account — an expensed one included — and let iris asset depreciate book the charges. For an expensed asset that is one charge: the whole cost, in the acquisition month. Booking the purchase straight to an expense account as well would count it twice.

schedule: — recording the table instead of computing it

For straight-line and expensed assets you can leave schedule out: iris computes the charges from useful_life_months (an expensed asset: the whole cost in its acquisition month). For anything else — Japan’s 定率法 with its switch to 改定償却率, US MACRS with its straight-line crossover — the table is recorded on the file (method: declining_balance requires one), and iris uses it verbatim.

Each row is a period (YYYY-MM) and an amount. Annual books write one row per fiscal year, dated the fiscal year’s last month; month-by-month books write one row per month. Both work.

Your AI assistant builds the table for you. When the book’s region overlay has a recipe for the method — Japan’s 定率法 is jp.teiritsu — it runs that with the published rates as inputs and the recipe composes the table and writes it, with its provenance, onto the file (iris overlay recipe, or the matching MCP tool). For a method no recipe covers it composes the arithmetic from the calculator tools (see CLI and your AI). Once written, the table is what the books, the reports and the CSV export all use.

iris checks the table is well-formed — rows in order, no negatives, nothing before the acquisition month or past the useful life or after disposal, and the rows add up to acquisition_cost − salvage_value (on a disposed asset, no more than that — see Disposing of an asset). From the rows alone it cannot check that a switch landed in the right year — that is what schedule_source is for (next section). On a hand-composed table, keep the rates you used on the file (any extra keys ride along untouched) so your 税理士 can check them against the published table.

schedule_source: — where the table came from, replayed

When a recipe wrote the table, it also recorded its provenance: the overlay version (jp@2026.09.1, or book:<hash> for a recipe from your own config/overlays/), the recipe, the engine versions it ran under, and the inputs you gave — the rates from the published table, the useful life, the first row’s month. iris validate replays the recipe with those inputs and refuses the file if the recorded rows differ, so a switch a year late no longer passes just because the total is right. The inputs stay on the file for your 税理士 to check against the published table. A table without schedule_source is checked for shape only. Replay uses the exact recorded version from the versions built into your iris or its verified download cache, even when it differs from the book’s current pin. If that version is unavailable, the book-layer hash differs, or the required engine capability is unavailable, validation warns and checks the shape only.

Disposing of an asset

Add the disposal: block with the date and the proceeds. Depreciation runs up to and including the disposal month at the same monthly charge as before — disposal ends the schedule, it does not speed it up. What is left of the cost at that point is the book value at disposal. iris asset schedule shows it as DISPOSAL_NBV and iris export assets as disposal_nbv, next to accumulated, the depreciation actually taken. The disposal journal removes the asset’s cost and that accumulated depreciation, records the proceeds, and books the difference between the proceeds and the book value at disposal as a gain or a loss.

A computed straight-line schedule stops at the disposal month by itself. A recorded table is never rewritten for you: delete the rows after the disposal month, and set the disposal-period row to the charge for the part of that year the asset was held (in Japan, 月割). The table may then add up to less than acquisition_cost − salvage_value, never more. If a recipe wrote the table, iris validate still replays the rows before the disposal month; the disposal-period row is yours.

Japan’s 一括償却資産 (toku_rei: ikkatsu_3yr) is the exception: the one-third-a-year deduction continues after the item is gone. Leave disposal: off those items and note the disposal in the file body instead — with disposal: set, iris would stop the schedule at the disposal month.

Filings — filings/<recipe>.md

The figures a return is filed from, as a recorded file. A figures recipe of the region overlay (for Japan, jp.shouhizei-general and jp.shouhizei-simplified for the 消費税 return) sums the posted journals and combines them the way the return needs; iris overlay recipe … --write filings/jp.shouhizei-general.md records the result with the same provenance as a schedule:

---
schema_version: 1
filing: jp.shouhizei-general
period: {from: 2026-01-01, to: 2026-12-31}
source:
  overlay: jp@2026.09.1
  recipe: jp.shouhizei-general
  bindings: 1
  params: {from: 2026-01-01, to: 2026-12-31, non_invoice_pct: 80}
figures:
  sales_10: 11000000
  sales_tax_10: 1000000
  deductible_tax: 620000
  net_tax: 380000
  payable: 380000
  # …
---
(a readable table of the same figures)

iris validate re-runs the recipe over the journals and refuses a filing whose figures no longer follow from them — so a correction posted after you filed shows up as an error until you re-run the recipe (or revert the correction). Your AI fills the government form from figures; it never re-adds lines by hand. Filings sync and are sealed with the book, unlike compiled/.

Your book’s overlay layer — config/overlays/ (optional)

The region overlay — the rules, recipes and derivations your book’s region comes with — is published with iris and pinned by overlay: or overlays: in book.yaml. A book may add its own layer on top:

config/overlays/
├── overlay.yaml        # id: book / extends: jp@2026.09.1
├── fields.yaml         # optional field types and choices
├── functions.yaml      # optional shared expressions
├── rules/*.yaml        # extra checks (an id matching a published rule overrides it)
├── recipes/*.yaml      # extra computations
├── derive/*.yaml       # extra derived-value proposals
└── tests/*.yaml        # golden cases — `iris overlay test` runs them

With multiple published pins, the layer’s extends is a list containing all of them. Local expressions inherit the regional primary package’s CEL helpers; other published packages keep their helpers private. An override of an existing rule, derivation or recipe keeps that item’s package ID for overlay_settings. New book-local items use the reserved book settings key, independent of the published pins and the local manifest’s ID:

overlay_settings:
  book:
    rules:
      local.memo:
        params: {memo: invoice}  # a new rule declared in config/overlays/rules/

Use the declared item ID for rules/derivations and the short recipe name for new local recipe defaults. Published field definitions cannot be replaced by the book layer. When adding a required rule input, sync its book-local definition first, then its settings. During a pin upgrade, the server can accept the new config even if the stored layer cannot compile on it; published settings must still be valid. Repair the definitions against the new pins, then sync the matching extends manifest. If several files need repair, each incoming definition must compile with the published and local helpers; file limits still apply while other definitions await repair. Record writes wait until the actual layer and all settings are valid.

Rules and recipes are written in CEL expressions over the book’s records — a language with no file or network access and a bounded cost, which is what makes it safe for your AI to write them. iris validate applies your layer next to the published one, and the cloud applies it to every member’s writes; only the book’s Owner can change these files. The first time a machine meets a version of this layer it shows the files and asks once (iris overlay trust records the answer); until then only the published overlay applies. iris overlay list and published MCP recipe tools remain available; the CLI and MCP describe_overlay.issues report overlay.book-layer-untrusted. Book-local settings are checked when the layer is trusted. A recipe from your layer records book:<hash> as its source, so a reviewer can see a schedule came from a book-specific recipe. The published overlays are open source (Apache-2.0) in the public irisbooks/overlays repository. A layer that proves useful beyond one book can be proposed there as a pull request.

config/rules.yaml (optional)

Human-curated hints your AI may use when categorizing; never enforced.

schema_version: 1
categorization:
  - when:
      payee_matches: "Amazon"
      amount_max: 50000
    propose:
      account: "費用:消耗品費"
      confidence: 0.85

Parse caches — notes/raw/<source>.md

When your AI parses a document under raw/, it writes a durable, normalized view here, mirroring the source path. Each row carries a status (journaled / ignored / deferred) so re-opening the same statement doesn’t redo the work.

---
source: raw/2026-04-sbi.csv
source_sha: <iris hash>
parsed_at: 2026-05-11
counts: { total: 47, journaled: 42, ignored: 3, deferred: 2 }
---

## Rows
| id | date       | description | amount | status    | target / reason                          |
|----|------------|-------------|--------|-----------|------------------------------------------|
| 1  | 2026-04-01 | Amazon JP   |  -5000 | journaled | journals/2026-04/2026-04-01-amazon-01.md |

What syncs and what doesn’t

With cloud sync, iris sync mirrors the syncable files to the cloud:

  • Synced: journals/, assets/, filings/, notes/ (including parse caches), raw/ (verbatim bytes), config/book.yaml, config/chart-of-accounts.yaml, config/rules.yaml, config/overlays/.
  • Not synced: .iris/ (runtime state), README.md / LLM-GUIDE.md / CLAUDE.md (guides), and compiled/ (regeneratable).

See also: Core concepts · CLI command reference.

Independent annual books and acquisition openings

iris yearend writes complete opening inventory in the next book’s config/book.yaml. Each book can be valued independently, without a link to an earlier book. Select earlier books only to include their own historical periods.

opening_inventory:
  - account: Assets:Fund
    unit: FUND
    method: fifo
    quantity: 100
    carrying_value_minor: 1200000
    acquisition_cost_minor: 1000000
    lots:
      - id: original-purchase
        date: 2025-11-01
        quantity: 100
        cost_minor: 1000000

Quantities are integers at the unit’s scale; money is integer book-currency minor units. Carrying value and acquisition cost are separate. Carrying value also disambiguates a native-currency cash residual from a unit holding in the same account. FIFO/specific openings retain original lots and their dates; moving-average openings use a quantity/cost pool without lots. A null acquisition cost means unknown. The opening journal still states the monetary/quantity balance and must reconcile with these fields within this book. Do not infer acquisition cost from a revalued opening amount.

Explicit lot IDs are preserved. When a purchase omits its lot ID, analytics derives one from the fiscal year, journal path and original line index within this book’s inventory. Changing the book’s cloud ID does not change that lot ID.