Technical specification for creating Horatio .htx Content Packs
A Content Pack (.htx) is a ZIP archive containing liturgical, biblical, or classical texts in a structured format. Horatio loads and indexes these packs for offline reading, full-text search, and calendar-based daily navigation.
Packs are self-contained: each pack bundles its texts, metadata, and code mappings. No external dependencies are required.
Design Principles
Offline-first: All content works without internet connectivity.
Modular: Users install only the languages and texts they need.
Preservation: Focus on languages with declining or halted editorial production.
A .htx file is a standard ZIP archive with this directory layout:
my-pack.htx
manifest.json # Required: pack metadata
codes_map.json # Required: code-to-file mapping
texts/ # Text fragments (BMD or plain)
ps.001.bmd
ps.002.bmd
...
RPL/ # Optional: replacement patterns
MEM;0117.bmd
AL0;0.bmd
AL0;1.bmd
The texts/ directory can use subdirectories for organization (e.g., texts/psalms/, texts/readings/). File paths in codes_map.json are relative to the pack root.
The manifest describes the pack and its contents. All fields marked required must be present.
{
"id": "georgian-breviary-sample",
"version": "1.0.0",
"name": "Georgian Breviary",
"description": "Liturgy of the Hours in Georgian (Mkhedruli script)",
"language": "kat",
"script": "georgian",
"text_direction": "ltr",
"author": "PineSoft",
"period": "Modern",
"genre": "liturgical",
"difficulty": "intermediate",
"fragment_count": 42,
"has_translations": ["lat"],
"has_morphology": false,
"has_audio": false,
"required_fonts": ["NotoSansGeorgian"],
"min_app_version": "1.0.0",
"pack_size_bytes": 85200,
"checksum_blake3": "a1b2c3d4...",
"preservation_status": "vulnerable"
}
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique identifier, kebab-case. Must match the pack's root directory name. |
version | string | Yes | Semantic version (e.g., "1.0.0"). |
name | string | Yes | Human-readable pack name. |
description | string | No | Short description of the pack's contents. |
language | string | Yes | ISO 639-3 language code (e.g., "kat" for Georgian, "cop" for Coptic). |
script | string | Yes | Writing system (e.g., "georgian", "coptic", "syriac"). |
text_direction | string | No | "ltr" (default) or "rtl" for Hebrew, Arabic, Syriac. |
author | string | No | Pack creator or source institution. |
period | string | No | Historical period of the texts. |
genre | string | No | Content genre: "liturgical", "biblical", "classical", "prayer". |
difficulty | string | No | "beginner", "intermediate", or "advanced". |
fragment_count | integer | No | Number of text fragments in the pack. |
has_translations | string[] | No | ISO 639-3 codes of available translation languages. |
has_morphology | boolean | No | Whether morphological annotations are included. |
has_audio | boolean | No | Whether audio recordings are included. |
required_fonts | string[] | No | Font families required to render the texts. Horatio bundles Noto Sans variants. |
min_app_version | string | No | Minimum Horatio version required. |
pack_size_bytes | integer | No | Uncompressed size of the pack in bytes. |
checksum_blake3 | string | No | BLAKE3 hash of the pack for integrity verification. |
preservation_status | string | No | "critical", "endangered", "vulnerable", or "safe". |
For liturgical packs following the CLEDR schema (CatholicOS Liturgical Event Data Registry):
| Field | Type | Description |
|---|---|---|
community_contact | string | Contact for the language community. |
source_institution | string | Institution that curated the texts. |
source | string | Source type: "CRG", "MR", or "LOCALE". |
missal_editions | string[] | Applicable Missale Romanum editions: "mr1970", "mr2002", "mr2008". |
external_ids | object | Cross-references: {"romcal": "...", "litcal_api": "..."}. |
dublin_core | object | Dublin Core metadata for archive interoperability. |
Maps short codes to text files. This file enables calendar-based lookup and navigation.
{
"mapping": {
"ps.001": {
"file": "texts/ps.001.bmd",
"title": "Psalmus 1 — Beatus vir"
},
"ps.002": {
"file": "texts/ps.002.bmd",
"title": "Psalmus 2 — Quare fremuerunt gentes"
},
"0117": {
"file": "texts/sanctorale/0117.bmd",
"title": "S. Antonii Abbatis",
"cledr_id": "anthony_of_egypt_abbot",
"rank": "MEMORIA",
"type": "SANCTORALE"
}
}
}
| Pattern | Usage | Examples |
|---|---|---|
ps.NNN | Psalms | ps.001, ps.150 |
MMDD | Fixed feasts (month-day) | 0117 (Jan 17), 1225 (Dec 25) |
PAS0...PAS7 | Easter and octave | PAS0 = Easter Sunday |
ADV1...ADV4 | Advent Sundays | ADV1 = First Sunday of Advent |
QUA0...QUA6 | Lent | QUA0 = Ash Wednesday |
ORD1...ORD34 | Ordinary Time weeks | ORD1 = Week 1 |
| Field | Required | Description |
|---|---|---|
file | Yes | Path to the text file, relative to pack root. |
title | Yes | Display title for the fragment. |
cledr_id | No | CLEDR canonical identifier (snake_case English). |
rank | No | Liturgical rank: SOLLEMNITAS, FESTUM, MEMORIA, FERIA. |
type | No | TEMPORALE, SANCTORALE, or LOCALE. |
BMD (Bible MarkDown) is a lightweight markup extending Markdown for biblical and liturgical notation. Originally developed for ePrex (2015). Files use the .bmd extension.
| Syntax | Renders As | Description |
|---|---|---|
# Title | Heading (red) | Section heading, level 1 |
## Subtitle | Heading (red) | Section heading, level 2 |
### Sub-subtitle | Heading (red) | Section heading, level 3 |
{Rubric text} | Red italic | Liturgical instruction or direction |
{V.} Text | Versicle | Verse indicator (V./) |
{R.} Text | Response | Response indicator (R./) |
{Ant.} Text | Antiphon label | Antiphon introduction |
| 2-space indent | Continuation | Verse continuation from previous line |
| Syntax | Meaning | Rendering |
|---|---|---|
text * | Flexa (half-verse pause) | Pause point in recitation, asterisk |
text + | Mid-verse pause | Renders as † (dagger/crux) |
The asterisk or plus sign must be preceded by a space and appear at the end of the line.
| Syntax | Renders As | Description |
|---|---|---|
//text// | Italic | Subtitle or emphasis |
$text$ | Bold | Strong emphasis |
^text^ | Superscript | Biblical cross-reference |
{text} | Red text | Inline rubric |
# Psalmus 22
{Ant.} Dominus pascit me, et nihil mihi deerit.
Dominus pascit me, et nihil mihi deerit; *
in pascuis virentibus me collocat,
Ad aquas tranquillitatis conducit me, *
reficit animam meam.
Deducit me per semitas iustitiae *
propter nomen suum.
{V.} Gloria Patri et Filio et Spiritui Sancto.
{R.} Sicut erat in principio et nunc et semper.
For packs containing the Liturgy of the Hours, responsories, or intercessions, BMD provides additional structural markers. These are backward compatible — packs using only basic BMD markup continue to work unchanged.
Antiphons bracket psalms and canticles. Use {Ant|} / {|Ant} to mark the antiphon text block:
{Ant|}
Il Signore è vicino.
{|Ant}
Dominus pascit me, et nihil mihi deerit; *
in pascuis virentibus me collocat,
{Gloria}
{Ant|}
Il Signore è vicino.
{|Ant}
Responsories use {Rsp|} / {|Rsp} for block boundaries and {R*} to mark the repeat portion (distinct from the psalm flexa *):
{Rsp|}
{R.} Mostraci Signore,
{R*} la tua misericordia.
{V.} E donaci la tua salvezza,
{R*} la tua misericordia.
{Gloria}
{R.} Mostraci Signore,
{R*} la tua misericordia.
{|Rsp}
| Marker | Purpose |
|---|---|
{Gloria} | Insert the doxology (locale-specific text inserted by the app) |
{!Gloria} | Suppress the doxology (e.g., Daniel 3:57–88 which has its own) |
This avoids duplicating the Gloria Patri text in every psalm file. The app inserts the correct locale-specific doxology automatically.
Intercessions distinguish celebrant, assembly, and petition parts using {Int|} / {|Int} block boundaries and semantic role markers:
{Int|}
{C.} Supplichiamo Dio nostro Padre:
{A.} Custodisci il tuo popolo, Signore.
{C.} Dio, che hai promesso al tuo popolo un germoglio di giustizia,
{P.} conserva pura e santa la tua Chiesa.
{C.} Apri il nostro cuore all'ascolto della tua parola,
{P.} rendici forti e irreprensibili nella testimonianza della fede.
{|Int}
| Marker | Role | Rendering |
|---|---|---|
{C.} | Celebrant/leader | Regular text with red prefix |
{A.} | Assembly response (fixed refrain) | Bold text with red prefix |
{P.} | Petition continuation | Indented with dash |
Use {Ref ...} to tag explicit biblical references, rendered in superscript rubric style:
{Ref Gen 1, 1-3}
{Ref Sal 62, 2-9}
For self-contained documents representing a complete liturgical hour, use {Hour|} / {|Hour} to wrap the entire hour and {Sect|} to mark sections:
{Hour| Lauds}
{Sect| Introduction}
{V.} O Dio, vieni a salvarmi.
{R.} Signore, vieni presto in mio aiuto.
{Gloria}
{Sect| Psalm 56}
{Ant|}
Pietà di me, o Dio, in te mi rifugio.
{|Ant}
Pietà di me, o Dio, *
in te mi rifugio...
{Gloria}
{Ant|}
Pietà di me, o Dio, in te mi rifugio.
{|Ant}
{Sect| Reading Is 66, 1-2}
{Ref Is 66, 1-2}
Così dice il Signore...
{Sect| Intercessions}
{Int|}
{C.} Supplichiamo Dio:
{A.} Custodisci il tuo popolo.
{|Int}
{Sect| Prayer}
O Dio, creatore e redentore...
{|Hour}
| Marker | Purpose | Category |
|---|---|---|
{Ant|} / {|Ant} | Antiphon block open/close | Antiphon |
{Rsp|} / {|Rsp} | Responsory block open/close | Responsory |
{R*} text | Responsory repeat portion | Responsory |
{Gloria} | Insert Gloria Patri | Doxology |
{!Gloria} | Suppress Gloria Patri | Doxology |
{Int|} / {|Int} | Intercessions block open/close | Intercessions |
{C.} text | Celebrant/leader part | Roles |
{A.} text | Assembly response | Roles |
{P.} text | Petition continuation | Roles |
{Ref ...} | Biblical reference | Reference |
{Hour| name} / {|Hour} | Liturgical hour open/close | Structure |
{Sect| name} | Section within an hour | Structure |
The RPL (Replacement) system allows texts to include placeholders that are filled dynamically based on the liturgical calendar. RPL files live in the RPL/ directory.
| Pattern | Purpose | Example |
|---|---|---|
MEM;MMDD.bmd | Memorial name for date | MEM;0117.bmd (Jan 17 → St. Anthony) |
AL#;0.bmd | Alleluia removed (Lent) | AL0;0.bmd |
AL#;1.bmd | Alleluia present (Easter) | AL0;1.bmd |
Each line contains a token-replacement pair, separated by |:
@MEMORIA@|sant'Antonio abate
@COMMEMORAZIONE@|nella memoria di sant'Antonio
In your BMD texts, use the token (e.g., @MEMORIA@) where the replacement should appear. The app substitutes the token with the replacement at runtime based on the current date.
Individual text files can include optional YAML frontmatter between --- delimiters:
---
title: Psalmus 22
work: Psalterium
language: lat
script: latin
---
# Psalmus 22
Dominus pascit me...
| Field | Description |
|---|---|
title | Display title (overrides codes_map title). |
work | Parent work or collection name. |
language | ISO 639-3 code for this specific fragment. |
script | Writing system for this fragment. |
Use ISO 639-3 codes for language identification. Common codes for Horatio packs:
| Code | Language | Script | Direction |
|---|---|---|---|
lat | Latin | latin | LTR |
ita | Italian | latin | LTR |
kat | Georgian | georgian | LTR |
cop | Coptic | coptic | LTR |
syc | Classical Syriac | syriac | RTL |
heb | Hebrew | hebrew | RTL |
grc | Ancient Greek | greek | LTR |
ell | Modern Greek | greek | LTR |
ara | Arabic | arabic | RTL |
mlt | Maltese | latin | LTR |
gez | Ge'ez (Ethiopic) | ethiopic | LTR |
got | Gothic | gothic | LTR |
hye | Armenian | armenian | LTR |
san | Sanskrit | devanagari | LTR |
rus | Russian | cyrillic | LTR |
chu | Church Slavonic | cyrillic | LTR |
Horatio bundles Noto Sans font variants for the following scripts. If your pack uses a script not listed here, specify the required font in required_fonts.
Bundled: Noto Sans (Latin, Cyrillic, Greek), Noto Sans Arabic, Noto Sans Hebrew, Noto Sans Syriac, Noto Sans Coptic, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Armenian, Noto Sans Devanagari, Noto Sans Gothic.
mkdir my-pack
mkdir my-pack/texts
Start with the manifest template above. Set your id, language, script, and other metadata.
Write your texts as .bmd files using the BMD markup. Place them in the texts/ directory.
Create a mapping entry for each text fragment. The file path is relative to the pack root.
# From the pack directory:
cd my-pack
zip -r ../my-pack.htx manifest.json codes_map.json texts/
Import the .htx file in Horatio using the Pack Manager's "Import .htx" button. Verify that:
Before sharing your pack, verify:
manifest.json has a unique id, correct language (ISO 639-3), and scriptcodes_map.json maps every text filefile paths in codes_map actually exist in the archivefragment_count matches the actual number of entries{}, //, $$, ^^)text_direction is "rtl" for Hebrew, Arabic, Syriacchecksum_blake3.htx file opens successfully in Horatio's Pack ManagerContributing Packs
We welcome contributions of texts in rare and endangered languages. Contact us at [email protected] to discuss inclusion in Horatio's official pack catalog.