← Back to Horatio

Content Pack Format

Technical specification for creating Horatio .htx Content Packs

Overview

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.

Pack Structure

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.

manifest.json

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 Reference

FieldTypeRequiredDescription
idstringYesUnique identifier, kebab-case. Must match the pack's root directory name.
versionstringYesSemantic version (e.g., "1.0.0").
namestringYesHuman-readable pack name.
descriptionstringNoShort description of the pack's contents.
languagestringYesISO 639-3 language code (e.g., "kat" for Georgian, "cop" for Coptic).
scriptstringYesWriting system (e.g., "georgian", "coptic", "syriac").
text_directionstringNo"ltr" (default) or "rtl" for Hebrew, Arabic, Syriac.
authorstringNoPack creator or source institution.
periodstringNoHistorical period of the texts.
genrestringNoContent genre: "liturgical", "biblical", "classical", "prayer".
difficultystringNo"beginner", "intermediate", or "advanced".
fragment_countintegerNoNumber of text fragments in the pack.
has_translationsstring[]NoISO 639-3 codes of available translation languages.
has_morphologybooleanNoWhether morphological annotations are included.
has_audiobooleanNoWhether audio recordings are included.
required_fontsstring[]NoFont families required to render the texts. Horatio bundles Noto Sans variants.
min_app_versionstringNoMinimum Horatio version required.
pack_size_bytesintegerNoUncompressed size of the pack in bytes.
checksum_blake3stringNoBLAKE3 hash of the pack for integrity verification.
preservation_statusstringNo"critical", "endangered", "vulnerable", or "safe".

Optional CLEDR Fields

For liturgical packs following the CLEDR schema (CatholicOS Liturgical Event Data Registry):

FieldTypeDescription
community_contactstringContact for the language community.
source_institutionstringInstitution that curated the texts.
sourcestringSource type: "CRG", "MR", or "LOCALE".
missal_editionsstring[]Applicable Missale Romanum editions: "mr1970", "mr2002", "mr2008".
external_idsobjectCross-references: {"romcal": "...", "litcal_api": "..."}.
dublin_coreobjectDublin Core metadata for archive interoperability.

codes_map.json

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"
    }
  }
}

Code Conventions

PatternUsageExamples
ps.NNNPsalmsps.001, ps.150
MMDDFixed feasts (month-day)0117 (Jan 17), 1225 (Dec 25)
PAS0...PAS7Easter and octavePAS0 = Easter Sunday
ADV1...ADV4Advent SundaysADV1 = First Sunday of Advent
QUA0...QUA6LentQUA0 = Ash Wednesday
ORD1...ORD34Ordinary Time weeksORD1 = Week 1

Entry Fields

FieldRequiredDescription
fileYesPath to the text file, relative to pack root.
titleYesDisplay title for the fragment.
cledr_idNoCLEDR canonical identifier (snake_case English).
rankNoLiturgical rank: SOLLEMNITAS, FESTUM, MEMORIA, FERIA.
typeNoTEMPORALE, SANCTORALE, or LOCALE.

BMD Markup

BMD (Bible MarkDown) is a lightweight markup extending Markdown for biblical and liturgical notation. Originally developed for ePrex (2015). Files use the .bmd extension.

Block Elements

SyntaxRenders AsDescription
# TitleHeading (red)Section heading, level 1
## SubtitleHeading (red)Section heading, level 2
### Sub-subtitleHeading (red)Section heading, level 3
{Rubric text}Red italicLiturgical instruction or direction
{V.} TextVersicleVerse indicator (V./)
{R.} TextResponseResponse indicator (R./)
{Ant.} TextAntiphon labelAntiphon introduction
2-space indentContinuationVerse continuation from previous line

Psalm Notation

SyntaxMeaningRendering
text *Flexa (half-verse pause)Pause point in recitation, asterisk
text +Mid-verse pauseRenders as (dagger/crux)

