lodgeit labs

Publishing a calculator to the LodgeiT Labs constellation

An invitation and a standard for anyone building bounded, deterministic tax and accounting tools.
LodgeiT Labs · September 2026 · draft v2

Why we're writing this

We run a small fleet of deterministic Australian tax and accounting calculators behind one public front door — no key, no signup, built so an agent can call them without a human in the loop (see lodgeit.org/calculators.html and lodgeit.org/llms.txt). Depreciation, Division 7A and nineteen FBT benefit categories are live, and a trial-balance classifier (Fano) joined them this week.

We are not going to build the rest of the world's tax and accounting algorithms ourselves. There are a million of them across jurisdictions and we'd like to point at other people's — provided they meet a standard an agent can rely on. If you already show the branch, the formula, the evidence state and the rounding — and refuse when the supplied facts do not settle the test — you are most of the way there.

This document sets out what "meeting the standard" means today, what we'd do with a calculator that meets it, and how we intend to help you earn from it as the platform matures. We are candid throughout about what exists now and what is still planned.

The standard, in one paragraph

A constellation calculator is a deterministic engine — no model in the path — behind an HTTP surface that describes itself, validates the request and refuses what it cannot answer, names every statutory input it consumed, and returns money as exact decimals. Everything below is an elaboration of those four properties.

1. Describe yourself

An agent should be able to go from your base URL to a correct first call without reading prose.

GET /v1/calculators
lists every calculator you serve: a stable URN, a JSON Schema reference for its input, and the period URNs it accepts.
GET /openapi.json
a complete OpenAPI 3 document for the surface.
GET /healthz
liveness.
GET /v1/rates/{period_uri}
the rate tables for a period, each with a SHA-256 content hash (see §3).

Naming conventions we use, and would ask you to follow so the registry can index by them:

ThingPatternExample
Calculatorurn:sbrm:calculator:{module}:{name}urn:sbrm:calculator:fbt:car-operating-cost
Periodurn:sbrm:period:{module}:{scope}urn:sbrm:period:fbt:fy2026
Rate tableurn:sbrm:rate:{module}:{period}:{rate-type}urn:sbrm:rate:div7a:fy2026:benchmark-interest

If a calculator has no period dependence, use the scope unscoped.

Every calculator declares a module (the URN’s second-last segment, e.g. urn:sbrm:module:fbt) and a short description of when to use it and when not to. Where a benefit type is served by more than one valuation method, each calculator also declares a selection.kind — fact, election or statutory_default — so an agent computes every method the records support and lets the client elect, rather than choosing one. GET /v1/modules lists the modules and their calculators; GET /v1/calculators?module= filters to one.

2. Validate, then refuse honestly

Refusals are a feature. The status code is a contractual signal, not an error to hide:

CodeMeaningBody must include
200Computedresults + manifest + advisory
422Malformed or incomplete requestthe field that failed
400Well-formed but outside what the calculator can answerrefusal_class and a one-line reason
404Unknown calculator URN or unsupported period URNwhich one
5xxService fault; the caller may retrynothing sensitive

A 400 is exactly your "supplied facts do not settle the test" case. Give it a stable refusal_class string an agent can branch on (out_of_scope_period, insufficient_facts, unsupported_entity, and so on — publish your own list in the OpenAPI document).

3. Name what you consumed

Every 200 carries a manifest: the rate tables and statutory parameters the calculation actually used, each with a SHA-256 of the table's content as served by /v1/rates/{period_uri}. This is what lets a caller detect that a rate changed between two calls months apart, and it is what our bounty reviewers check against the legislation.

