> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vinmake.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How it fits together

> The layers, the five deployed graphs, the two gates, and why the two dependency trees are deliberately separate.

# How it fits together

GreatBook is five layers.
Reading them from the outside in, each one is narrower than the last, and the narrowest is the only one that writes.

## The layers

```mermaid theme={null}
flowchart TD
  CLIENTS["ChatGPT · Claude<br/>unexercised"] --> MCP
  MCP["Public MCP ingress<br/>live · registry 1.14.1"] --> API
  UI["Web UI<br/>workspaces"] --> API
  CONN["Connectors<br/>evidence"] --> LOOP
  API["API<br/>typed gateway"] --> LOOP
  LOOP["Agent graphs<br/>propose · gate · act"] --> LS
  LS["Ledger service<br/>18 invariants · writer"] --> PG
  PG["Postgres<br/>record · audit"] --> AN
  AN["Analytics / EPM<br/>read-only"]
```

| Layer                                | Responsibility                                                                                                                                                               | Can it write to the ledger?                                                                                                            |
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| ChatGPT, Claude and the MCP boundary | `greatbook.co/mcp` is a live OAuth-protected ingress advertising registry `1.14.1`, aligned with the pinned source contract. Neither provider has been exercised end to end. | not directly. The boundary delegates an exact confirmed selection to a named canonical service and never becomes accounting authority. |
| API layer                            | the typed HTTP contract. Routers handle HTTP and identity, services hold the business logic, repos do data access only.                                                      | only by calling the writer                                                                                                             |
| Cognitive loop                       | LangGraph state machines, one graph per lane. Each ingests a source, enriches deterministically, proposes a posting, and **pauses at the gate**.                             | no                                                                                                                                     |
| Ledger service                       | the single writer. The only path to a GL row. Owns the 18 GL invariants and the hash chain.                                                                                  | **yes, and only this**                                                                                                                 |
| Postgres                             | the system of record.                                                                                                                                                        | it is the record                                                                                                                       |
| Analytics / EPM                      | read-only cube over the GL and sub-ledgers. An extension.                                                                                                                    | no                                                                                                                                     |

<Note>
  The cognitive loop is **checkpointed in Postgres**, which is what makes the gate durable rather than a
  UI convention.
  The graph survives a restart while it is paused, and it resumes from the checkpoint rather than
  re-running the expensive pipeline from scratch.
</Note>

## The five deployed graphs

Each agent is one LangGraph graph, registered in the deploy manifest, one lane each.

| Graph        | Lane                                                                        | Writes?                                                                         |
| ------------ | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| `clerk`      | documents in: classify, extract, flag, queue for review                     | queue only, never the ledger                                                    |
| `bookkeeper` | an approved document to one balanced journal entry, behind the posting gate | **the only graph on the write path**                                            |
| `auditor`    | read-only assurance over the book of record                                 | no. Its session is put read-only by the database and then read back to prove it |
| `accountant` | period close and statutory reporting. It proposes adjustments.              | no                                                                              |
| `typewriter` | compose a document from words and lists, render a signable PDF              | documents only, never the ledger                                                |

<Warning>
  A graph must be declared in **both** places, the deploy manifest and the served-graph registry.
  A graph declared in only one is simply absent from the agent picker, with nothing failing anywhere,
  which is the worst kind of missing.
  A test gates the two files against each other so the drift is caught in CI rather than in production.
</Warning>

## The two gates

The accounting path after a document reaches intake has exactly two human decision points, and they are different questions asked of different people.
A Typewriter document has an earlier PDF-signing gate as well; that gate approves the document bytes, not their accounting treatment.
Native subledger records, approved workpapers, reversals and system events are also valid accounting-event sources; they do not pretend to begin in intake and remain subject to their own canonical service controls and the same single writer.

```mermaid theme={null}
flowchart TB
  U["Uploaded bytes"] --> C["Clerk<br/>classify · extract · flag"]
  T["Approved Typewriter<br/>payload"] --> H1
  C --> H1["Intake approver<br/>does this document<br/>belong in the books?"]
  H1 --> B["Bookkeeper<br/>draft one balanced entry"]
  B --> H2["Posting checker<br/>is this entry right?"]
  H2 --> L["Ledger service<br/>validate 18 GL invariants"]
  L --> J["Immutable entry<br/>hash-chained in the GL"]
  classDef source fill:#dbeafe,color:#172554
  classDef gate fill:#fef3c7,color:#451a03
  classDef writer fill:#dcfce7,color:#14532d
  class U,T,C source
  class H1,H2 gate
  class B,L,J writer
```

**Gate 1, intake.** For an uploaded document: “Is this document real and correctly extracted?”
For a Typewriter document, which bypasses Clerk extraction, the question is “Does this approved composition belong in the books?”
Approving advances the row and launches the Bookkeeper.
It moves no money.

**Gate 2, posting.** For that proposed document entry: "Is this journal entry right?"
Approval releases the proposal to the ledger service, which remains the only writer.

The rule across both document gates is strict: **three distinct authenticated people stand behind every document-originated posted journal entry** - whoever submitted the document, whoever approved it into the queue, and whoever approved the posting.
Not two, and not "two plus a constant".

<Note>
  The approve-to-Bookkeeper handoff is an **outbox, not a call**.
  The intake approval is durable the moment the request returns, and the launch that follows it can
  still fail.
  The reviewer is told so explicitly rather than being shown an unconditional success for an operation
  that may have done nothing, and there are two ways to finish the job: retry one launch, or sweep them.
</Note>

## Two dependency trees, on purpose

The repository carries two Python trees with separate dependency sets, and the separation is a design decision rather than an accident of history.

| Tree              | What it is                                                                            | Its dependency closure                                                                       |
| ----------------- | ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| `backend/`        | the canonical GL core: the writer, the ORM models, the migrations, the finance logic  | psycopg and the standard library for the posting path; the ORM, web and lint stack around it |
| `langgraph_chat/` | the running floor: the five agents, the DevCenter API behind the UI, the review gates | psycopg plus the standard library, plus the agent runtime                                    |

The reason they are separate is the reason the second one can import the first.
Because the engine's posting path has a psycopg-and-stdlib closure, the agent runtime can import the real writer **in process** without dragging an ORM and a web framework along with it.

That is what makes "the agents post through the same engine the API posts through" a fact rather than an aspiration.
There is no second ledger implementation to keep in step, because there is no second implementation.

<Note>
  One migration runner, one chain: alembic, in `backend/migrations/`.
  Read the live database's `alembic_version` before authoring a migration rather than inferring the head
  from the versions directory. CI migrates an empty database, so a repository whose head is behind
  production stays green while an upgrade against production fails closed.
</Note>

## Related

* [GreatBook in ChatGPT](/greatbook/greatbook) - the current integration boundary and availability
* [The seven guarantees](/greatbook/guarantees) - what each layer is protecting
* [Who does what](/greatbook/roles) - the people the two gates require
* [What is live](/greatbook/status) - the honest status of every component above
* [Technical flows and authority](/greatbook/technical/index) - the exact artifacts, stores, identities and refusals from document to journal entry
