Language · We run it ourselves
A general-purpose language whose value in this practice is narrow and specific: the reference implementations for reading and writing awkward archive and binary formats — .docx, .xlsx internals, font tables — are written in it.
The language for a script is chosen by asking which ecosystem already contains a correct implementation of the format the script has to produce. For document generation, font compilation, spreadsheet extraction and audio transcription that answer is Python, and for nothing else in the inventory is it. Python here is build-time tooling that emits artefacts, never a runtime — the deployed surface is Node.
01
A .docx file is a ZIP archive of XML parts joined by a relationship graph, and the failure mode of writing one by hand is not a crash. It is a document that opens with a repair prompt, or one where list numbering silently restarts at the third heading. python-docx encodes which parts must exist and how they reference each other; reimplementing that in whatever language the surrounding application happens to use buys nothing and costs the weeks it takes to discover which parts a word processor actually validates.
02
Hyperlinks in an .xlsx do not live in the cell. The cell holds a display string; the target sits in xl/worksheets/_rels/sheetN.xml.rels keyed by a relationship id. Every tool that treats a spreadsheet as a grid of values drops them, which is precisely the data extract-xlsx-links.py exists to recover — the URLs someone pasted into a column years ago, often the only surviving record of where a number came from.
03
Fonts are binary tables, not text. build-fonts.py and build-logo.py in the DYD repositories compile typographic assets ahead of the build rather than at request time, and the same reasoning puts OG image font embedding in Python: a face has to be subset and re-embedded, which means reading and rewriting tables, not templating a string. A language that cannot open the file at byte level is not a candidate for that job regardless of how pleasant it is elsewhere.
04
The audio transcription pipeline is Python because container decoding, resampling and model invocation are all bindings problems and the bindings are there. It is not there for speed. Wall clock is dominated by the model, and the surrounding code does nothing but move buffers, retry on partial input and write out timings — work at which the language is irrelevant and the library availability is decisive.
05
Python is confined to build time. Nothing on datanexus.ae and nothing in the deployed products executes Python on a request; the runtime is Node. This site generates its own PDFs in TypeScript — scripts/build-invoice.mts and scripts/build-proposal.mts — because that layout logic sits beside the site's own types and content, and no Python library removes work the Node PDF tooling does not already do.
06
The rule cuts both ways and mostly cuts against Python. When the advantage would be a single library function, a second toolchain — an interpreter version, a virtual environment, wheels with native extensions, a second image in CI — costs more than the function returns. That is why the repository inventory contains no Python web service and no Python API layer: a language earns entry per problem, not per project, and most problems here do not admit it.
07
These scripts are pure functions from inputs to artefacts, which makes the choice reversible. If the format tooling in another ecosystem catches up, build-fonts.py or extract-xlsx-links.py can be rewritten and deleted without anything at runtime noticing, because nothing at runtime depends on them. A Python service would not have that property, and that asymmetry is the reason the boundary sits where it sits.
An entry that cannot point at something you can open, run or read does not compile. That is a property of the type, not a promise in a paragraph.
Invariant
Every Python script is a second toolchain living beside a TypeScript one, and it breaks at the seam rather than in the code. The artefacts these scripts produce — compiled fonts, generated documents, extracted link tables — are committed outputs, and nothing in the deployed build re-runs the scripts, so the build gates that guard this site (scripts/check-schema.ts, check-markdown.ts, check-knowledge.ts) cannot see when an artefact has drifted from the source it was generated from. A colleague on a different interpreter version, or one missing a wheel with a native extension, cannot regenerate them at all, and discovers this at the worst moment. Below roughly a few hundred lines of glue the arithmetic fails outright: a second lockfile, a second version manager and a second CI image cost more than the library saves, and the correct decision is to write the awkward parsing by hand in the language already present.