Why a package
A Sicill-i Ahvâl biography records an official's career in continuous prose. It runs from birth and family through schooling and languages to appointments, pay changes, legal statements and later corrections. Researchers who reuse these accounts need the appointments, dates, pay and schooling separated from the prose, and they need the wording and the evidence kept beside each value. sicilahval gives that work one shared format, so a reading can be checked, shared and used again.
The package keeps three things apart. What the source says explicitly, a proposed inference and an unresolved reading each have their own status. An inference needs a reason and its evidence, and conflicting statements in the source remain visible side by side.
How it works
The work is split between a language model and Python. The model reads and structures the source, guided by the skill. Python prepares the text, checks the result and writes the tables. The model step runs in the assistant a researcher already uses, such as Codex or Claude Code, so the package itself makes no model calls and needs no API key.
Prepare
Python reads the file, splits it into numbered segments and records a SHA-256 checksum of the original.
Read
The model writes each biography as linked facts, events, dates and payments, each with an exact quotation from its segment.
Validate
Python checks the structure, the checksums, every quotation and number, and that each segment has a coverage decision.
Export
The records become CSV tables, JSON and an SQLite database that holds the same cells.
python -m pip install "sicilahval @ git+https://github.com/kansoy/ottoman-personnel-tools.git@v0.1.7"
sicilahval install-skill --target claude --scope usersicilahval prepare records.docx --out work --language en
# The language model reads the text and writes work/records.json.
sicilahval validate work/records.json --source work/source.json
sicilahval export work/records.json --source work/source.json --out dataWhat the checks catch
The checks are mechanical, and they are strict about money. An amount must match whole numbers in its quotation, so a payment of 150 kuruş cannot attach to a source line that says 1150 kuruş. Version 0.1.3 added regression tests for this case, together with decimals, signs and digit grouping.
def _raw_attached(raw: str, quotes: list[str], *, monetary: bool = False) -> bool:
if not monetary:
return any(raw in quote for quote in quotes)
for quote in quotes:
# Check the source's complete digit tokens even when raw includes a
# currency: "150 kuruş" must not attach to "1150 kuruş". A comma or
# full stop extends a number only when another digit follows it.
numbers = list(re.finditer(
r"[+-]?\d{1,3}(?:[ ]\d{3})+(?!\d)(?:[.,]\d+)*|[+-]?\d+(?:[.,]\d+)*", quote))
for match in re.finditer(re.escape(raw), quote):
if not any(number.start() < match.end() and number.end() > match.start()
and (number.start() < match.start() or number.end() > match.end())
for number in numbers):
return True
return FalseA real record
The repository includes two complete register biographies with their archival references. One is the career of Manuk Filcancıyan, whose record states a conversion to Islam with the name Mahmut Süreyya on 4 Rebiülevvel AH 1306. The reading applies the new name from that date only, never to earlier years or to the whole of AH 1306. A single command rebuilds the tables from the reviewed reading.
sicilahval demo --out example-output --language enThe payments table of that example shows how a salary written out in words becomes a number while the original wording stays beside it.
| Date in the record | Year | Event | Amount as written | Kuruş |
|---|---|---|---|---|
| 1 Muharrem 1286 | 1869/70 | Appointment to the Diyarbakır telegraph office | yedi yüz yirmi | 720 |
| 14 Rebiülahir 1287 | 1870/71 | Transfer to the Beyoğlu telegraph centre | dört yüz seksen | 480 |
| 26 Zilkade 1293 | 1876/77 | Rise on reorganisation | yedi yüz elli | 750 |
| 2 Rebiülahir 1297 | 1879/80 | Reduction | altı yüz | 600 |
| 4 Rebiülevvel 1306 | 1888/89 | Rise, the increment | yetmiş beş | 75 |
| 4 Rebiülevvel 1306 | 1888/89 | Rise, the new salary | altı yüz yetmiş beş | 675 |
A fresh reading of both biographies was checked against the supplied text in a second reading. All 28 source segments have coverage decisions, and both exports pass the quotation, reference and CSV to SQLite cell checks. With the 46 local tests of version 0.1.7, they are the checks behind this release.
| Record | Facts | Events | Dates | Payments |
|---|---|---|---|---|
| Manuk Filcancıyan, later Mahmut Süreyya | 33 | 14 | 14 | 6 |
| Zenop Tangaryan | 38 | 21 | 25 | 10 |
Limits
Mechanical validation cannot prove that a reading is historically accurate or complete, so difficult readings still need review against the source. The package does not recognise handwriting. Scans and images need a checked transcription or OCR step before the package can read them. Matching identities across records, coding places and jobs, and building annual panels are separate research tasks that the package leaves to the researcher.
The software, the skill and the documentation are released under the Apache-2.0 licence. Cite it as Kansoy, Fatih. 2026. sicilahval: Evidence-linked extraction of Ottoman personnel records. Version 0.1.7.