# GridTRX — Agent Instructions
# Role: You are a bookkeeper operating a full-cycle double-entry accounting system.
# GridTRX is built for AI agents first, human accountants second.
# Every operation is deterministic. All data is local — no cloud, no APIs.

## Core Rules
- Every transaction is a balanced zero-sum entry. Debits = Credits. Always.
- Positive = Debit. Negative (parentheses) = Credit. Zero = em dash.
- If a category is unknown, post to EX.SUSP (Suspense). Review later.
- Amounts are stored as integers (cents). Display as dollars with two decimals.
- Account names are case-insensitive. Use UPPER by convention.

## Architecture
- Database: Single SQLite file (books.db) per client. Copy it, back it up, email it.
- Logic: models.py is the single source of truth. All three interfaces call it.
- Three interfaces, one engine:
  1. MCP Server (preferred) — Structured JSON tools, typed parameters, deterministic output.
  2. CLI (fallback) — One-shot shell commands. Zero dependencies beyond Python 3.7+.
  3. Browser UI (for humans) — Flask at localhost:5000 via run.py. Same database, same data.

## CLI Usage (One-Shot Mode)
python cli.py <path/to/books.db> <command>

Runs a command, prints output to stdout, exits. Chain with && for multi-step.

## Essential Commands

### Read Operations
tb                                  # Trial balance (all accounts, Dr/Cr columns)
tb 2025-12-31                       # Trial balance as of a date
report BS                           # Balance sheet
report IS 2025-01-01 2025-12-31     # Income statement for a period
ledger BANK.CHQ                     # Full ledger for an account
ledger BANK.CHQ 2025-01-01 2025-03-31  # Ledger with date range
balance BANK.CHQ                    # Single account balance
accounts                            # List all accounts
accounts posting                    # List only posting accounts
find bank                           # Search accounts by name
search rent                         # Search transactions by description
rules                               # List all import rules
info                                # Company name, fiscal year, lock date
trace RE                            # Trace accumulation tree for a total
trace RE 2025-12-31                 # Trace as of a date
trace NETEARN 2025-01-01 2025-12-31 # Trace for a date range

### Write Operations
post 2025-03-01 "March rent" 1500.00 EX.RENT BANK.CHQ
    # Simple 2-line entry: Dr EX.RENT 1500, Cr BANK.CHQ 1500

postx 2025-03-01 "Compound entry"
    # Multi-line transaction. Enter lines interactively.

importcsv ~/data/jan2025.csv BANK.CHQ
    # Import bank CSV. Applies import rules to auto-categorize.
    # Unmatched rows go to EX.SUSP.

importofx ~/data/jan2025.qbo BANK.CHQ
    # Import bank OFX/QBO file. Same rules as importcsv.

importaje ~/data/aje_export.iif 25AJE
    # Import CaseWare AJE export (IIF or Venice format).
    # Parses entries, maps CsW accounts to Grid accounts, posts all.

addrule SHOPIFY REV.SVC G5 10
    # Add import rule: keyword SHOPIFY -> account REV.SVC, GST 5%, priority 10

delrule 42
    # Delete import rule by ID

addaccount EX.PARKING D "Parking Expense"
    # Add new posting account. D=debit-normal, C=credit-normal.

rollforward 2025-08-31
    # Roll fiscal year forward. Posts RE offset, sets lock, advances ceiling.
    # Reads RE.CLOSE (not RE from BS) to avoid double-counting.

ye 2025-08-31
    # Alias for rollforward.

ceiling 2025-12-31
    # Show or set the fiscal year ceiling. Prevents posting after this date.

lock 2025-08-31
    # Set lock date. Prevents changes on or before this date.

### Export
exporttb trial_balance.csv 2025-12-31   # TB to CSV
exportcsv IS income.csv 2025-01-01 2025-12-31  # Report to CSV

## Standard Workflow
1. Create books:        new ~/clients/acme "Acme Corp"
   (Ceiling auto-set to current fiscal year end)
2. Import bank data:    importcsv ~/data/bank.csv BANK.CHQ
   Or OFX/QBO:          importofx ~/data/bank.qbo BANK.CHQ
   (Rows after ceiling are skipped — rollforward first if needed)
3. Review suspense:     ledger EX.SUSP
4. Add rules:           addrule <keyword> <account> [tax] [priority]
5. Delete suspense:     delete <txn_id>  (for each misposted entry)
6. Re-import:           importcsv ~/data/bank.csv BANK.CHQ
7. Verify:              tb  (debits must equal credits)
8. Run reports:         report BS && report IS
9. Year-end:            rollforward 2025-12-31
   (Posts RE offset, locks year, advances ceiling to next FY)
10. Repeat from step 2 for next fiscal year

## Output Conventions
- Success: lines contain a checkmark character
- Errors: lines start with "Error:" or "Cannot"
- Tables: header row, separator line, fixed-width columns
- Amounts: 1,500.00 = debit, (1,500.00) = credit, — = zero
- All output is plain text. Parse with string splitting.

## Account Naming Convention
- BANK.xxx   Bank accounts (D-normal)
- AR.xxx     Accounts receivable (D-normal)
- AP.xxx     Accounts payable (C-normal)
- REV.xxx    Revenue (C-normal)
- EX.xxx     Expenses (D-normal)
- GST.xxx    Tax accounts
- RE.xxx     Retained earnings (C-normal)
- EX.SUSP    Suspense — uncategorized transactions land here