The asterisk or plus sign must be preceded by a space and appear at the end of the line.

Inline Markup

SyntaxRenders AsDescription
//text//ItalicSubtitle or emphasis
$text$BoldStrong emphasis
^text^SuperscriptBiblical cross-reference
{text}Red textInline rubric

Example BMD File

# 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.

Liturgical Structure Markers

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.

Antiphon Boundaries

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}

Responsory Structure

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}

Gloria Patri

MarkerPurpose
{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 with Roles

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}
MarkerRoleRendering
{C.}Celebrant/leaderRegular text with red prefix
{A.}Assembly response (fixed refrain)Bold text with red prefix
{P.}Petition continuationIndented with dash

Biblical References

Use {Ref ...} to tag explicit biblical references, rendered in superscript rubric style:

{Ref Gen 1, 1-3}
{Ref Sal 62, 2-9}

Hour Structure (Composite Documents)

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}

All Liturgical Markers Reference

MarkerPurposeCategory
{Ant|} / {|Ant}Antiphon block open/closeAntiphon
{Rsp|} / {|Rsp}Responsory block open/closeResponsory
{R*} textResponsory repeat portionResponsory
{Gloria}Insert Gloria PatriDoxology
{!Gloria}Suppress Gloria PatriDoxology
{Int|} / {|Int}Intercessions block open/closeIntercessions
{C.} textCelebrant/leader partRoles
{A.} textAssembly responseRoles
{P.} textPetition continuationRoles
{Ref ...}Biblical referenceReference
{Hour| name} / {|Hour}Liturgical hour open/closeStructure
{Sect| name}Section within an hourStructure

RPL Replacement System

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.

File Naming

PatternPurposeExample
MEM;MMDD.bmdMemorial name for dateMEM;0117.bmd (Jan 17 → St. Anthony)
AL#;0.bmdAlleluia removed (Lent)AL0;0.bmd
AL#;1.bmdAlleluia present (Easter)AL0;1.bmd

RPL File Format

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.

Fragment Frontmatter

Individual text files can include optional YAML frontmatter between --- delimiters:

---
title: Psalmus 22
work: Psalterium
language: lat
script: latin
---

# Psalmus 22
Dominus pascit me...
FieldDescription
titleDisplay title (overrides codes_map title).
workParent work or collection name.
languageISO 639-3 code for this specific fragment.
scriptWriting system for this fragment.

Language & Script Codes

Use ISO 639-3 codes for language identification. Common codes for Horatio packs:

CodeLanguageScriptDirection
latLatinlatinLTR
itaItalianlatinLTR
katGeorgiangeorgianLTR
copCopticcopticLTR
sycClassical SyriacsyriacRTL
hebHebrewhebrewRTL
grcAncient GreekgreekLTR
ellModern GreekgreekLTR
araArabicarabicRTL
mltMalteselatinLTR
gezGe'ez (Ethiopic)ethiopicLTR
gotGothicgothicLTR
hyeArmenianarmenianLTR
sanSanskritdevanagariLTR
rusRussiancyrillicLTR
chuChurch SlavoniccyrillicLTR

Bundled Fonts

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.

Building a Pack

Step 1: Create the Directory Structure

mkdir my-pack
mkdir my-pack/texts

Step 2: Write manifest.json

Start with the manifest template above. Set your id, language, script, and other metadata.

Step 3: Create Text Fragments

Write your texts as .bmd files using the BMD markup. Place them in the texts/ directory.

Step 4: Build codes_map.json

Create a mapping entry for each text fragment. The file path is relative to the pack root.

Step 5: Package as .htx

# From the pack directory:
cd my-pack
zip -r ../my-pack.htx manifest.json codes_map.json texts/

Step 6: Install and Test

Import the .htx file in Horatio using the Pack Manager's "Import .htx" button. Verify that:

Submission Checklist

Before sharing your pack, verify:

Contributing 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.