- contact@insightxtract.com
InsightXtract runs entirely in your environment — your cloud, your data boundary, your choice of model. Start on a laptop with Docker Compose, then take the same containers to production on AWS, Azure, GCP, or OCI with Terraform. This is how.
InsightXtract is a self-hosted, container-native platform. Everything — the API, the console, the agentic extraction workers, the datastore, and the vector index — ships as containers you run inside your own network. Nothing leaves your boundary unless you point it at a hosted model, and even the model is your choice.
Get the full stack running locally or on a single VM in minutes — ideal for developers, evaluation, and small workloads.
Start here →Production-grade, autoscaling deployments on AWS, Azure, GCP, and OCI from one Terraform workflow.
Deploy to cloud →Autoscaling workers, database replicas, zero-downtime upgrades, backups, observability, and secrets.
Operate it →Bring your own cloud object store, database, and LLM — Claude, OpenAI, Bedrock, Vertex, Azure OpenAI, or a custom endpoint.
See the matrix →InsightXtract is a small number of stateless services around a metadata database, an object store, and a vector index. The services scale horizontally; state lives in managed data services you already trust.
Everything is stateless except the datastores. The API and workers hold no local state, so you scale them by adding replicas. Durability lives in the database, the object store, and the vector index — all of which you can run as managed cloud services with backups and replication.
| Component | What it is | Scales by | State |
|---|---|---|---|
| Web / Console | Static React app served by nginx | Replicas behind the LB / CDN | Stateless |
| API service | FastAPI — auth, projects, documents, REST API | Horizontal replicas | Stateless |
| Extraction workers | Agentic LangGraph runners (classify, extract, resolve) | Autoscale on queue depth / CPU | Stateless |
| Metadata DB | MySQL 8 — projects, classes, results, audit | Vertical + read replicas | Durable |
| Object store | Documents & run artifacts (S3/Blob/GCS/OCI) | Elastic (managed) | Durable |
| Vector index | Embeddings for RAG / semantic lookup | Managed or self-hosted | Durable |
| LLM provider | Your chosen model endpoint | Provider concurrency | External |
| Identity provider | OIDC/SAML (Okta, Entra ID, etc.) | Managed | External |
Each pluggable dependency has a native option on every major cloud. Set a few environment variables and InsightXtract uses the managed service you already run.
| Dependency | AWS | Azure | GCP | OCI |
|---|---|---|---|---|
| Compute | ECS Fargate / EKS | Container Apps / AKS | Cloud Run / GKE | Container Instances / OKE |
| Database | RDS MySQL / Aurora | Azure DB for MySQL | Cloud SQL MySQL | MySQL HeatWave |
| Object store | S3 | Blob Storage | Cloud Storage | Object Storage |
| LLM (managed) | Bedrock (Claude) | Azure OpenAI | Vertex AI | OCI Generative AI |
| Load balancer | ALB + CloudFront | Front Door | Cloud Load Balancing | OCI Load Balancer |
| Secrets | Secrets Manager | Key Vault | Secret Manager | OCI Vault |
Models are provider-agnostic: point the API at Anthropic Claude (direct or via Bedrock/Vertex), OpenAI (direct or Azure OpenAI), or any custom/self-hosted OpenAI-compatible endpoint. The extraction agents are written against a provider interface, so switching is a config change, not a rebuild.
Every deployment is driven by environment variables. These are the essentials; the deployment guides list the full set.
| Variable | Purpose |
|---|---|
DATABASE_URL | MySQL connection string (host, db, user, password). |
OBJECT_STORE_* | Bucket/container name, region, and credentials (or workload identity). |
LLM_PROVIDER | anthropic · openai · bedrock · vertex · azure_openai · custom. |
LLM_MODEL / *_API_KEY | Model id and provider credentials (or cloud IAM role). |
OIDC_* | Issuer, client id/secret for SSO (Okta, Entra ID, etc.). |
WORKER_CONCURRENCY | Parallel extractions per worker replica. |
Two layers do the reading, and both are pluggable. The document layer turns a page into text, structure and geometry — where every value sits, which label owns it, and which box is ticked. The reasoning layer decides what those values mean. Keeping them separate is why the same agent configuration runs unchanged on a different cloud, and why an air-gapped deployment is a configuration rather than a fork.
A submission is not prose. A quarter of a typical application is tick boxes, and the printed text of a question lists every option whether or not it is selected — so text alone cannot answer it. The document layer returns selection state, key/value pairing and bounding boxes, which is what makes a checkbox answerable and a citation clickable.
| Engine | Where it runs | What it gives the agent |
|---|---|---|
| Amazon Textract | AWS | Key/value pairs with the printed label beside each value, SELECTION_ELEMENT state for every checkbox, table cells, and per-word bounding boxes with page numbers. |
| Azure AI Document Intelligence | Azure | Prebuilt and custom form models, key/value pairs, selection marks, table structure, and polygons per field. |
| Google Document AI | GCP | Form Parser entities, checkbox state, table extraction, and normalised values with layout anchors. |
| Tesseract / PaddleOCR | In-cluster, no egress | Word-level text and geometry for air-gapped or sovereign deployments where no managed service may be called. |
| Native text layer | Anywhere | For digital PDFs and Office files, the embedded text is read directly — layout preserved, no OCR cost at all. |
The agent asks the document layer for what it needs rather than receiving a fixed parcel: the whole page, one page again, a search across the submission, a worksheet as rows, or the form’s key/value pairs. Engines are selected per document class, so a scanned loss run and a digital exposure workbook in the same submission take different paths.
Model choice is a deployment decision, not a product one. The provider interface is narrow — text, vision, document, and tool-calling — so a model is swapped by configuration and the extraction agents, schemas and rules are untouched.
| Family | Reached via | Typical use |
|---|---|---|
| Anthropic Claude | Amazon Bedrock · Google Vertex AI · Azure · Anthropic API | Default for extraction and agentic reading — long context, native document input, strong tool use. |
| Google Gemini | Vertex AI · Gemini API | Native multimodal reading of long, image-heavy submissions. |
| OpenAI GPT | Azure OpenAI · OpenAI API | Where an enterprise has standardised on Azure OpenAI. |
| Open weights | Bedrock · Vertex · vLLM in your cluster | Llama, Mistral and similar — for air-gapped deployments, or cheap high-volume classification. |
Models are chosen per task, not per deployment: a small fast model for the structural pass and classification, a stronger one for extraction, and an optional escalation model that is only reached when the first attempt cannot return usable output. Every call records the model, token counts and cost against the run.
A generalist model has to be told what a retention is, what an ACORD 125 contains, and which of five names on a loss run is the claimant. A model fine-tuned on your own policies, forms and claim notes has absorbed it. InsightXtract serves both, and chooses between them per task rather than per deployment — because the tasks in a run are not alike.
| Task | Shape | Runs well on |
|---|---|---|
| Perception | One call per document: what kind of document is this, where are its sections and schedules. High volume, tightly bounded. | A domain SLM, in your VPC |
| Classification | One call per document, choosing from a closed list of document classes, with the quote that settles it. | A domain SLM, in your VPC |
| Extraction | Fill a 60–120 field schema with citations, evidence and confidence, as strict JSON. Long structured output. | A frontier LLM, or a domain model tuned on your forms |
| Escalation | Reached only when the primary model cannot return usable output. Rare by design. | The strongest model you have |
Set per document class, so a line of business is tuned without touching a schema:
ai_configuration: perception_model: insightdlm/pc-7b # domain SLM, in-VPC, no egress classifier_model: insightdlm/pc-7b # domain SLM extraction_model: bedrock/claude-sonnet # frontier escalation_model: bedrock/claude-opus # only on failure
That is the common pattern: the high-volume, well-bounded work runs on a small domain model inside your network, and a frontier model is reached for the hard remainder. Escalation is measured, not assumed — every call records which model answered, what it cost, and whether it was a first attempt or a retry, so the split between the two is a number you can see rather than a claim.
Domain models are served over any OpenAI-compatible endpoint — vLLM, SGLang, TGI or a managed deployment — so a model trained with InsightDLM on your own corpus is reached by pointing a base URL at it. Nothing about the agents, glossaries or post-processing rules changes; the model is a setting.
Training data you already have. Every extraction is written with its page, bounding box and the verbatim quote it was read from, and every human correction is captured with the reason it was made. Those are supervised examples with provenance attached — and the corrections are the highest-value ones, being exactly the cases the current model got wrong. Synthetic submissions can be generated from known data for a cold start, so a pilot can be scoped before any customer document is shared.
| Topology | What it means | Chosen when |
|---|---|---|
| Single-tenant SaaS | We run it, in an account dedicated to you. Your documents, database and object store are yours alone. | You want the fastest start and have no requirement to hold the infrastructure. |
| Your cloud, your VPC | Terraform into your account. Private subnets, workload identity instead of static keys, model reached over a private endpoint — no credential and no document leaves your network. | The common enterprise choice, and the one the deployment guides are written for. |
| Air-gapped / sovereign | No egress at all: in-cluster OCR, open-weight models served locally, container images mirrored to an internal registry. The same agents and rules run unchanged. | Data residency or classification rules forbid calling a managed service. |
Deploying: see cloud deployment with Terraform for the managed-service mapping on AWS, Azure, GCP and OCI, or Docker Compose to run the whole stack locally first.
The settings above stand the platform up. These decide how it reads — and they are set per document class in the console, not in code, so an underwriting team can tune a line of business without a release. Defaults below are the ones we ship; where a default looks conservative, it is because measuring the alternative changed our mind.
| Setting | Values | Default | What it does |
|---|---|---|---|
extraction_mode | vision · textract_text · text | vision | Page images, OCR text with coordinates, or plain text. On our benchmark corpus the text path was ~11% cheaper and 8% faster — less than the input-token difference suggests, because these workloads are output-bound — but it misread a broker’s identity from a carrier letterhead. Worth choosing for text-heavy sets with few tables. |
layout_text | true / false | false | Keeps a PDF’s columns instead of reflowing it. A two-column coverage block flattens to Limit 1,000,000 Limit 1,000,000 / Premium $21,875 Premium $0.00, with nothing saying which column a figure belongs to. Turn it on for form-heavy classes. |
enable_vision | true / false | true | Forces a text-only path and skips page rendering entirely. |
image_dpi · max_pages | integer | 150 · 10 | Render fidelity against cost. |
perception_model | model id | a fast model | The cheap structural pass that runs before extraction. |
Both of these can only ever empty a field, so both ship off. A blank is recoverable; a confident wrong number is not.
| Setting | Values | Default | What it does |
|---|---|---|---|
label_check | off · warn · strict | off | Checks each value against the label the form prints beside it, using the key/value pairing OCR already produces — no extra model call. A figure sitting under “Premium” is not a retention. We recommend warn: it annotates and lowers confidence. Run strict during development first — on our own corpus an early, broader version of this check cleared ten correct values to catch one wrong one, which is why it narrowed to genuine conflicts and why clearing is not the default. |
min_confidence | 0 – 1 | 0 | Empties any value the run itself is not confident in. Makes the precision/coverage trade explicit rather than leaving it to whatever the model happened to emit. |
Anything derivable from data already extracted should be computed, not read. Repeatedly, a field description telling a model that two figures are different did not stop it copying one into the other — counting the rows did. Fourteen rule kinds run after extraction:
| Rule | Purpose |
|---|---|
standardize · format · lookup_code | Glossary and reference-table normalisation; dates, money and codes to a house standard. |
derived_fields | Header figures computed from a table — count, count_distinct, sum, avg, min, max, first. A claim count that disagrees with the claims beneath it cannot be trusted on their value either. |
derived_tables · project_table | Build a schedule by rolling up or projecting another — a rating schedule assembled from whichever sheet in the submission carries class codes. |
infer | Thirteen named inferences, each deterministic and each recording why it fired: parse_labelled_amount (one line stating several coverages’ figures), distinct_from, not_equal_to, not_before, absent_means_no, year_from_years, date_offset, compose_from_row, modal_column, legal_suffix, years_since, first_present, join_column. |
merge_rows · dedupe_rows | Fold rows describing the same thing. The same benefit plan named slightly differently on two forms is one plan — read as two, the fiduciary exposure doubles on paper. |
map_column · copy_column · select_column | Reconcile the header a workbook happens to use with the column your schema declares. |
validate | Cross-field invariants — a policy period ends after it begins; a per-claim limit is not the aggregate. |
Submission workbooks open with a title banner, so the header is rarely row 1, and one logical schedule is often split across regional tabs. EXCEL_CODEGEN (on by default) reasons about each sheet’s layout, writes code against what it finds, and caches that reader by sheet shape — so a workbook seen before is read by the same code every time, which is what makes two uploads of one file give one answer.
Each setting above lives in the document class or agent configuration, is versioned with it, and is visible in the run trace alongside the value it produced. A record shows not only what was extracted but which rules touched it — which is the difference between an answer and an auditable one.
Extraction answers the questions you knew to ask. An underwriter looking at a new submission, or an adjuster opening a first notice of loss, also has the other kind — is there a prior act exclusion in here, who signed the application and when, what did the broker actually say about the tower. Point at a folder in Drive, press Ask, and put those questions to the documents directly.
Preparing a folder is deterministic reading — no model is called — so it takes seconds and its only cost is OCR, paid once and stored. The digest then sits in the cached part of the prompt, ahead of the question. That placement is the whole cost story: with the folder behind the cache point, a question is a couple of pence; in front of it, the same question re-sends the entire folder as fresh input every time and costs roughly ten times more.
Every factual claim comes back with the verbatim words it rests on, the file, and the page. If the documents do not state something, the answer says exactly that rather than inferring a figure or filling the gap from general knowledge of insurance. An underwriter acting on a confident, unsupported sentence is the failure the whole platform exists to avoid.
Where the folder has already been extracted, questions the audited record answers are served from that record — instantly, at no cost, and in agreement with the record by construction. Re-reading the PDF to answer them again risks producing a different number than the one already reviewed, which is worse than not answering at all.
A citation an underwriter cannot check is a claim, not evidence. Click one and the document opens at the page with the quoted words boxed. The rectangle comes from the document’s own word geometry — the quote is matched back against the page, never plotted from coordinates a model invented. Scanned pages are highlighted from the OCR geometry captured at prepare time. Where the exact words cannot be located, the page still opens and the viewer says so; a highlight over the wrong paragraph is worse than no highlight.
When a comparison is the point — losses by policy year, expenses by function, revenue against expenses across years — the answer carries a chart alongside the prose, and every number in it is cited like any other figure. Longer answers come back as a table rather than a paragraph of pipes. Each answer also offers two or three follow-ups that this folder can actually answer, grounded in what was read rather than in what a question generator imagined.
Nothing has to be uploaded anywhere new. A folder is whatever your storage location already points at — the same connectors extraction runs against, so a submission mailbox, a broker’s SharePoint site, or a bucket in your own account is askable the moment it is registered.
| Location type | Typical use |
|---|---|
| SharePoint · OneDrive | The broker or agency site a submission arrives on, and the claim folder an adjuster works out of. Sites, drives and document libraries are browsed in place. |
| Outlook · Teams | Submission mailboxes and channels — the email body and its attachments read together as one folder. |
| S3 · Azure Blob · Google Cloud Storage · OCI Object Storage | Your own bucket, in your own account and region. Documents are read with your credentials and never copied outside your perimeter. |
Chat is not a back door round your document security. The folder is reached through the same registered location and the same credentials the rest of the platform uses, and the question runs under the asking user’s role — admin, builder, operator, reviewer or viewer. Someone who cannot open a folder in Drive cannot ask questions of it either, and a quote can only cite a document that user is entitled to read. Every question, the documents it read, and the answer it gave are recorded against the user, so “who asked what of this claim file” is answerable after the fact.
Everything the console does here is a REST call, so an underwriting workstation, a claims desktop, or an internal insights tool can offer the same interactive exploration inside its own screens — including the tables and charts, which come back as data rather than as pictures, ready to render in your own component library.
| Endpoint | What it does |
|---|---|
POST /folder-chat/prepare | Reads the folder and streams progress per document, so your UI can show the file being read rather than a spinner. Idempotent — a prepared folder returns immediately. |
POST /folder-chat/ask | One question plus the conversation so far. Returns the answer, its citations (file, page, verbatim quote and the rectangle on the page), an optional table, an optional chart as labels and series, suggested follow-ups, and what the call cost. |
POST /folder-chat/forget | Drops the prepared copy and its digest — for a folder whose documents have changed. |
Calls authenticate with a scoped API key, and usage is tracked per key, so an embedded assistant in another product is metered and governed like any other consumer of the platform.
| Setting | Default | What it does |
|---|---|---|
FOLDER_DIGEST_DIR | /tmp/insightxtract/digests | Where prepared digests are kept. Point it at a persistent volume so a restart does not re-read folders. |
FOLDER_CHAT_STAGE | /tmp/insightxtract/folder-chat | Staging directory for the documents themselves, reused across questions so a follow-up does not re-download. |
max_iterations | 8 | How many searches or reads one question may make before it must answer with what it has. Raise it for large folders. |
| Digest budget | 90,000 chars | How much of the folder is carried in the cached prefix. Beyond it the agent reads on demand through the tools. |
| Model | platform default | Any configured provider — the chat uses the same model routing as extraction. |
Scale note. The digest carries a bounded slice of each document; beyond it, the agent searches and reads on demand. That fits targeted questions well — a limit, a date, a signature, what a form says. Very long documents (a few hundred pages of policy wording) and sweeping questions (“summarise every exclusion”) need more lookups than one question is given, so plan those as extraction jobs against a schema rather than as chat.
Next: stand it up locally with Docker Compose, or go straight to a production cloud deployment with Terraform.