# open-doc-review Advisory AI document review that bolts onto the content-management system (ECM) you already use. When a document lands in your ECM, open-doc-review: 1. **classifies** it into one of the document types you define, and saves the type as metadata, 2. **extracts** the fields you define for that type into metadata, 3. **finds the reference documents** it must agree with (by matching extracted fields: an invoice's PO number finds the purchase order), 4. **reviews** it against those references with Claude, using **your** prompts, and 5. **writes the findings beside the document**: one comment per finding (severity, page, what was compared), a summary comment, and review metadata. A reference that arrives later triggers a re-review, and long PDFs are reviewed in page windows. > **Align it with your own policies.** The example document types, fields, prompts and severity levels > are starting points, not a standard. Before relying on any result, make them reflect your organization's > own policies, procedures, specifications and regulatory obligations; have the policy owners approve the > wording; and check the results with `docreview eval`. Every starter prompt carries this notice in its > header. Nothing in this project is legal, quality or regulatory advice. It never edits, moves, renames or deletes a document. The ECM port has no method that could. Every finding is advisory: a person decides what to do with it. ```mermaid flowchart LR ECM[("Your ECM
(via its adapter)")] C["1 · Classify"] X["2 · Extract fields"] F["3 · Find references"] R["4 · Review"] YOU[/"Your prompts +
document-type config"/] LOG[("Audit log
every model call")] ECM -- "new or changed document" --> C C -- "writes: document type" --> ECM C --> X X -- "writes: field values" --> ECM X --> F F -- "searches by field values" --> ECM F --> R R -- "writes: comments + review outcome" --> ECM YOU -.-> C & X & R C & X & R -.-> LOG ``` Each step writes its own result into the ECM as soon as it has it. The document type and fields are therefore searchable (and correctable by a person) before the review runs, and a person's correction is respected on the next pass. ## What you bring | You provide | Where | Example | |---|---|---| | Document types and their fields | `docreview.yaml` → `doc_types` | invoice: `invoice_number`, `po_number`, `total` | | How to find references | `doc_types..review.references` | invoice → purchase order where `po_number` matches | | Prompts, in your own words and style | a folder of Markdown files | `prompts/review/invoice.md`, started from `examples/prompt_templates/review_template.md` | | Documents with known problems, to check it works | `expected.yaml` + a test folder | `examples/generic/expected.yaml` | | A connection to your ECM | an adapter: `local`, `box`, or your own | see [docs/ADAPTERS.md](docs/ADAPTERS.md) | What's in `examples/`: | Folder | What it is | |---|---| | `shared_prompts/` | Generic starter system, classification and extraction prompts, written for any document type. | | `prompt_templates/` | A fill-in review prompt template: checks, exclusions, severity, how to report. | | `generic/` | The quick-start example: an invoice checked against a purchase order, and a batch record against its master record. | | `starter_pack/` | Ready-to-copy examples: three-way invoice match, certificate of analysis against a specification, contract against standard terms, and a policy checklist with no references. | All of it is illustrative. Copy it, then replace the wording with your own. ## Quick start (no ECM needed) ```bash git clone https://github.com/enveda/open-doc-review.git && cd open-doc-review uv sync # or: pip install -e . export ANTHROPIC_API_KEY=... # or: ant auth login cd examples/generic uv run docreview check # validates config, prompts and the adapter uv run docreview templates # shows the metadata it will write (for Box/SharePoint: the setup script) uv run docreview run --once # reviews the sample documents in library/ uv run docreview estimate # rough tokens and cost before you run anything (no model calls) uv run docreview eval --runs 3 # scores the review against the planted problems (expected.yaml) ``` ### What you'll see The example library holds two made-up pairs of documents. Each document under review has four planted mistakes, so you can check that the review catches them. **A supplier invoice** (`library/inbox/INV-2041.txt`), checked against the purchase order it cites (`library/purchase_orders/PO-7730.txt`): 1. It bills 550 widgets; the PO ordered 500. 2. Brackets are charged at 0.95; the agreed price is 0.85. 3. It adds a 60.00 expedite fee that is not on the PO. 4. The total says 1,460.00; the lines add up to 1,450.00. **An executed batch record** (`library/inbox/EBR-B24-0117.txt`), checked against the master batch record it was made to (`library/master_batch_records/MBR-0042.txt`), found by MBR number and version: 1. 10.40 kg of active ingredient was dispensed; the limit is 10.00 kg ± 1% (10.10 kg at most). 2. The drying inlet air was 68 °C; the limit is 55–65 °C. 3. The blend step has no second-person verification, which the MBR requires. 4. The yield is 91.2%; the acceptable range is 95.0–102.0%. None of the out-of-limit results has a deviation recorded. Nothing in these files refers to a real product, company or batch. The local adapter has no ECM to write to, so after the run it saves results **in a new file next to each document**, such as `INV-2041.txt.docreview.json`. (With Box or SharePoint, the same results appear as metadata and comments on the file.) This file does not exist until you run the example. Trimmed, it looks like this; the wording of the findings varies from run to run: ```json { "classification": {"doc_type": "invoice", "processed_version": "3f9c0d1e2a7b", "...": "..."}, "fields": {"invoice_number": "INV-2041", "po_number": "PO-7730", "supplier": "Acme Widgets Co.", "invoice_date": "2026-09-18", "total": 1460.0, "currency": "USD"}, "review": {"outcome": "blocking_findings", "finding_counts": {"blocker": 1, "major": 3, "minor": 0, "info": 0}, "references": {"Purchase order": "purchase_orders/PO-7730.txt"}, "...": "..."}, "comments": [ {"text": "[BLOCKER] Invoice total does not add up\nLines sum to 1,450.00 but the total states 1,460.00."}, {"text": "[MAJOR] Quantity exceeds purchase order\nLine 1 bills 550; PO-7730 ordered 500. · compared with Purchase order"}, {"text": "[MAJOR] Unit price differs from purchase order\nBracket billed at 0.95; agreed price 0.85. · compared with Purchase order"}, {"text": "[MAJOR] Charge not on purchase order\nExpedite fee of 60.00 is not on PO-7730. · compared with Purchase order"}, {"text": "Review summary — advisory outcome: blocking findings\n..."} ] } ``` - **classification**: what type of document it decided this is. - **fields**: the values it pulled out, as configured for that type in `docreview.yaml`. - **review**: the overall outcome, the count of findings by severity, and which reference documents were used. - **comments**: one per finding (severity, what's wrong, what it was compared with), plus a summary. Every call to the model is also recorded in `logs/ai_calls.jsonl`, the audit log: what was asked, which model answered, what it returned, tokens and time. Other commands: ```bash docreview run # poll forever (every 60 s; --interval to change) docreview process # one document: classify, extract, review if not yet reviewed docreview review # review now, even if this version was already reviewed ``` Set `review.dry_run: true` to run real model calls while writing nothing to the ECM. It's useful for trying a prompt change on live documents. ## Connecting your ECM | Adapter | `adapter:` | Install | Status | Guide | |---|---|---|---|---| | Local folder | `local` | (built in) | supported: for trying it out and tests | this README | | Box | `box` | `pip install 'open-doc-review[box]'` | supported | [docs/BOX.md](docs/BOX.md) | | SharePoint Online | `sharepoint` | `pip install 'open-doc-review[sharepoint]'` | experimental | [docs/SHAREPOINT.md](docs/SHAREPOINT.md) | | Veeva Vault | `veeva_vault` | `pip install 'open-doc-review[veeva_vault]'` | example | [docs/VEEVA_VAULT.md](docs/VEEVA_VAULT.md) | | M-Files | `mfiles` | `pip install 'open-doc-review[mfiles]'` | example | [docs/MFILES.md](docs/MFILES.md) | | Alfresco | `alfresco` | `pip install 'open-doc-review[alfresco]'` | example | [docs/ALFRESCO.md](docs/ALFRESCO.md) | | Amazon S3 | `s3` | `pip install 'open-doc-review[s3]'` | example | [docs/S3.md](docs/S3.md) | What the statuses mean: - **Supported:** built and unit-tested against the vendor's SDK. - **Experimental:** written to the documented API and unit-tested, but not yet run against a live system. - **Example:** the same as experimental, but intended mainly as a worked starting point for your own adapter. Read its Known limits first. **Anything else** (OpenText, Documentum, NetDocuments, Egnyte, Google Drive, ...): implement eight methods. See [docs/ADAPTERS.md](docs/ADAPTERS.md). `adapter: your_package.module:YourAdapter` loads it, with no fork needed. ## Documentation - [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md): how a document flows through, and the design rules - [docs/CONFIGURATION.md](docs/CONFIGURATION.md): every config key - [docs/METADATA.md](docs/METADATA.md): every metadata key written on a document, with examples, and how each ECM stores it - [docs/PROMPTS.md](docs/PROMPTS.md): writing your own prompts, and the variables available - [docs/WRITING_REVIEW_PROMPTS.md](docs/WRITING_REVIEW_PROMPTS.md): how to write review checks and severities that give consistent results - [docs/VALIDATION.md](docs/VALIDATION.md): a generic risk-assessment and validation starting point for regulated organizations - [docs/ADAPTERS.md](docs/ADAPTERS.md): writing an adapter for your ECM - [docs/BOX.md](docs/BOX.md): setting up the Box adapter - [docs/SHAREPOINT.md](docs/SHAREPOINT.md): setting up the SharePoint adapter (experimental) - Example adapters: [Veeva Vault](docs/VEEVA_VAULT.md), [M-Files](docs/MFILES.md), [Alfresco](docs/ALFRESCO.md), [Amazon S3](docs/S3.md) - [docs/DEPLOY.md](docs/DEPLOY.md): running it as a service, rolling it out, cost - [CDP methods paper, Supplementary Information (PDF)](docs/Supplementary_Enveda-Anthropic_CDP_methods_paper.pdf): the production system this project's design comes from, including how it compares with open-doc-review (Supplementary Note 1.7) ## Before you use it on real documents - Documents are sent to the Claude API. Check that this is allowed for your content, and review your data-retention settings with Anthropic. - Give the adapter's service account the least access that works: read, plus write for metadata and comments. - Findings come from a model. Validate the prompts and configuration on documents with known problems before anyone relies on the output, and keep a person in the loop. ## Author Created and maintained by Andrew Martin ([LinkedIn](https://www.linkedin.com/in/andrew-martin-7961834b/), [GitHub](https://github.com/Hedgehog-Info)) at Enveda. ## License MIT License. See [LICENSE](LICENSE).