Skip to content

okf-inventory

Build a court Inventory of Productions PDF for an OKF matter (whole-paragraph yellow highlighting of production source PDFs, optional verbatim web-page captures, court-formatted cover + hyperlinked index + page ranges + page numbers, deployed to the matter folder) and the related bundle families: adjudication appendix indexes (INDEX TO APPENDICES TO THE RESPONSE etc., with section bands and no pages column), arbitration indexes to supporting documents/authorities (IN THE MATTER OF THE ARBITRATION ACT 1996 heading, bracketed (pp. x - y) ranges), and papers for counsel / inventory of papers (numbered list with sections). Use when the user mentions an inventory of productions, '4th/fifth inventory', building/rebuilding a production PDF, adding highlighted extracts to an inventory, FOURTH_INVENTORY_OF_PRODUCTIONS, PAI references, an INDEX TO APPENDICES / index to supporting documents / papers for counsel bundle. Never modifies the production sources themselves.

Source: .opencode/skills/okf-inventory/SKILL.md — site rebuilt 2026-09-05.


OKF → Inventory of Productions & bundle indexes

Turn highlighted production extracts (court) or plain source PDFs (adjudication, arbitration, counsel papers) into a ready-to-file index/bundle PDF. Three stages, one config file:

[verbatim pages]  ->  [highlight extracts]  ->  [assemble inventory + deploy]
tools/okf_inventory_verbatim.py   (optional; web captures)
tools/okf_inventory_highlight.py  (stage 1 - court only)
tools/okf_inventory_build.py      (stage 2)

One builder (okf_inventory_build.py) serves all four families — the index + sections config keys switch the layout:

Family Cover Index columns Pages Example
Court inventory of productions PAI ref, sheriffdom, parties Doc # / Document name / Pages a - b plain examples/okf_inventory_h1673_sample.json
Adjudication appendix index IN THE MATTER OF AN ADJUDICATION BEFORE [adjudicator] NO. / DOCUMENT DESCRIPTION hidden examples/okf_inventory_adjudication_sample.json
Arbitration index (supporting docs / authorities) IN THE MATTER OF THE ARBITRATION ACT 1996 … BETWEEN Claimant - and - Respondent NO. / DOCUMENT / PAGES (pp. a - b) bracketed examples/okf_inventory_arbitration_sample.json
Papers for counsel / inventory of papers PAPER(S) FOR COUNSEL + instance NO. / PAPER / PAGES plain or hidden examples/okf_inventory_counsel_sample.json

All example configs are self-contained templates with fictitious parties (McFadden v Millar; Greenway v Meridian before Mr Alistair Craig; Highland Build Products v Lochview Homes; Lyra Assurance petition) — copy them for real matters and swap in the true names.

When to run

  • The user asks to build/rebuild the inventory of productions for a matter ("4th inventory", "add docs to the inventory").
  • New highlighted extracts exist and need indexing, hyperlinking, page numbering and deployment to the matter folder.
  • A web page needs a verbatim, citable production copy (e.g. CPCAB qualification pages).
  • An adjudication pleading (Referral Notice, Response, Reply, Rejoinder…) needs its appendix index ("INDEX TO APPENDICES…") or an inventory of papers in that adjudication.
  • An arbitration needs an "Index to Supporting Documents" or "Index to Authorities" bundle.
  • Papers are being sent to counsel and an inventory/papers-for-counsel index is needed.
  • Do NOT use for ordinary correspondence filing or evidence production under an Existing Productions order — those are okf-ocr/inventory matters; this skill only assembles the index PDF.

Tooling

One config JSON drives everything. Examples: - examples/okf_inventory_h1673_sample.json — court Fourth Inventory as built 09-08-2026 (fictitious parties in this template copy). - examples/okf_inventory_adjudication_sample.json — Greenway v Meridian style INDEX TO APPENDICES (no pages column, section bands). - examples/okf_inventory_arbitration_sample.json — IN THE MATTER OF THE ARBITRATION ACT 1996 style, bracketed (pp. a - b) ranges. - examples/okf_inventory_counsel_sample.json — Papers for Counsel with numbered sections.

