old-hands
old-hands
A measured reading pipeline for AI readers of historical handwritten and typed records: parish and Catholic registers, statutory certificates, testaments, war diaries.
It ships as a Python library, a command line, an MCP server (five oldhands_* tools over
stdio, usable from Claude Code, Cursor, or any MCP client) and an agent skill.
Why it exists
An AI reader's bottleneck is perception and calibration, not knowledge. A prose skill full of letterform tables was measured on a blind set of eighteen war-diary cells and had no effect: the only wins came from procedure (a native-resolution crop, a sense-check of a date against its neighbours), and the skill produced a confident wrong answer the baseline had avoided. So this is a procedure the agent RUNS, and reference tables are consulted last.
Status: v0.1.0, measured, no gain claimed. On 2026-09-08 a pre-registered, blind, two-seed A/B on 41 adjudicated cells from Scottish Catholic registers (1821-1869) gave:
Arm | accuracy | Brier (lower is better) | image reads per cell |
no procedure, seed 1 / 2 | 73.2% / 75.6% | 0.202 / 0.201 | 3.3 / 3.6 |
this pipeline, seed 1 / 2 | 73.2% / 73.2% | 0.215 / 0.234 | 7.9 / 7.0 |
The bootstrap interval on the Brier difference includes zero in both seeds. The pipeline did not beat a plain reader on that set, and cost twice the image reads. Most skill-arm losses were format losses (answering the procedure's glyph instead of the whole cell) and the Mc versus M' convention; the genuinely hard cells were missed by every arm. What did hold up: model-free staging so the expensive reader never sees a page, native-raster loading, the per-crop scan ceiling, the leak-checked blind-set builder, the cold-read adjudication protocol (which overturned several prior readings), and one fixed Brier convention. Use it as a harness and a staging tool; do not use it expecting better readings until a later round shows one.
What the pipeline does
inspect: load the page at native resolution (a PDF page yields its embedded raster, never a render), writedisplay.pngat a known scale, report whether the scan is thresholded (contrast views useless).candidate_set: derive the allowed readings from context first: neighbouring dates or entry numbers, a gazetteer, the document class's confusion pairs.evidence: a native crop (no resampling), an upright rotation if the page is sideways, CLAHE when useful, and a same-hand exemplar strip for the contested glyph. Every file lands inside the caller's output directory; a bundle has a size budget; a tiny crop is flaggedBELOW-SCAN-CEILING WxH.compare: two or three candidate readings, each glyph cropped beside its exemplars.commit: a probability per candidate, orCANNOT-READ. A reading cannot exist without the comparison step; a confident choice on disagreeing views is refused.score: accuracy and Brier (one fixed convention, abstention costs half, unreadable truth is scored the same for every arm), with a bootstrap interval on the delta.
Staging is model-free: old-hands stage --cells cells.csv --out DIR writes one small bundle
per cell and a PROMPT_PACK.md that any model (Grok, Sonnet, Haiku, Claude) can read; the
expensive reader only ever sees pre-cut evidence.
Install
uv pip install -e . # library and CLI
uv pip install -e ".[mcp]" # plus the MCP serverMCP client configuration (stdio):
{ "mcpServers": { "old-hands": { "command": "uv", "args": ["run", "--project", "/path/to/old-hands", "old-hands-mcp"] } } }What the tools do and do not enforce
The tools enforce that evidence files exist before a reading is committed and that the reading obeys the calibration rules. They cannot prove the reader looked at the files. A harness that refuses result lines without a resolvable comparison, or a client hook, carries that; say so in any claim.
Tests
uv run python -m unittest discover -s tests -p "test_*.py"Ninety-odd tests on synthetic fixtures only. No real record images, no private paths and no personal data are in this repository, and the calibration fetcher refuses a cache inside it.
Provenance and licence
MIT. The generic skill descends from a private reading discipline; only its hash is recorded
(skills/reading-old-hands/PROVENANCE.yaml) so drift is detectable without exposing it.
Design borrows, licence-clean: the MCP-plus-skill packaging of AI-Riksarkivet/ra-mcp
(Apache-2.0), the HTR-United catalogue vocabulary (CC0), and the test-time augmentation
findings of arXiv:2509.09722 (reimplemented, no code copied).
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Gusmack1/old-hands'
If you have feedback or need assistance with the MCP directory API, please join our Discord server