## Tax Codes
- G5   GST 5%
- H13  HST 13%
- H15  HST 15%
- E    Exempt (no tax split)

## CRITICAL: Perpetual Retained Earnings System
GridTRX uses perpetual totals — there is NO traditional year-end
close that zeros revenue/expense accounts. Instead, the total-to chain computes
net income dynamically and flows it to the BS. This chain MUST be intact.

### Required Total-To Chain (IS → BS)
Revenue accounts → TOTREV → GROSS → OPINC → NETINC → NI → RE.CLOSE → RE (on BS)
Expense accounts → TOTEX → OPINC (same chain continues to RE)
COS accounts    → GROSS (same chain)

The chain is GLOBAL across all reports. An IS total can feed a BS total.

### Required Accounts for RE System
- **NI** (C, total) — Net Income accumulator. All IS totals must reach this.
- **RE.CLOSE** (C, total) — Closing retained earnings. Receives NI + RE.OPEN + DIVPAID.
- **RE** (C, total) — Retained earnings on BS. Receives RE.CLOSE + RE.OFS.
- **RE.OPEN** (C, posting) — Opening retained earnings. Credited by rollforward command.
- **RE.OFS** (D, posting) — Offset account. Debited by rollforward command. Cancels RE.OPEN in RE.
- **PY.CLOSE** (C, posting) — Prior year closing balance. Used when importing only a PY balance sheet
  (no income history). Post all PY TB amounts against PY.CLOSE. total_to_1 = RE, so the
  unreconciled difference flows to retained earnings correctly. Lives on the TRX report.

### Fiscal Year Ceiling
Books have a posting window: (lock_date, fy_end_date]. The ceiling prevents
accidentally posting into future fiscal years. Set automatically when books
are created. Advanced automatically by rollforward. Can be set manually: ceiling YYYY-MM-DD

### Year-End Process (rollforward command)
Reads RE.CLOSE from the IS report (not RE from BS — avoids double-counting).
Posts ONE entry dated first day of new fiscal year:
  Dr RE.OFS / Cr RE.OPEN (for the RE.CLOSE amount)
This "freezes" prior-year earnings into RE.OPEN. The debit in RE.OFS cancels
RE.OPEN within the RE total, so only current-year NI shows in RE on the BS.
Also sets lock_date = YE date, advances fy_end_date to next year.
`ye` is an alias for `rollforward`.

### RE.OFS Report
A separate report (sort order 50) that makes RE.OFS visible and wires it to RE:
  RE.OPEN  (display only, no total-to)
  RE.OFS   (total_to_1 = 'RE')

### Always Start from Starter Books
When creating new books, ALWAYS use create_starter_books() as the base. This
ensures the RE chain, all 5 standard reports (BS, IS, AJE, TRX, RE.OFS), and
the required total accounts are created correctly. Then add/modify accounts
for the specific client. Never build reports from scratch without the RE chain.

### Importing Client Data
When importing a client's existing chart of accounts, preserve the client's
original account layout and structure. Their previous accountant organized
accounts logically — don't reorganize. Map client accounts to GridTRX naming
(BANK.xxx, AR.xxx, etc.) but keep the grouping and ordering intact.

### Validate
Run `validate` after any report setup to check the chain is intact:
  python cli.py books.db validate

Validate checks: total-to chain, RE.OFS/RE.OPEN exist, BS balances,
**BS RE vs IS RE.CLOSE match** (catches duplicates, chain errors, conversion artifacts),
and orphan total-to targets.

### Trace
Trace the accumulation tree for any account to see what feeds into it:
  python cli.py books.db trace RE
  python cli.py books.db trace NETEARN 2024-06-01 2025-05-31

Shows each contributor's own balance, received accumulation, and dumped value.

## Important Notes
- Lock date prevents posting to closed periods (floor). Check with: lock
- FY ceiling prevents posting beyond the fiscal year end (ceiling). Check with: ceiling
- Posting window is (lock_date, fy_end_date]. Work in batches per fiscal year.
- Rollforward is one-way: it posts a closing entry, locks the year, advances the ceiling.
- The trial balance MUST always balance. If it doesn't, something is wrong.
- Import rules are matched by keyword (case-insensitive), highest priority wins.
- Total report items MUST have an account_id linked or they will always show zero.

## Workspace Security
Set GRIDTRX_WORKSPACE to restrict file access to a single directory.
Both the MCP server and CLI enforce this boundary — paths outside the workspace are rejected.
  export GRIDTRX_WORKSPACE=~/clients

## MCP Server (Structured AI Agent Access)
pip install mcp
GRIDTRX_WORKSPACE=~/clients python mcp_server.py

The MCP server exposes 19 typed tools (12 read, 7 write) that wrap models.py directly.
No shell parsing needed — agents get structured JSON responses.
GRIDTRX_WORKSPACE is mandatory — the server will not start without it.

Add to Claude Desktop config (claude_desktop_config.json):
  "gridtrx": {"command": "python", "args": ["/path/to/mcp_server.py"], "env": {"GRIDTRX_WORKSPACE": "/path/to/clients"}}

Every tool takes db_path as its first parameter (must resolve inside the workspace).
