Designing Your Own Glossia
To construct a custom language for Glossia, you will need three essential components:
- A payload wordlist with weighted parts of speech
- A cover wordlist with weighted parts of speech
- A grammar file (YAML with CFG productions and Montague types)
The grammar must take any payload sequence and return a sequence of cover words plus grammar words that preserves the order of the payload. This ensures payload words appear in the same order in the generated text as in the input. The grammar is deterministic but may accept additional parameters (such as seeds) to guide output variety.
Important Considerations
- Decoding requirement: Others need to decode your messages! They only need the payload wordlist. This is why Glossia includes BIP39 wordlists by default.
- No overlap: The cover wordlist must never contain any words from the payload wordlist. This is enforced at compile time.
- POS weights: Words can have multiple parts of speech with different probabilities.
- Append-only wordlists: Both payload and cover wordlists are append-only:
- You can add new words to the end
- You cannot replace or reorder existing words
- Glossia encodes data by mapping words to their index in the wordlist; changing order breaks decoding
1. Payload Wordlist
The payload wordlist is a YAML file mapping words to their POS tag weights:
abandon:
V: 0.6
N: 0.4
ability:
N: 1.0
able:
Adj: 1.0
about:
Prep: 0.6
Adv: 0.4
Key points:
- Weights should sum to 1.0 per word (Glossia normalizes if needed)
- Valid POS tags:
N,V,Adj,Adv,Prep,Det,Modal,Aux,Cop,To,Conj - Frequency ordering: Custom payload wordlists should be ordered by frequency (most frequent first). BIP39 is frozen in alphabetical order.
2. Cover Wordlist
Same YAML format as the payload wordlist, but for words that fill non-payload slots:
the:
Det: 1.0
refinement: def
a:
Det: 1.0
refinement: indef
is:
Cop: 1.0
after:
Prep: 0.6
Adv: 0.4
Critical requirements:
- Must NOT overlap with the payload wordlist (compile-time enforced)
- Must include function words (determiners, prepositions, conjunctions, copulas, etc.)
- Optional
refinementtags enable grammar-driven morphology (e.g.,Det[def]selects "the",Det[indef]selects "a") - Frequency ordering: Order by frequency (most frequent first), especially for Merkle mode where the first cover word becomes the Merkle root
3. Grammar File
Grammar files are YAML with Montague Grammar types and CFG productions:
grammar:
name: "My Language"
types:
- name: "N"
lambda_type: "e -> t"
- name: "V"
lambda_type: "e -> (e -> t)"
- name: "Adj"
lambda_type: "e -> e"
- name: "Det"
lambda_type: "(e -> t) -> (e -> t)"
- name: "Cop"
lambda_type: "(e -> t) -> (e -> t)"
- name: "Dot"
lambda_type: "t"
rules:
sentence:
lambda: "N"
cfg_productions:
- production: "NP VP Dot"
weight: 0.85
lambda: "N"
- production: "NP V NP Dot"
weight: 0.15
lambda: "N"
noun_phrase:
lambda: "N"
cfg_productions:
- production: "N"
weight: 0.40
lambda: "N"
- production: "Det[def] N"
weight: 0.35
lambda: "Det"
- production: "Det[indef] N"
weight: 0.25
lambda: "Det"
verb_phrase:
lambda: "N"
cfg_productions:
- production: "V NP"
weight: 0.50
lambda: "N"
- production: "Cop Adj"
weight: 0.30
lambda: "N"
- production: "Modal V NP"
weight: 0.20
lambda: "N"
Key syntax:
- Terminal symbols are POS tags:
Det,Adj,N,V,Modal,Aux,Cop,To,Prep,Adv,Conj,Dot,Prefix - Refinement tags in brackets:
Det[def],Det[indef],Det[quant] - Weights determine probabilistic selection
- Rule names map to abbreviations:
noun_phrase->NP,verb_phrase->VP,sentence->S
Optional dialect overlay (dialect.yaml):
dialects:
subject:
rules:
sentence:
cfg_productions:
- production: "NP Cop Adj Dot"
weight: 1.0
Test your grammar:
glossia --show-grammar --dialect body
Complete Workflow
-
Create language directory:
mkdir -p languages/my_language -
Create payload wordlist:
- Start with your word list
- Tag with POS:
cargo run --bin tag_words -- -i words.txt -o words_POS.txt - Generate weights:
cargo run --bin validate_pos_weights -- --file words.yaml --output payload.yaml
-
Create cover wordlist:
- Generate common words:
cargo run --bin get_top_words -- -n 1000 --download-coca -o cover_words.txt - Tag with POS:
cargo run --bin tag_words -- -i cover_words.txt -o cover_POS.txt - Generate weights:
cargo run --bin validate_pos_weights -- --file cover.yaml --output cover.yaml - Overlap is validated automatically at compile time
- Generate common words:
-
Create grammar file:
- Write
grammar.yamlwith types and rules - Optionally add
dialect.yamlfor subject/body variants - Test with
glossia --show-grammar --dialect body
- Write
-
Register the language in the meta-grammar:
The meta-grammar (
languages/meta/) is Glossia's dialect calculus layer. It treats language and format names as payload words so that pipeline instructions like"translate from english into my_language"can be parsed. When you add a new language, you must register it in the meta-layer.-
Append to
languages/meta/payload.yaml: Add your language name with POS weights. Language names typically useN(encoder),Adj(format modifier), andPron(data reference):my_language: N: 0.5 Adj: 0.4 Pron: 0.1The meta payload wordlist must remain a power-of-2 size (it is currently 16 = 2^4). If appending your language would exceed the current power-of-2 boundary, you may need to add additional identifiers to reach the next power of 2, or coordinate with existing entries.
-
Check
languages/meta/cover.yaml: If your language introduces new pipeline verbs, prepositions, or other function words that are not already present in the meta cover wordlist, append them there. For example, if your language requires a new encoding verb or a direction preposition not already covered byencode,decode,translate,from,into, etc., add it to the appropriate section oflanguages/meta/cover.yaml. -
Update
src/pipeline.rs: The pipeline parser has match arms that map meta payload words to concrete language configurations. Add your language tometa_word_to_language():#![allow(unused)] fn main() { "my_language" => Some(("my_language", "body")), }If your language introduces new dialect modifiers, also update
meta_word_to_dialect().
-
-
Test your language:
glossia --random 12 --language my_language --seed 0 -
Test meta-language integration:
glossia --meta "translate from english into my_language" <<< "abandon ability able" -
Verify decoding:
- Extract all words from output
- Filter to only words in your payload wordlist
- Verify the original payload is preserved in order
File Structure
Your language directory should look like:
languages/my_language/
├── grammar.yaml # Grammar rules with Montague types
├── payload.yaml # Payload wordlist with POS weights
├── cover.yaml # Cover wordlist with POS weights
└── dialect.yaml # Optional: dialect overlays (subject/body/poetry)
In addition to the language directory, you must also update these shared files:
languages/meta/payload.yaml # Append your language name as a dialect identifier
languages/meta/cover.yaml # Append any new pipeline function words (if needed)
src/pipeline.rs # Add match arm in meta_word_to_language()
Tools
Glossia includes several utility tools for creating and validating language files.
Word Frequency Tool
Generate word lists from frequency data:
# Download and use COCA word frequency data (recommended)
cargo run --bin get_top_words -- -n 1000 --download-coca -o output.txt
# Re-running reuses the cached download (use --force-download to refresh)
cargo run --bin get_top_words -- -n 1000 --download-coca -o output.txt
# Use a local wordfrequency.info format file
cargo run --bin get_top_words -- -n 1000 --wordfreq lemmas_60k.txt -o output.txt
# Use a CSV frequency file
cargo run --bin get_top_words -- -n 1000 --csv word-freq.csv -o output.txt
The get_top_words tool:
- Downloads word frequency data from wordfrequency.info (COCA corpus)
- Caches the download locally (reuses for 7 days)
- Filters for words with 6 or fewer characters (no punctuation)
- Extracts POS tags when available
- Sorts by frequency and returns the top N most common words
POS Tagging Tool
Assign parts of speech to words using nlprule:
# Tag a word list (one word per line)
cargo run --bin tag_words -- -i input_words.txt -o output_POS.txt
# Use alternative (faster) tagging method
cargo run --bin tag_words -- -i input_words.txt -o output_POS.txt --alternative
POS Weight Generation Tool
Generate POS tag weights from nlprule analysis:
# Generate weights for cover words
cargo run --bin validate_pos_weights -- \
--file languages/english/cover.yaml \
--output cover_nlprule_weights.yaml
# Generate weights for payload words
cargo run --bin validate_pos_weights -- \
--file languages/english/payload.yaml \
--output payload_nlprule_weights.yaml
# Test with limited words (for faster testing)
cargo run --bin validate_pos_weights -- \
--file languages/english/cover.yaml \
--max-words 10 \
--output test_weights.yaml
# Adjust minimum weight threshold and decimal places
cargo run --bin validate_pos_weights -- \
--file languages/english/cover.yaml \
--threshold 0.05 \
--round 2 \
--output cover_weights.yaml
The weight generation tool:
- Tests each word in multiple sentence contexts using nlprule
- Calculates observed POS tag frequencies
- Normalizes weights to sum to 1.0
- Filters out weights below a threshold (default: 0.01)
- Rounds weights to specified decimal places (default: 3)
Weight Cleanup Tool
Remove zero-weighted productions from grammar files:
cargo run --bin cleanup_weights -- --file grammar.yaml --output grammar_clean.yaml
Weight Comparison Tool
Compare POS weight distributions between two wordlist files:
cargo run --bin compare_pos_weights -- \
--file1 payload_old.yaml \
--file2 payload_new.yaml
Workflow: Generate Short Words and Tag Them
A common workflow for building cover wordlists:
# Step 1: Generate shortest words (3-4 characters) from frequency data
cargo run --bin get_top_words -- \
-n 500 \
--download-coca \
--min-length 3 \
--max-length 4 \
--words-only \
-o shortest_words.txt
# Step 2: Tag those words with POS using nlprule
cargo run --bin tag_words -- \
-i shortest_words.txt \
-o shortest_words_POS.txt
Data Sources
The get_top_words tool uses word frequency data from:
- COCA (Corpus of Contemporary American English): Available from wordfrequency.info
- Google Books Ngram: Can process downloaded Ngram 1-gram files
Downloaded data is cached locally as lemmas_60k.txt and reused for 7 days before automatically refreshing.