"manifest": {
  "calculator": "urn:sbrm:calculator:payroll-levy:levy",
  "period": "urn:sbrm:period:payroll-levy:fy2026",
  "rate_table_uris": [
    { "uri": "urn:sbrm:rate:payroll-levy:fy2026:levy-rate", "sha256": "…" }
  ],
  "engine": "payroll-levy/1.2.0",
  "citation": " , s 
" }

Alongside it, an advisory block: what kind of figure this is and what it is not — your "review aid, not a compliance determination" language belongs here, as structured text the agent will pass to the human.

"advisory": {
  "figure_type": "payroll_levy_estimate",
  "notes": [
    "Review aid for a qualified professional; not a lodgement figure.",
    "Assumes eligible wages as supplied; eligibility under s 3B is not tested here."
  ]
}

4. Numbers are decimal strings

Money and rates are returned as decimal strings, never JSON floats: "9830.60", not 9830.6. Beyond representation, the constellation has one rounding standard:

  1. Exact inside. Internal arithmetic is exact — rational or arbitrary-precision decimal. No binary float on the path from parsed input to emitted figure.
  2. One rounding point. A figure is rounded once, when it is emitted. A rounded value is never fed back into arithmetic, except as rule 6 allows.
  3. Cents, ties away from zero. Money emits at 2 dp, ties away from zero (ROUND_HALF_UP, MidpointRounding.AwayFromZero, Excel ROUND). Rates and factors emit at 4 dp on the same rule; the emitted scale is stated in the schema.
  4. Cent-quantised in, refused otherwise. Money inputs must already be cents. A finer value is refused with 422 naming the field — never silently rounded.
  5. Published totals foot. Where lines and a total are published together, the total is the sum of the published lines. A cent difference against the exact total is exposed as a working, not hidden.
  6. The posted unit is the rounded line. When one rounded figure is apportioned into posted periods, each period is rounded and the final period carries the difference so the periods sum to the figure. This is the only place a rounded value is carried.
  7. Schedules never absorb. An amortisation schedule is not forced to close at zero. A non-zero end balance is a fact about the contract or the stated rate and is reported as such.
  8. Whole dollars only at the ATO label, once, by one named function, applying the ATO's per-label direction. Never by a cast.

A conformant calculator states in its advisory which of rules 3, 5, 6 and 7 apply to it, and names the rounding policy in force in its manifest beside the rate-table hashes. This is the single most common way an otherwise-correct calculator fails a review.

5. Determinism and reproducibility

Same request, same period, same rate-table hashes → byte-identical result. No model, no external lookup at call time other than your own rate tables, no clock dependence except through the period URN. Publish a small fixture — a handful of requests with expected responses — in your repository; we will run it against your live endpoint as part of listing, and again whenever you tell us you've changed something.

6. Access and cost

The constellation model is open access: no key, no signup. Bound your own cost the way we do — a small instance cap on whatever you host on, and request guards (body size, a per-IP rate limit returning 429 with Retry-After). Tell callers the limits in your discovery response. You host it; we point at it. Cloud Run, a VPS, or a browser-side calculator with a thin HTTP wrapper are all fine, so long as the URL is stable and the surface above is present.

What we'll do with a calculator that meets the standard

Today (manual, but real):

  1. We run your fixture and a conformance pass against the six sections above and tell you what, if anything, is short.
  2. We list it on calculators.html and in llms.txt as an external entry with your name on it, status available, linking to your repository and base URL. Agents that already read our llms.txt will find it the same day.
  3. We expose it through the same discovery your calculators already understand, so a caller enumerating the constellation sees yours next to ours.

Planned (the parts that make this scale, in the order we'll build them):

How you'd earn from it — the future state, stated plainly

None of this is live yet, and we'd rather say so than imply otherwise. The design is:

L402 at your endpoint. L402 is the Lightning-native HTTP payment flow: a call without payment returns 402 with an invoice; the caller (typically an agent) pays a few satoshis and retries with the proof. It is machine-native and needs no signup, which is the same "no key" philosophy applied to money. Because it lives at your endpoint, payment goes to you directly; there is no intermediary holding your revenue.

What LodgeiT earns, and from what. We charge for what we actually provide — discovery and attestation — as a routing fee on calls that come through our gateway or MCP surface, and nothing on calls that reach you directly. A listing in the registry is free; a practitioner attestation, once you've earned it, is what drives traffic to you, and that traffic is what you're paid on.

Order of operations. Contract and conformance first (nothing to pay for until a caller can trust the thing it's paying for), registry and tiers second, L402 third. We expect the first two within the next quarter; the third depends on them. If you'd rather not touch Lightning, an unpaid listing is still worth having — the agents are already reading llms.txt.

A concrete first step

Take one deterministic calculator you already have and put it behind the surface in §1–§4: discovery, 422/400/404 refusals with a refusal_class, a manifest naming the rate table with its hash and the statutory citation, decimal-string money, and a five-case fixture in the repo. Send us the base URL. We'll run the fixture and the conformance pass, and if it clears, it is on the page and in llms.txt the same week — the first calculator in the constellation that we didn't write.

If something in the standard doesn't fit your tool, say so; the spec is young and you are the kind of author it's meant to serve.

— Andrew Noble, LodgeiT Labs
andrew@lodgeit.net.au

Reference