An open standard + toolchain that embeds a machine-readable, broker-asserted data payload inside commercial-real-estate offering-memorandum (OM) PDFs, and exposes the same payload as JSON-LD on the web. Extract once at the source; consume infinitely, cheaply, downstream.
Published by Vervelio Labs (neutral steward). Dual-licensed: the toolchain is MIT, the specification is CC-BY-4.0 (see License). Docs, the verifier, and the namespace live at openom.app.
Pick the door that matches your job. Each one is the shortest path to a working result.
| You are⦠| openOM gives you⦠| Start here | No install? |
|---|---|---|---|
| π’ Broker - I have an OM PDF and want to add verified deal data | A review form that embeds your deal into the PDF. You never touch a terminal. | openom.app/embed/ (in your browser) or the Chrome extension | β Nothing to install; bytes never leave your machine |
| π Portal - I run a listings site and want trust badges + payloads at scale | A drop-in <openom-badge> web component and a free read API |
Portal quickstart β js/widget/ + mcp.openom.app |
Badge is one <script> tag; read API needs no key |
| π» Developer - I want to call the API in my own code | Clean Python + TypeScript libraries (embed / read / validate) | Developer quickstart β examples/ |
pip install openom-core Β· npm install openom-js |
| π€ AI-builder - I want to ground an agent on OM data | A free, deterministic, public MCP endpoint | mcp.openom.app/mcp β config |
No key, no per-call cost |
You have an OM PDF. You want to embed your deal data so machines can read it. That's it.
β Go to openom.app/embed/. No install, no account, no command line. Your PDF never leaves your computer. You'll get a review form where you enter (or confirm) the deal facts, then download an openOM version of your PDF. New to this? The step-by-step broker guide walks the whole thing in plain language.
Prefer a browser extension you can reuse on any listing? Install openOM from the Chrome Web Store and use author mode - it remembers your name, brokerage, and license so you never retype them.
A few things that trip up first-time brokers:
- Cap rate is a decimal. A 6.25% cap rate is entered as
0.0625, not6.25. The form tells you this; if you see a "greater than the maximum of 1" error, that's the fix. - On-device AI is optional. The extension can pre-fill the form using Chrome's built-in AI, but it's a convenience, not a requirement - entering the fields by hand is the normal, fully supported path. If your Chrome doesn't have the model, just fill the form yourself.
- Verified means provenance, not truth. openOM records who asserted the deal, that it is unaltered, and as of when - it never claims your numbers are correct. See Assertions, not facts.
You do not need the Python om CLI. It exists for developers and automated pipelines.
You run a listings site. You want a trust badge next to each listing and to read openOM payloads programmatically. Full walkthrough: openom.app/docs/quickstart-portal.
Three ways in:
- Drop-in badge (client-side). The
<openom-badge>web component renders the trust state next to a listing with one script tag. Seeexamples/badge.html. - Precompute the state (server-side, best for results grids). Call
om_readon the public MCP endpoint, then set the badge state from the response. Map it explicitly -om_readreturnsstate: "present", so derive the badge state:state = (r.state === "present" && r.verification.hashValid) ? "integrity-ok" : (r.state === "hash-mismatch" ? "hash-mismatch" : "absent"). - In your own code (Node).
npm install openom-jsand import the reader (readPayloadFromBytes,summarizeDeal).
Note: origin-verified (ββ) requires the mirror JSON and the PDF to share the same registrable domain (Β§10.1). PDFs served from a separate CDN domain show integrity-ok (unaltered since embed) but not origin-verified - host the mirror on the listing's own domain to reach ββ.
pip install openom-core openom-cli # the Python library + the `om` CLIgit clone https://github.com/sarthaknimbalkar/OpenOM
python OpenOM/examples/quickstart.py # embed β read β validate, end to endPython API (from openom_core import embed, read, validate) and the om CLI:
om init deal.json # scaffold a ready-to-edit payload (so "no deal.json" can't happen)
om profile set --broker "Jane Broker" --brokerage "Acme" --license "MI 6501-000000" # once; auto-filled
om inspect path/to/offering.pdf
om embed path/to/offering.pdf --payload deal.json --out out.pdf --asserted-date 2026-08-16
om read out.pdf
om validate deal.json # schema 0.1 is bundled; --schema only to override itThe CLI coaches you as you go: om with no arguments routes non-developers to the browser, every
error names the next action, and om init/om profile remove the two things brokers trip on.
TypeScript:
npm install openom-jsimport { embedPayload, readPayloadFromBytes, validatePayload } from "openom-js";More runnable examples - including a browser badge and an MCP config - are in
examples/.
Point any MCP client at the free public endpoint and ask it to read an OM.
https://mcp.openom.app/mcp
No API key, no per-call cost. It exposes two deterministic, read-only tools - om_read (from PDF
bytes or an https URL) and om_validate. Try it on the
sample OM. Full grounding guide:
openom.app/docs/grounding-ai.
Client config - see examples/mcp-config.json:
{ "mcpServers": { "openom": { "url": "https://mcp.openom.app/mcp" } } }Client only supports stdio (e.g. a Claude Desktop JSON config)? Use the mcp-remote bridge instead:
{ "mcpServers": { "openom": { "command": "npx", "args": ["-y", "mcp-remote", "https://mcp.openom.app/mcp"] } } }Want the full six-tool surface (om_inspect Β· om_extract_text Β· om_extract_images Β· om_read Β· om_validate Β· om_embed)? Self-host it: pip install openom-mcp, then run om-mcp (stdio) or
om-mcp-http (HTTP).
Every downstream consumer of an OM - CRM, underwriting model, portal, LLM agent - re-extracts the same facts from the same PDF, badly and repeatedly. openOM moves the extraction to the source: the broker (or their tool) embeds a signed, versioned payload once, using the Factur-X / PDF/A-3 attachment mechanism. The PDF still looks byte-for-byte identical; a machine can now read the deal in milliseconds with zero inference.
Deterministic core, inference at the edges. The engine, MCP server, and consumer tooling
contain zero LLM/inference calls, ever - no keys, no per-call cost, fully testable. Any
LLM-assisted mapping runs client-side / on-device in the authoring layer only. This boundary is
enforced mechanically in CI (the boundary job fails if an inference/network client ever
enters the core/cli/mcp dependency tree).
An OM is an advertisement - a broker's opinion of value, which the seller agreed to before
it was published. So every payload is an identified party's opinion as of a date (assertedBy +
assertedDate are always required), and openOM records who asserted it, that it is
unaltered, and as of when - it never claims the opinion is true. Verified means
provenance, not truth. Tooling checks internal consistency (NOI Γ· price vs cap rate,
rent-schedule math, date arithmetic) and never market truth. Schema errors block; consistency
warnings never do.
The MV3 Chrome extension detects/verifies openOM data on any PDF (consumer mode) and lets a broker embed data into an OM without the CLI (author mode). Chrome 116+; the same build loads in Edge, and Firefox is roadmapped (see extension/README).
β Install from the Chrome Web Store: openOM (one click, auto-updates). Not a developer and just want to embed one OM? You don't even need the extension - do it in your browser at openom.app/embed/.
For developers, to build and load it unpacked from a clone:
npm --prefix js install && npm --prefix extension install
npm --prefix extension run build # β extension/dist (load this unpacked)
npm --prefix extension run package # β extension/openom-extension-<version>.zip (Web Store upload)Then open chrome://extensions, enable Developer mode, click Load unpacked, and select
extension/dist. Consumer mode is the toolbar popup; author mode opens from the popup's "Embed a
payloadβ¦" button (a side panel).
- CI / server-side: the openom-embed GitHub Action embeds or
validates payloads in a broker's pipeline, and the
omCLI does the same locally - no browser, no inference. - Verify without installing anything: the hosted, fully client-side tool at https://openom.app/verify/ reads a PDF in your browser and shows its openOM state (bytes never leave your machine).
- Portals: the embeddable
<openom-badge>shows the trust badge next to a listing with one script tag.
| Path | What |
|---|---|
core/ |
Python library - deterministic PDF/data verbs (embed, read, inspect, extract, validate). The heart of the standard. Zero inference deps. |
cli/ |
The om command over core. |
spec/ |
JSON Schema, sample payloads, @context/vocabulary, and the conformance vectors (JCS oracles + golden PDFs). The product. |
mcp/ |
Deterministic MCP server - the 6-tool surface (om_inspect Β· om_extract_text Β· om_extract_images Β· om_read Β· om_validate Β· om_embed) over core. Self-host stdio/HTTP (om-mcp/om-mcp-http); a free public read-only grounding endpoint (om_read+om_validate) runs on a Cloudflare Worker at mcp.openom.app (mcp-worker/). |
js/ |
TypeScript reference implementation (openom-js) - embed/read/validate/verify/decrypt - powering the extension + web/Node consumers. Byte-parity with core. |
extension/ |
MV3 Chrome extension: consumer mode (detect/verify/badge/publish) + author mode (capture/review/assert/embed, on-device extraction). |
process/ |
Extraction/mapping playbook (SKILL.md + agent-instructions) for authoring clients. No code. |
fixtures/ |
Seeded-defect + producer-diverse fixtures (committed for CI); the full real-OM corpus is confidential (gitignored). |
Cardinal boundary: core/, mcp/, and consumer-mode js/ never import an inference client.
The Python (core) and TypeScript (js) implementations MUST produce byte-identical
canonical JSON (RFC 8785 JCS) and therefore the same
SHA-256 integrity hash. This is the anti-fork oracle: spec/vectors/ holds
payloads with their expected canonical bytes/hash plus golden embedded PDFs, and CI runs each
implementation against the other's output on every commit ([OM-VEC-002]).
pip install -e "core[dev]" -e "cli[dev]"
pre-commit install # optional local guardrails
ruff check core/src core/tests core/scripts cli/src cli/tests
mypy core/src && mypy cli/src
pytest core -q --cov=openom_core --cov-fail-under=90
pytest cli -q --cov=openom_cli --cov-fail-under=90
python core/scripts/gen_vectors.py # regenerate vectors (must be a no-op = no drift)See CONTRIBUTING.md for the workflow, GOVERNANCE.md for how the standard evolves (RFCs, versioning, stability guarantees), CODE_OF_CONDUCT.md, and SECURITY.md for the threat model. Full documentation lives at https://openom.app/docs/.
Pre-1.0, active development - the full toolchain is shipped and green. Implemented: core
(embed/read/inspect/extract/validate), cli (om), mcp (six deterministic tools, self-host stdio/HTTP;
public read-only Worker at mcp.openom.app), js (openom-js, byte-parity with core), spec (schema 0.1, vectors,
@context, webhook envelope, codes registry), process (extraction playbook), and the two-persona
extension (consumer + author). Non-destructive embedding is proven across ~60 real producers; the
cross-implementation, JCS-differential-fuzz, and RFC 8785 anti-fork gates run in CI. The schema is
0.1 and may change until 1.0.
Dual-licensed. The toolchain (core, cli, mcp, js, extension) is MIT; the
specification artifacts under spec/ and the spec documents are
CC-BY-4.0. Β© 2026 Vervelio Labs.