ntro.capabilities.gl is the external accounting system integration layer: one stable Python surface (GLProvider, resource clients, typed models) regardless of which underlying GL the customer connects.
It is distinct from:
Subledger proposals (
BillProposal, etc.) strip Ntropii-only metadata before crossing into gl — see ntro.subledger.proposals and the unified-adapter docs in source.
Install
[gl] extra pulls the unified-GL SDK. Worker images that post to Xero / QuickBooks / Sage should include this extra — same as runbooks that call gl.for_entity.
Workflow authoring typically still pins ntro[workflow] for Temporal + capabilities; add [gl] when the runbook posts to a connected ledger.
Resolve a provider
Providers are selected fromtenant.config.gl:
provider— the registered GL adapter (e.g. the bundled unified adapter, or a future direct provider).options— provider-specific connection (consumer id, service id, etc.), populated after the tenant completes GL connect in Ntropii Workspace.
tenant.config.gl.provider is missing or unknown, resolution raises ProviderNotRegisteredError or ConnectionError_ — handle these in activities (many runbooks short-circuit posting when no GL is configured).
Example: post bills from approved expenses
Fromexpense_processor.post_expenses_to_gl — proposals built from subledger rows, then provider.bills.create with an idempotency external id:
external_id; providers must honour deduplication and expose find_by_external_id so Temporal retries stay safe.
Errors you should handle
Models
Types such asJournalEntry, Bill, LedgerAccount, … are re-exported from ntro.capabilities.gl.models. Prefer importing from gl.models in runbook code so upgrades stay centralized.
Reports — typed read-only views of GL state
A report is a typed, point-in-time view of the customer’s GL state —TrialBalanceReport, future BalanceSheetReport, ProfitAndLossReport. They live at ntro.capabilities.gl.reports (sibling to models).
Reports differ from subledgers: no per-row HITL lifecycle, no posting back, no transactional shape. They’re inputs to a workflow run, ephemeral after the run closes. The same typed shape is hydrated regardless of source.
Pattern B — the canonical flow for reports
<100ms, vs ~30s if the workflow re-runs ai.extract itself (the original parse_starting_tb shape pre-N-70).
Two source paths, one shape
The classmethod
from_extracted_payload adapts the document-ingest payload dict; the TrialBalanceClient.get(...) Protocol returns the same TrialBalanceReport from the underlying provider. Workflow code is invariant across sources.
The <capability>.reports.<Type> convention
This pattern generalises across capabilities. Each “external ledger” capability (gl, banking, …) gets a sibling reports module:
Same
from_extracted_payload(...) constructor shape across all of them.
Related
Accounting
Domain journals and proposals before external posting.
Subledgers
Typed rows and
propose_for_gl metadata.Data plane
Resolving tenant DB connections inside activities.