clawbooks 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +157 -0
- package/build/cli.js +881 -0
- package/build/ledger.js +60 -0
- package/package.json +49 -0
- package/policy-complex.md.example +149 -0
- package/policy-simple.md.example +48 -0
- package/policy.md.example +80 -0
- package/program.md +186 -0
package/build/ledger.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFileSync, appendFileSync, existsSync, writeFileSync } from "node:fs";
|
|
3
|
+
export function computeId(data, meta) {
|
|
4
|
+
const sortedData = JSON.stringify(data, Object.keys(data).sort());
|
|
5
|
+
const envelope = { data: sortedData, source: meta.source, ts: meta.ts, type: meta.type };
|
|
6
|
+
const canonical = JSON.stringify(envelope);
|
|
7
|
+
return createHash("sha256").update(canonical).digest("hex").slice(0, 16);
|
|
8
|
+
}
|
|
9
|
+
export function readAll(path) {
|
|
10
|
+
if (!existsSync(path))
|
|
11
|
+
return [];
|
|
12
|
+
return readFileSync(path, "utf-8")
|
|
13
|
+
.split("\n")
|
|
14
|
+
.filter(Boolean)
|
|
15
|
+
.map((l) => JSON.parse(l));
|
|
16
|
+
}
|
|
17
|
+
export function filter(events, opts) {
|
|
18
|
+
let out = events;
|
|
19
|
+
if (opts?.after)
|
|
20
|
+
out = out.filter((e) => e.ts >= opts.after);
|
|
21
|
+
if (opts?.before)
|
|
22
|
+
out = out.filter((e) => e.ts <= opts.before);
|
|
23
|
+
if (opts?.source)
|
|
24
|
+
out = out.filter((e) => e.source === opts.source);
|
|
25
|
+
if (opts?.type)
|
|
26
|
+
out = out.filter((e) => e.type === opts.type);
|
|
27
|
+
if (opts?.last)
|
|
28
|
+
out = out.slice(-opts.last);
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
export function hashLine(line) {
|
|
32
|
+
return createHash("sha256").update(line).digest("hex").slice(0, 16);
|
|
33
|
+
}
|
|
34
|
+
const CURRENCY_EXEMPT_TYPES = new Set(["snapshot", "reclassify", "opening_balance"]);
|
|
35
|
+
export function append(path, event) {
|
|
36
|
+
if (!CURRENCY_EXEMPT_TYPES.has(event.type) && event.data.currency === undefined) {
|
|
37
|
+
throw new Error(`Event missing data.currency (type: ${event.type}, id: ${event.id})`);
|
|
38
|
+
}
|
|
39
|
+
if (!existsSync(path))
|
|
40
|
+
writeFileSync(path, "", "utf-8");
|
|
41
|
+
const existing = readAll(path);
|
|
42
|
+
if (existing.some((e) => e.id === event.id))
|
|
43
|
+
return false;
|
|
44
|
+
// Compute prev hash from last line in file
|
|
45
|
+
if (existing.length === 0) {
|
|
46
|
+
event.prev = "genesis";
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const lines = readFileSync(path, "utf-8").split("\n").filter(Boolean);
|
|
50
|
+
event.prev = hashLine(lines[lines.length - 1]);
|
|
51
|
+
}
|
|
52
|
+
appendFileSync(path, JSON.stringify(event) + "\n", "utf-8");
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
export function latestSnapshot(events, before) {
|
|
56
|
+
let snapshots = events.filter((e) => e.type === "snapshot");
|
|
57
|
+
if (before)
|
|
58
|
+
snapshots = snapshots.filter((e) => e.ts <= before);
|
|
59
|
+
return snapshots.at(-1) ?? null;
|
|
60
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clawbooks",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Accounting by inference, not by engine. Zero dependencies.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/rev1ck/clawbooks.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/rev1ck/clawbooks#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/rev1ck/clawbooks/issues"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"accounting",
|
|
16
|
+
"ledger",
|
|
17
|
+
"cli",
|
|
18
|
+
"bookkeeping",
|
|
19
|
+
"finance",
|
|
20
|
+
"llm"
|
|
21
|
+
],
|
|
22
|
+
"bin": {
|
|
23
|
+
"clawbooks": "./build/cli.js"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc && chmod 755 build/cli.js",
|
|
27
|
+
"prepare": "npm run build",
|
|
28
|
+
"prepack": "npm run build"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"build",
|
|
32
|
+
"program.md",
|
|
33
|
+
"policy.md.example",
|
|
34
|
+
"policy-simple.md.example",
|
|
35
|
+
"policy-complex.md.example"
|
|
36
|
+
],
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=20"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^22.0.0",
|
|
46
|
+
"typescript": "^5.8.0"
|
|
47
|
+
},
|
|
48
|
+
"license": "MIT"
|
|
49
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Accounting policy
|
|
2
|
+
|
|
3
|
+
## Entity
|
|
4
|
+
|
|
5
|
+
Solo quantitative trader operating across centralized exchanges, DeFi protocols, and prediction markets. US tax resident. Not registered as a company — individual trader.
|
|
6
|
+
|
|
7
|
+
Base currency: USD for all P&L tracking.
|
|
8
|
+
Fiscal year: January 1 to December 31.
|
|
9
|
+
|
|
10
|
+
## Jurisdiction notes
|
|
11
|
+
|
|
12
|
+
The IRS treats crypto as property (Notice 2014-21, Rev. Rul. 2019-24). For a frequent trader:
|
|
13
|
+
- Short-term gains (held < 1 year) are taxed as ordinary income
|
|
14
|
+
- Long-term gains (held > 1 year) are taxed at capital gains rates (0%, 15%, or 20%)
|
|
15
|
+
|
|
16
|
+
This operation is frequent trading. **All crypto gains and losses are short-term unless a specific lot has been held over 1 year.**
|
|
17
|
+
|
|
18
|
+
## Cost basis
|
|
19
|
+
|
|
20
|
+
FIFO (First In, First Out) for all assets across all venues.
|
|
21
|
+
|
|
22
|
+
Track cost basis per asset in USD.
|
|
23
|
+
|
|
24
|
+
Lot tracking: each acquisition event creates a lot. Each disposal event consumes lots in FIFO order. The LLM must maintain a running lot schedule when generating reports.
|
|
25
|
+
|
|
26
|
+
## Source: Hyperliquid
|
|
27
|
+
|
|
28
|
+
Hyperliquid is a perpetual futures DEX. Events from this source include:
|
|
29
|
+
|
|
30
|
+
- **Trades** (type: `trade`): opening or closing perpetual positions. The `side` field indicates buy/sell. These are leveraged positions, not spot purchases. Track the notional value and the margin used.
|
|
31
|
+
- **Funding payments** (type: `funding`): periodic funding rate payments. If rate is positive and you're long, you pay. If rate is positive and you're short, you receive. Classify as **interest expense** (paid) or **interest income** (received).
|
|
32
|
+
- **Liquidations** (type: `liquidation`): forced closure of a position. Classify the loss as a **realized trading loss**. Flag for review — liquidations indicate risk management failure.
|
|
33
|
+
- **Deposits/Withdrawals** (type: `transfer`): movement of USDC to/from the Hyperliquid bridge contract on Arbitrum. These are not income or expense — they are transfers between own accounts. Match the on-chain transfer with the Hyperliquid balance change.
|
|
34
|
+
|
|
35
|
+
### Hyperliquid P&L
|
|
36
|
+
|
|
37
|
+
Realized P&L on each trade = (exit price - entry price) x quantity x direction.
|
|
38
|
+
Include all fees (taker/maker) as a deduction from the P&L, not as a separate expense line.
|
|
39
|
+
Unrealized P&L on open positions should be reported separately and NOT included in taxable income until the position is closed.
|
|
40
|
+
|
|
41
|
+
## Source: Polymarket
|
|
42
|
+
|
|
43
|
+
Polymarket is a binary prediction market on Polygon. Events include:
|
|
44
|
+
|
|
45
|
+
- **Position entry** (type: `trade`): buying YES or NO shares on a market. Cost basis = price paid per share x quantity. These are **speculative derivative contracts**, not purchases of an underlying asset.
|
|
46
|
+
- **Settlement** (type: `settlement`): market resolves. If the position wins, payout = number of shares x $1.00. If it loses, payout = $0. Realize the gain or loss as: payout - cost basis.
|
|
47
|
+
- **Redemption** (type: `trade`, side: `sell`): selling a position before settlement. Realize gain/loss as: sale proceeds - cost basis (FIFO).
|
|
48
|
+
|
|
49
|
+
### Polymarket classification
|
|
50
|
+
|
|
51
|
+
Classify all Polymarket activity as **speculative derivative income/loss**. This is distinct from the trading income on Hyperliquid — keep them as separate line items in reports.
|
|
52
|
+
|
|
53
|
+
## Source: Ethereum / Arbitrum / Polygon (on-chain)
|
|
54
|
+
|
|
55
|
+
Chain watchers emit transfer events. Classification rules:
|
|
56
|
+
|
|
57
|
+
- **Transfers between own wallets**: not income/expense. Internal transfer. Match by amount and token across the two addresses. Maintain a list of own addresses (see Known Addresses below).
|
|
58
|
+
- **Bridge transactions**: transfers to/from bridge contracts. These are internal transfers that may take time to complete. Match the source chain debit with the destination chain credit. If the amounts don't match after 1 hour, flag as a potential bridge failure.
|
|
59
|
+
- **Gas fees**: classify as **operating expense: gas**. Always denominated in the chain's native token (ETH, MATIC). Convert to USD at the block timestamp.
|
|
60
|
+
- **Token approvals**: zero economic impact, but record the gas fee.
|
|
61
|
+
- **Failed transactions**: the transaction reverted but gas was still consumed. Classify the gas as **operating expense: failed transaction gas**. This is deductible.
|
|
62
|
+
- **Unknown contract interactions**: flag for manual review. Do not auto-classify interactions with unrecognized contracts.
|
|
63
|
+
|
|
64
|
+
## Source: Agent (autonomous agents, bots, etc.)
|
|
65
|
+
|
|
66
|
+
Agent-generated events are annotations, not primary financial events. They provide context for the LLM but do not create new economic activity.
|
|
67
|
+
|
|
68
|
+
- **Notes** (type: `note`): agent's commentary on a trade, strategy, or observation. Use these for context when generating reports but do not create journal entries from them.
|
|
69
|
+
- **Signals** (type: `signal`): agent's trading signals. These are informational only — the actual trade event from the exchange is the authoritative record.
|
|
70
|
+
|
|
71
|
+
Exception: if an agent records a type: `adjustment`, treat it as a legitimate correction (same as a human adjustment). The adjustment must include a `reason` field.
|
|
72
|
+
|
|
73
|
+
## Reconciliation rules
|
|
74
|
+
|
|
75
|
+
### Trade booking vs on-chain settlement
|
|
76
|
+
|
|
77
|
+
When a trade is executed on Hyperliquid/Polymarket, the exchange event and the on-chain settlement may not match exactly. Rules:
|
|
78
|
+
|
|
79
|
+
| Delta | Classification | Action |
|
|
80
|
+
|-------|---------------|--------|
|
|
81
|
+
| < 0.1% | Slippage | Auto-classify, no flag |
|
|
82
|
+
| 0.1% - 1.0% | Fee variance | Log as operating expense: execution variance |
|
|
83
|
+
| > 1.0% | Discrepancy | Flag for manual review, do not auto-classify |
|
|
84
|
+
|
|
85
|
+
### Cross-source matching
|
|
86
|
+
|
|
87
|
+
When the same economic event appears from multiple sources (e.g., a Hyperliquid trade appears both in the exchange feed and in the Arbitrum chain watcher), deduplicate:
|
|
88
|
+
|
|
89
|
+
1. Check `id` (content hash) — if identical, skip the duplicate
|
|
90
|
+
2. If hashes differ (different raw payloads), match by: timestamp (+/-30 seconds) + amount (+/-0.5%) + token
|
|
91
|
+
3. If matched, keep the exchange source as primary (more detailed), link the on-chain source as confirmation
|
|
92
|
+
4. If not matched, flag both events for review
|
|
93
|
+
|
|
94
|
+
## Known addresses
|
|
95
|
+
|
|
96
|
+
These are all my addresses. Transfers between them are internal.
|
|
97
|
+
|
|
98
|
+
- `0x_eth_main` — Ethereum mainnet primary
|
|
99
|
+
- `0x_arb` — Arbitrum primary
|
|
100
|
+
- `0x_polygon` — Polygon primary
|
|
101
|
+
- `0x_hl_deposit` — Hyperliquid deposit address
|
|
102
|
+
|
|
103
|
+
(Replace with actual addresses)
|
|
104
|
+
|
|
105
|
+
## Reporting
|
|
106
|
+
|
|
107
|
+
### Monthly
|
|
108
|
+
- P&L by source (Hyperliquid, Polymarket, other)
|
|
109
|
+
- Realized vs unrealized breakdown
|
|
110
|
+
- Funding income/expense
|
|
111
|
+
- Gas costs
|
|
112
|
+
- Open positions with unrealized P&L
|
|
113
|
+
- Cash/stablecoin balances across all venues
|
|
114
|
+
|
|
115
|
+
### Quarterly
|
|
116
|
+
- Tax estimate (quarterly estimated payments due: April 15, June 15, September 15, January 15)
|
|
117
|
+
- Strategy performance: arb P&L (HL long + PM short combined)
|
|
118
|
+
- Win rate by market type
|
|
119
|
+
- Risk metrics: max drawdown, largest single loss
|
|
120
|
+
- Reconciliation status: any unresolved discrepancies
|
|
121
|
+
|
|
122
|
+
### Annual (tax filing)
|
|
123
|
+
- Total income from trading (all sources)
|
|
124
|
+
- Total deductible expenses (gas, fees, execution variance, home office if applicable)
|
|
125
|
+
- Net taxable income
|
|
126
|
+
- Supporting schedule: every realized gain/loss with dates, amounts, cost basis
|
|
127
|
+
- Schedule D / Form 8949 preparation notes
|
|
128
|
+
|
|
129
|
+
## Special rules
|
|
130
|
+
|
|
131
|
+
### The arb strategy
|
|
132
|
+
|
|
133
|
+
The primary strategy is microstructure arbitrage between Hyperliquid and Polymarket on short-term BTC price windows. This means:
|
|
134
|
+
|
|
135
|
+
- A Hyperliquid long/short AND a Polymarket YES/NO position are opened together as a single economic unit
|
|
136
|
+
- When reporting arb P&L, combine the HL leg and PM leg into a single arb trade with net P&L
|
|
137
|
+
- For tax purposes, each leg is still reported individually (IRS doesn't recognize synthetic positions)
|
|
138
|
+
- For management accounting, report both: individual leg P&L AND combined arb P&L
|
|
139
|
+
|
|
140
|
+
### Stablecoin treatment
|
|
141
|
+
|
|
142
|
+
USDC, USDT, and DAI are treated as cash equivalents. Do not track cost basis on stablecoins — treat them as USD at 1:1. If a stablecoin depegs more than 2%, flag and begin tracking cost basis from that point.
|
|
143
|
+
|
|
144
|
+
### Airdrops and rewards
|
|
145
|
+
|
|
146
|
+
Any tokens received as airdrops, staking rewards, or protocol incentives:
|
|
147
|
+
- Recognize as income at fair market value at time of receipt
|
|
148
|
+
- Cost basis = fair market value at receipt
|
|
149
|
+
- If no reliable price feed exists, flag for manual valuation
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Accounting policy
|
|
2
|
+
|
|
3
|
+
## Entity
|
|
4
|
+
|
|
5
|
+
Small web design studio. US-based, single member LLC.
|
|
6
|
+
Cash basis accounting. Fiscal year: January to December.
|
|
7
|
+
Base currency: USD.
|
|
8
|
+
|
|
9
|
+
## Revenue recognition
|
|
10
|
+
|
|
11
|
+
Income is recognized when payment is received, not when invoiced.
|
|
12
|
+
All client payments are service revenue.
|
|
13
|
+
Crypto payments are converted to USD at the spot price at time of receipt and recognized as service revenue at that USD amount. The crypto itself is not held as an investment — convert or record the USD equivalent immediately.
|
|
14
|
+
|
|
15
|
+
## Expense classification
|
|
16
|
+
|
|
17
|
+
- **Software subscriptions** (Figma, hosting, domains): operating expenses
|
|
18
|
+
- **Contractor payments**: cost of goods sold
|
|
19
|
+
- **Hardware** (laptops, monitors): capitalize if over $2,500, otherwise operating expense. Depreciate capitalized assets over 3 years straight-line.
|
|
20
|
+
- **Home office**: allocate 15% of rent and utilities as business expense
|
|
21
|
+
- **Meals with clients**: 50% deductible business expense
|
|
22
|
+
- **Conference travel**: fully deductible if business purpose documented
|
|
23
|
+
|
|
24
|
+
## Tax
|
|
25
|
+
|
|
26
|
+
Quarterly estimated tax payments due: April 15, June 15, September 15, January 15.
|
|
27
|
+
Self-employment tax rate: 15.3% on net earnings.
|
|
28
|
+
Set aside 30% of net income for combined federal + state + SE tax.
|
|
29
|
+
State: California.
|
|
30
|
+
|
|
31
|
+
## Bank accounts
|
|
32
|
+
|
|
33
|
+
- Chase Business Checking: primary operating account
|
|
34
|
+
- Mercury: secondary / savings
|
|
35
|
+
- Stripe: payment processing (settlement to Chase, 2-day rolling)
|
|
36
|
+
|
|
37
|
+
When Stripe settles to Chase, do not double-count. The Stripe payout and the Chase deposit are the same money. Match them by amount and date (±2 days).
|
|
38
|
+
|
|
39
|
+
## Invoicing
|
|
40
|
+
|
|
41
|
+
Net 30 terms. Invoices over 45 days past due should be flagged.
|
|
42
|
+
Deposits (typically 50% upfront) are recognized as revenue when received, not deferred.
|
|
43
|
+
|
|
44
|
+
## Reports
|
|
45
|
+
|
|
46
|
+
- Monthly: P&L summary, outstanding invoices, cash position
|
|
47
|
+
- Quarterly: tax estimate, P&L by client, expense breakdown by category
|
|
48
|
+
- Annual: full P&L, balance sheet, Schedule C preparation
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Accounting policy
|
|
2
|
+
|
|
3
|
+
## Entity
|
|
4
|
+
|
|
5
|
+
Describe your business here.
|
|
6
|
+
|
|
7
|
+
## Currencies
|
|
8
|
+
|
|
9
|
+
Base currency: USD.
|
|
10
|
+
The CLI aggregates per-currency; the agent handles cross-currency reporting and conversions when needed.
|
|
11
|
+
|
|
12
|
+
## Revenue recognition
|
|
13
|
+
|
|
14
|
+
Cash basis. Income is recognized when payment is received.
|
|
15
|
+
|
|
16
|
+
## Expense classification
|
|
17
|
+
|
|
18
|
+
### Operating expenses (OpEx)
|
|
19
|
+
- **Software subscriptions** (Figma, hosting, domains, SaaS tools)
|
|
20
|
+
- **Home office**: allocate 15% of rent and utilities as business expense
|
|
21
|
+
- **Meals with clients**: 50% deductible business expense
|
|
22
|
+
- **Conference travel**: fully deductible if business purpose documented
|
|
23
|
+
- **Office supplies**: consumables, stationery, minor accessories
|
|
24
|
+
- **Professional services**: legal, accounting, consulting
|
|
25
|
+
- **Insurance**: business-related insurance premiums
|
|
26
|
+
- **Bank fees**: monthly fees, transaction charges, card fees
|
|
27
|
+
|
|
28
|
+
### Cost of goods sold (COGS)
|
|
29
|
+
- **Contractor payments**: direct labor for client deliverables
|
|
30
|
+
- **Platform fees**: marketplace commissions, payment processing fees tied to revenue
|
|
31
|
+
|
|
32
|
+
### Capital expenditure (CapEx)
|
|
33
|
+
See capitalization policy below. Hardware, equipment, and other tangible assets above the threshold are capitalized, not expensed.
|
|
34
|
+
|
|
35
|
+
## Capitalization policy
|
|
36
|
+
|
|
37
|
+
- **Threshold**: $2,500 — items below this are expensed immediately
|
|
38
|
+
- **Method**: straight-line depreciation
|
|
39
|
+
- **Default useful life**: 36 months (per-asset override via `data.useful_life_months`)
|
|
40
|
+
- **Selection**: events with `data.capitalize: true` appear in the asset register
|
|
41
|
+
- **Disposal**: record a `disposal` event with `data.asset_id` and `data.proceeds`. Gain/loss = proceeds - net book value
|
|
42
|
+
- **Write-off**: record a `write_off` event with `data.asset_id`. Remaining NBV is a loss
|
|
43
|
+
- **Impairment**: record an `impairment` event with `data.asset_id` and `data.impairment_amount`. Reduces carrying value
|
|
44
|
+
|
|
45
|
+
## Tax jurisdiction
|
|
46
|
+
|
|
47
|
+
Your jurisdiction and relevant rules.
|
|
48
|
+
|
|
49
|
+
## Reconciliation
|
|
50
|
+
|
|
51
|
+
### Post-import checklist
|
|
52
|
+
1. **Count**: verify event count matches source row count
|
|
53
|
+
2. **Debits/credits**: verify totals match source statement totals
|
|
54
|
+
3. **Closing balance**: `clawbooks verify --balance <closing> --currency USD`
|
|
55
|
+
4. **Duplicates**: review `potential_duplicates` in verify output
|
|
56
|
+
5. **Gaps**: `clawbooks reconcile --source S --gaps` to find date gaps >7 days
|
|
57
|
+
|
|
58
|
+
### Cross-source checks
|
|
59
|
+
When importing from multiple sources (bank, Stripe, manual), verify:
|
|
60
|
+
- No double-counting of the same transaction across sources
|
|
61
|
+
- Transfers between accounts net to zero
|
|
62
|
+
- Opening balances + net transactions = closing balances per source
|
|
63
|
+
|
|
64
|
+
## Reporting
|
|
65
|
+
|
|
66
|
+
### Monthly
|
|
67
|
+
- **P&L**: revenue, operating expenses, COGS, tax, net income
|
|
68
|
+
- **Cash flow**: inflows vs outflows by category
|
|
69
|
+
- **Reconciliation**: verify + reconcile for each source imported that month
|
|
70
|
+
|
|
71
|
+
### Quarterly
|
|
72
|
+
- **Balance sheet**: assets (cash + capitalized), liabilities, equity
|
|
73
|
+
- **Asset register**: `clawbooks assets --as-of <quarter-end>` — active, disposed, written-off
|
|
74
|
+
- **Tax estimate**: projected tax based on year-to-date income
|
|
75
|
+
|
|
76
|
+
### Annual
|
|
77
|
+
- **Full P&L**: 12-month income statement with monthly breakdown
|
|
78
|
+
- **Balance sheet**: year-end position
|
|
79
|
+
- **Asset register**: full depreciation schedule, disposals, write-offs
|
|
80
|
+
- **Tax preparation**: categorized expenses, income by source, deductions summary
|
package/program.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Clawbooks
|
|
2
|
+
|
|
3
|
+
You have access to `clawbooks`, a CLI tool for financial record-keeping.
|
|
4
|
+
The ledger is an append-only JSONL file. The accounting policy is a markdown file.
|
|
5
|
+
You are the accountant. The CLI is just data storage.
|
|
6
|
+
|
|
7
|
+
## Reading the books
|
|
8
|
+
|
|
9
|
+
To answer any financial question, first load context:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
clawbooks context 2026-03 # specific month
|
|
13
|
+
clawbooks context --after 2026-01-01 # everything since a date
|
|
14
|
+
clawbooks context # everything (small ledgers)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
This prints the accounting policy, the latest snapshot, and all events
|
|
18
|
+
in the period. Read the output, apply the policy, answer the question.
|
|
19
|
+
|
|
20
|
+
## Writing events
|
|
21
|
+
|
|
22
|
+
To record a financial event:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
clawbooks record '{"source":"stripe","type":"income","data":{"amount":500,"currency":"USD","customer":"acme"}}'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Required fields: `source`, `type`, `data` (any object). `ts` is optional (defaults to now).
|
|
29
|
+
`data.currency` is **required** — the ledger rejects events without it (except snapshots, reclassify, opening_balance).
|
|
30
|
+
|
|
31
|
+
The CLI enforces sign convention automatically for known types:
|
|
32
|
+
- **Outflow** (stored negative): `expense`, `tax_payment`, `owner_draw`, `fee`, `dividend`, `loan_repayment`, `refund`, `transfer_out`, `withdrawal`
|
|
33
|
+
- **Inflow** (stored positive): `income`, `deposit`, `equity_injection`, `loan_received`, `transfer_in`, `refund_received`, `grant`
|
|
34
|
+
- **Meta types** (sign not enforced): `snapshot`, `reclassify`, `opening_balance`
|
|
35
|
+
- **Asset events** (sign not enforced): `disposal`, `write_off`, `impairment`
|
|
36
|
+
- **Unknown types**: the CLI warns and preserves the sign you provide. Use critical thinking — if a new type represents money leaving the business, pass a negative amount. `verify` will flag sign inconsistencies.
|
|
37
|
+
|
|
38
|
+
The ledger is hash-chained — each event's `prev` field links to the previous event.
|
|
39
|
+
|
|
40
|
+
For bulk data, output JSONL and pipe it:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
echo '{"source":"bank","type":"income","data":{"amount":1000,"currency":"USD"}}
|
|
44
|
+
{"source":"bank","type":"fee","data":{"amount":25,"currency":"USD","desc":"Monthly fee"}}' | clawbooks batch
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Opening balances
|
|
48
|
+
|
|
49
|
+
Before importing transaction data, record opening balances for each account/currency. One event per account/currency:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
clawbooks record '{"source":"manual","type":"opening_balance","ts":"2025-01-01T00:00:00.000Z","data":{"amount":50000,"currency":"USD","account":"checking","category":"cash"}}'
|
|
53
|
+
clawbooks record '{"source":"manual","type":"opening_balance","ts":"2025-01-01T00:00:00.000Z","data":{"amount":-12000,"currency":"USD","account":"credit_card","category":"liability"}}'
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Convention:
|
|
57
|
+
- Positive amount = asset (cash, receivables, equipment)
|
|
58
|
+
- Negative amount = liability (credit cards, loans)
|
|
59
|
+
- `data.category`: `cash`, `asset`, `liability`, or `equity`
|
|
60
|
+
- `data.account`: identifies which account (e.g., `checking`, `credit_card`)
|
|
61
|
+
- One event per account/currency pair
|
|
62
|
+
- `opening_balance` is exempt from currency requirement and sign enforcement
|
|
63
|
+
|
|
64
|
+
## Importing messy data (CSVs, statements, etc.)
|
|
65
|
+
|
|
66
|
+
When the user gives you a CSV or other raw financial data:
|
|
67
|
+
|
|
68
|
+
1. Record opening balances first (if not already present)
|
|
69
|
+
2. Read the raw data and the policy (`clawbooks policy`)
|
|
70
|
+
3. Parse each row into a ledger event, classifying per the policy
|
|
71
|
+
4. For hardware/equipment purchases that meet the capitalization threshold, set `data.capitalize: true` and optionally `data.useful_life_months`
|
|
72
|
+
5. Output as JSONL and pipe to `clawbooks batch`
|
|
73
|
+
6. Run `clawbooks verify --balance <closing_balance>` to cross-check against the statement's closing balance
|
|
74
|
+
|
|
75
|
+
You are the parser. There is no import tool. You read the data and write the events.
|
|
76
|
+
|
|
77
|
+
## Capitalizing assets
|
|
78
|
+
|
|
79
|
+
When an expense meets the capitalization threshold (see policy), set `data.capitalize: true` on the event:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
clawbooks record '{"source":"bank","type":"expense","ts":"2025-09-15T00:00:00.000Z","data":{"amount":15000,"currency":"USD","description":"MacBook Pro","category":"hardware","capitalize":true,"useful_life_months":36}}'
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- `data.capitalize: true` — marks the event for the asset register
|
|
86
|
+
- `data.useful_life_months` — overrides the default useful life (default: 36 months)
|
|
87
|
+
- The `assets` command finds all events with `capitalize: true` and computes depreciation
|
|
88
|
+
- `--category` on the `assets` command is an optional filter, not the selection mechanism
|
|
89
|
+
|
|
90
|
+
## Asset lifecycle
|
|
91
|
+
|
|
92
|
+
After capitalizing an asset, you can record disposal, write-off, or impairment events. These reference the original asset by its event ID via `data.asset_id`:
|
|
93
|
+
|
|
94
|
+
**Disposal** (sold or traded in):
|
|
95
|
+
```bash
|
|
96
|
+
clawbooks record '{"source":"manual","type":"disposal","data":{"asset_id":"abc123","proceeds":5000,"currency":"USD"}}'
|
|
97
|
+
```
|
|
98
|
+
Gain/loss = proceeds - net book value at time of disposal.
|
|
99
|
+
|
|
100
|
+
**Write-off** (destroyed, stolen, obsolete):
|
|
101
|
+
```bash
|
|
102
|
+
clawbooks record '{"source":"manual","type":"write_off","data":{"asset_id":"abc123","currency":"USD"}}'
|
|
103
|
+
```
|
|
104
|
+
Remaining NBV becomes a loss.
|
|
105
|
+
|
|
106
|
+
**Impairment** (value reduced but still in use):
|
|
107
|
+
```bash
|
|
108
|
+
clawbooks record '{"source":"manual","type":"impairment","data":{"asset_id":"abc123","impairment_amount":3000,"currency":"USD"}}'
|
|
109
|
+
```
|
|
110
|
+
Reduces carrying value by the impairment amount. Multiple impairments can accumulate.
|
|
111
|
+
|
|
112
|
+
## Generating reports
|
|
113
|
+
|
|
114
|
+
When asked for a P&L, tax summary, balance, etc.:
|
|
115
|
+
|
|
116
|
+
1. Run `clawbooks summary <period>` for pre-computed aggregates
|
|
117
|
+
2. Map the output to the requested report:
|
|
118
|
+
- **P&L**: `by_type` + `by_category` → Revenue - OpEx = Gross Profit - Tax = Net
|
|
119
|
+
- **Balance Sheet**: `cash_flow.net` + opening balance (from snapshot or opening_balance events) → Assets. Capitalized assets from `clawbooks assets`. Equity = Assets - Liabilities
|
|
120
|
+
- **Cash Flow Statement**: Map categories to Operating/Investing/Financing per policy
|
|
121
|
+
3. For details or edge cases, also run `clawbooks context <period>` and reason over raw events
|
|
122
|
+
|
|
123
|
+
## Reconciliation workflow
|
|
124
|
+
|
|
125
|
+
After importing data from any source:
|
|
126
|
+
|
|
127
|
+
1. During import, compute expected totals (count, debits, credits) from the source data
|
|
128
|
+
2. Run `clawbooks verify <period> --source S` to check integrity (totals, hash, issues)
|
|
129
|
+
3. Run `clawbooks verify --balance <closing_balance> --currency USD` to cross-check the statement's closing balance
|
|
130
|
+
4. Run `clawbooks reconcile <period> --source S --count N --debits N --credits N --gaps` to compare and detect date gaps
|
|
131
|
+
5. Review `potential_duplicates` in verify output — same source/date/amount/description
|
|
132
|
+
6. If `RECONCILED`, proceed. If `MISMATCH`, investigate and fix before generating reports
|
|
133
|
+
7. Include the verify hash in report footers for audit trail
|
|
134
|
+
|
|
135
|
+
## Classification review
|
|
136
|
+
|
|
137
|
+
When importing events, set a `confidence` field in each event's data:
|
|
138
|
+
- `"clear"` — unambiguous classification (e.g., payroll labeled by bank)
|
|
139
|
+
- `"inferred"` — reasonable but uncertain (e.g., "AMZN" → office supplies)
|
|
140
|
+
- `"unclear"` — couldn't classify confidently
|
|
141
|
+
|
|
142
|
+
After import, run `clawbooks review <period> --source S` to see items needing review.
|
|
143
|
+
|
|
144
|
+
To reclassify an event, record an append-only correction:
|
|
145
|
+
```bash
|
|
146
|
+
clawbooks record '{"source":"manual","type":"reclassify","data":{"original_id":"abc123","new_category":"contractor"}}'
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The `summary` command automatically applies reclassifications. The `review` command excludes already-reclassified events.
|
|
150
|
+
|
|
151
|
+
## Generating snapshots
|
|
152
|
+
|
|
153
|
+
When the ledger is large, generate a snapshot to keep future context bounded:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
clawbooks snapshot 2026-03 --save # compute and save to ledger
|
|
157
|
+
clawbooks snapshot 2026-03 # compute and print (no save)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The snapshot includes balances by currency, totals by category, and P&L by currency.
|
|
161
|
+
|
|
162
|
+
## Quick reference
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
clawbooks record <json> # append one event
|
|
166
|
+
clawbooks batch # append JSONL from stdin
|
|
167
|
+
clawbooks log [--last N] # view recent events
|
|
168
|
+
clawbooks context [period] # load policy + events for reasoning
|
|
169
|
+
clawbooks policy # print policy.md
|
|
170
|
+
clawbooks stats # ledger overview
|
|
171
|
+
clawbooks verify [period] # integrity + chain + balance check + duplicates
|
|
172
|
+
clawbooks verify --balance N # cross-check closing balance
|
|
173
|
+
clawbooks reconcile [period] -S # compare expected vs actual totals
|
|
174
|
+
clawbooks reconcile -S --gaps # also detect date gaps >7 days
|
|
175
|
+
clawbooks review [period] # show items needing classification review
|
|
176
|
+
clawbooks summary [period] # pre-computed aggregates for reports
|
|
177
|
+
clawbooks snapshot [period] [--save] # compute period snapshot (balances, P&L)
|
|
178
|
+
clawbooks assets [--category C] [--life N] [--as-of DATE]
|
|
179
|
+
# asset register (capitalize-flag based)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Idempotent imports
|
|
183
|
+
|
|
184
|
+
When importing from a source (CSV, statement), include a stable `data.ref` field derived
|
|
185
|
+
from the source row (e.g. hash of date + description + amount + running balance). This
|
|
186
|
+
ensures re-importing the same source file produces identical event IDs and gets deduplicated.
|