{
  "workspace": "C:\\...\\matter workspace (extract PDFs live here)",
  "deploy_to": "H:\\My Drive\\<matter folder>",
  "output": "FOURTH_INVENTORY_OF_PRODUCTIONS_09-08-2026.pdf",
  "inventory_title": "FOURTH INVENTORY OF PRODUCTIONS FOR THE PURSUER",
  "index_subtitle": "Fourth Inventory of Productions for the Pursuer",
  "doc_start": 27,
  "fetch_date": "9 August 2026",
  "cover_lines": [ {"text": "PAI 43 - 26", "size": 16, "bold": true}, {"text": "", "size": 12} ],
  "index": {
    "heading": "INDEX TO APPENDICES TO RESPONSE",
    "doc_label": "NO.",
    "name_label": "DOCUMENT DESCRIPTION",
    "pages_label": null,
    "pages_format": "plain"
  },
  "sections": [ {"at": 16, "label": "DOCUMENTS ATTACHED TO REJOINDER"} ],
  "highlights": [ {"name": "ef2018", "src": "...", "pins": ["..."]} ],
  "verbatim_pages": [ {"name": "cpcab_lc_l4", "title": "...", "source_url": "...", "sections": [{"heading": "...", "paras": ["..."]}]} ],
  "extracts": [ {"file": "ef2018_extract.pdf", "name": "Extract from ... - pages 1, 6, ..."} ]
}

Config fields beyond the court basics:

  • index (optional; court defaults shown):
  • heading — index page title ('Index' for court; 'INDEX TO APPENDICES TO RESPONSE' for adjudication; 'INDEX TO RESPONDENT'S SUPPORTING DOCUMENTS' for arbitration).
  • doc_label — number column header ('Doc #' court / 'NO.' adjudication / 'PAPER' counsel).
  • name_label — description column header ('Document name' / 'DOCUMENT DESCRIPTION' / 'DOCUMENT' / 'PAPER').
  • pages_labelnull hides the pages column entirely (adjudication indexes, VG Gigaclear style). Default 'Pages'.
  • pages_format'plain' (a - b, court) or 'bracketed' ((p. 3) / (pp. 4 - 5), arbitration). Use ASCII hyphen: en-dash does not survive the simple-font encoding.
  • doc_numbers — optional explicit row numbers as strings (for A1/B1 style, 'Not used' gaps or sub-numbering like 6.1); defaults to doc_start + index.
  • sections — band rows drawn inside the index before the row at 1-based position at (e.g. 'DOCUMENTS ATTACHED TO RESPONSE' / 'DOCUMENTS ATTACHED TO REJOINDER'; or 'GROUNDS OF APPEAL' / 'ANSWERS' / 'NOTES OF ARGUMENT' / 'MISC.' in papers for counsel). Bands take no doc number and move with their row across page breaks.
  • extracts entries may omit file — a placeholder row ('Not used') with a number and description but no pages and no hyperlink.
  • cover_lines entries support "align": "center" and long lines are word-wrapped automatically (the Arbitration Act heading block is centred).

Run order:

python tools/okf_inventory_verbatim.py  <config>          # optional stage 0 (court web captures)
python tools/okf_inventory_highlight.py <config>          # stage 1 (court only; or --only <job>)
python okf_inventory_build.py           <config>          # stage 2 (assembles, verifies, deploys)

okf_inventory_highlight.py exits 1 if any pin could not be highlighted (WARN) — never deploy with unresolved WARNs; fix the pin or the source first.

Workflow

  1. Collect the documents. Court: source PDFs (scans must be OCR'd first — run okf-ocr), born-digital PDFs, or web pages. Adjudication/arbitration/counsel: the appendix or paper PDFs themselves (already OCR'd if scanned) — no highlighting needed.
  2. Web pages → verbatim stage: pull the page text, keep it verbatim, record the real URL and fetch date. Never paraphrase inside a production; paraphrase belongs in research notes.
  3. Highlight pins (court only). Pin phrases must be verbatim from the source (verify first; never guess). Whole-paragraph highlighting is the standard: the pin matches a paragraph, the whole text-block rect is highlighted in yellow (1.0, 0.92, 0.25). The extract = the source's own cover page + annotated pages.
  4. QA the extracts. Zero WARNs; every extract opens; annots present on the annotated pages; page 1 of each extract is its cover.
  5. Assemble. Stage 2 builds cover → hyperlinked index → extracts, adds page numbers, writes _paged twin, deploys to deploy_to.
  6. Report. Output path, page count, doc range (doc_start..), annotation count, link count, deploy target.

Rules

  • Never modify production sources. Highlighting writes _highlighted.pdf / _extract.pdf copies only; bundle builds append originals untouched.
  • Verbatim only. Pins and extract text must match the source exactly. Apostrophes: normalise U+2019/U+2018 to ' in BOTH pin and page text (PDFs often use curly quotes); also normalise U+00A0. A WARN means the pin did not match — investigate, never force it.
  • Whole paragraphs, not word-ranges. The extract must carry the source cover page so it is self-describing in the production list.
  • Doc numbering continues from the previous inventory (doc_start); page ranges are computed from actual page counts after the index is laid out (two-pass — single-page docs and index wrapping are the classic off-by-one traps). Adjudication/counsel indexes number from 1 unless continuing an earlier index.
  • Hyperlinks required: index row → extract start; cover → index; each extract cover → its index row. Use PyMuPDF's page key for LINK_GOTO (newer PyMuPDF rejects to). Placeholder rows (no file) get no link — verify the link count equals the number of real extracts.
  • ASCII hyphens in page ranges. En-dashes (U+2013) do not survive the simple-font encoding (they render as a centre dot) — the court and Ipsum exemplars use plain hyphens anyway.
  • Page numbers on every page, centred grey footer (10pt Palatino Linotype — house style; Arial only as a fallback if Palatino is missing).
  • House style: cover/index/footer render in Palatino Linotype (12pt body equivalents; footer 10pt). All example configs carry fictitious parties so they can be copied safely.
  • Deploy discipline. Deploy only when annotation and link counts verify; always refresh the _paged twin; report the deployed byte size.
  • NotebookLM sync (if the matter has one): rebuilding extracts changes staging inputs — run okf_nblm_build.py <matter> --check and rebuild if it exits 1.

Traps (learned; see learnings.md)

  • Edge/Chrome headless --print-to-pdf can hang on this machine — build verbatim web captures with okf_inventory_verbatim.py instead.
  • PowerShell > redirection corrupts Python UTF-8 stdout — use cmd /c python ... > out.txt or write the file from inside Python.
  • lcl4-style two-column criteria pages split paragraphs across text blocks: paragraph merging needs strict x-overlap, and a vertical gap threshold of ~8pt (measured line-gap clusters: 0–7pt intra-paragraph, 12–28pt inter-paragraph).
  • The index page range off-by-one: never assume one index page; count wraps first (see stage 2 pass 1).
  • Section bands are 1-based row positions (at = the extract's position in the extracts list, starting at 1) — they are NOT doc numbers; with doc_start > 1 the band position still refers to list order.
  • Centred cover headings wrap automatically — keep the long "AND IN THE MATTER OF THE JCT…" line as one entry and let the builder wrap; do not hand-split lines.
  • Check for leftover court styling — if an adjudication/arbitration/counsel build renders a 'Pages' column or 'Doc #'/'Index' headers, the index block is missing from the config (defaults are the court layout).