Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Fira Code — Administrator & Developer Guide

Generated May 2026 from tonsky/FiraCode at d0cf393

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

1. Architecture Overview

Fira Code is a monospaced programming font built on a hybrid Clojure/Python/Shell toolchain. The core intellectual property is a Clojure-based ligature generation engine that reads a Glyphs source file (FiraCode.glyphs), extracts ligature glyph definitions, generates OpenType calt (Contextual Alternates) feature code with priority ordering and conflict-avoidance ignore rules, injects character variant and stylistic set features from .fea source files, and writes the enriched Glyphs file back. Shell scripts then drive Python-based font compilation tools (fontmake, gftools, ttfautohint) to produce distributable OTF, TTF, variable TTF, WOFF, and WOFF2 font files.

The system is designed as a build pipeline, not a runtime application. There is no server, no API, and no persistent process — it takes source input (FiraCode.glyphs + .fea files) and produces font files.

Architecture Diagram

FiraCode.glyphs (Glyphs source)
       │
       ▼
┌──────────────────────────┐
│  Clojure Build Engine    │
│  (clojure/fira_code/)    │
│                          │
│  main.clj ─────────────► Parse .glyphs file
│    ├─ calt.clj           Generate calt ligature rules
│    ├─ classes.clj        Fill glyph classes from classes/*.fea
│    ├─ features.clj       Fill features from features/*.fea
│    ├─ spacers.clj        Add spacer glyphs for ligatures
│    ├─ not_space.clj      Regenerate NotSpace class
│    └─ checks.clj         Validate glyph widths
│                          │
│  Output: enriched .glyphs file
└──────────────┬───────────┘
               │
               ▼
┌──────────────────────────┐
│  Shell Build Pipeline    │
│  (script/)               │
│                          │
│  build.sh ──────────────► Orchestrate all formats
│    ├─ build_otf.sh       fontmake → OTF (6 weights)
│    ├─ build_ttf.sh       fontmake → TTF + ttfautohint
│    ├─ build_variable.sh  fontmake → Variable TTF
│    ├─ build_woff2.sh     woff2_compress → WOFF2
│    └─ build_woff.sh      sfnt2woff-zopfli → WOFF
│                          │
│  Output: distr/{otf,ttf,variable_ttf,woff,woff2}/
└──────────────────────────┘

Note

The Clojure engine and shell build pipeline are decoupled. You can run script/update_glyphs.sh (Clojure-only step) independently of the font compilation scripts. This is useful when iterating on ligature rules without recompiling all font formats.

Component Inventory

Component Path Role
Glyphs source FiraCode.glyphs Master font design file (Glyphs.app format)
Clojure engine clojure/fira_code/ Ligature rule generation, feature injection, glyph manipulation
OpenType features features/*.fea Character variant (cv) and stylistic set (ss) definitions
OpenType classes classes/*.fea Glyph class definitions (brackets, digits, tall chars)
Calt sub-features features/calt/*.fea Additional contextual alternate rules (arrows, dashes, underscores, etc.)
Build scripts script/ Shell/Python scripts for font compilation and release
Distribution distr/ Built font files, CSS, specimen page
Docker build Dockerfile Containerized build environment
Google Fonts QA googlefonts-qa/ Quality assurance checks for Google Fonts submission
Dev environment clojure/user.clj Clojure REPL configuration with hot-reload

Technology Stack

Technology Version Purpose
Clojure (via deps.edn) Ligature generation engine
Python 3.x Font compilation orchestration, release automation
fontmake 3.11.1 Glyphs → OTF/TTF/Variable compilation
glyphsLib 6.12.7 Glyphs file format parsing (Python library)
gftools 0.9.993 Google Fonts tools (metadata fixes, hinting)
fontbakery 1.1.0 Font quality assurance checks
ufo2ft 3.7.0 UFO to font compilation
uharfbuzz 0.53.3 HarfBuzz shaping engine bindings
ttfautohint system TrueType auto-hinting
woff2 system WOFF2 compression
sfnt2woff-zopfli system WOFF compression with Zopfli
Docker optional Containerized builds
npm via package.json Web distribution (package version 6.2.0)

2. System Requirements

Build Environment (Font Compilation)

Requirement Detail
Clojure JDK + Clojure CLI (deps.edn-based project)
Python 3.x with pip
System packages (Linux) pkg-config, zlib1g-dev, ttfautohint, woff2, sfnt2woff-zopfli
System packages (macOS) pkg-config, zlib, ttfautohint, woff2, sfnt2woff-zopfli (via Homebrew)
Disk ~500 MB for build artifacts

Bootstrap Scripts

Linux:

script/bootstrap_linux.sh

This runs:

sudo apt-get update
sudo apt-get install -y pkg-config zlib1g-dev ttfautohint woff2 sfnt2woff-zopfli
pip install -r requirements.txt

macOS:

script/bootstrap_macos.sh

This runs:

brew install python@3.12
python3.12 -m venv venv
source venv/bin/activate
brew install pkg-config zlib ttfautohint woff2
brew tap bramstein/webfonttools
brew install sfnt2woff-zopfli
pip install -r requirements.txt

Important

The macOS bootstrap creates a Python virtual environment at venv/. All subsequent build scripts check for venv/ and activate it automatically ([ -d venv ] && source venv/bin/activate).

Python Dependencies

From requirements.txt:

Package Version Purpose
fontmake 3.11.1 Font compilation from Glyphs source
glyphsLib 6.12.7 Glyphs file format I/O
gftools 0.9.993 Google Fonts tooling
fontbakery 1.1.0 Font QA validation
ufo2ft 3.7.0 UFO → OpenType compilation
uharfbuzz 0.53.3 HarfBuzz shaping bindings

3. Configuration Reference

Environment Variables

Variable Type Default Description Required?
FIRACODE_GLYPHS_FILE string FiraCode.glyphs Path to the Glyphs source file No
FIRACODE_FAMILY_NAME string Fira Code Font family name in output No
GITHUB_REF string (none) Git tag reference for version detection (e.g., refs/tags/6.2) CI only
GITHUB_BASIC string (none) Base64-encoded user:token for GitHub API auth Release only
API_TOKEN string (none) GitHub API token (alternative to GITHUB_BASIC) Release only
GITHUB_TOKEN string (none) GitHub token (alternative to API_TOKEN) Release only
GITHUB_REPOSITORY string tonsky/FiraCode GitHub repo for release target Release only

Important

Release authentication requires exactly one of GITHUB_BASIC, API_TOKEN, or GITHUB_TOKEN. If none is set, the release script raises Exception: Missing API_TOKEN or GITHUB_TOKEN.

Build Script Flags

The main build orchestrator script/build.sh accepts:

Flag Alias Argument Description
-f --features Comma-separated list Bake specific features into the font (e.g., cv01,cv02,ss01)
-w --weights Comma-separated list Build only specified weights (default: all 6)
-n --family-name String or features Custom family name; features appends feature list to name
-g --generate-glyphs-only (none) Generate enriched .glyphs file only, skip font compilation

Configuration Files

File Format Purpose
FiraCode.glyphs Glyphs.app plist-like Master font source (all glyphs, layers, metrics, features)
deps.edn EDN Clojure dependency and alias configuration
package.json JSON npm package metadata (version 6.2.0, SIL OFL-1.1 license)
requirements.txt pip Python build tool dependencies
Makefile Make Build automation targets
Dockerfile Docker Containerized build environment

OpenType Feature Files

Character Variants (features/cv01.fea – features/cv32.fea)

32 individual character variant feature files. Each defines an OpenType cv feature that substitutes a default glyph with an alternate form. These are independent toggles — users can enable any combination.

Stylistic Sets (features/ss01.fea – features/ss10.fea)

10 stylistic set feature files. Each defines an OpenType ss feature with a descriptive label (stored in the labels metadata with language: dflt). Stylistic sets group related alternate glyphs for batch activation.

Note

Each .fea file may include a header comment line ### Name which becomes the feature's display name in font selection UIs. The build engine (features.clj) extracts this header for ss features and stores it as a label.

Additional Feature Files

File Feature Tag Description
features/onum.fea onum Old-style (lowercase) numerals
features/zero.fea zero Slashed/dotted zero alternate

Calt Sub-Features (features/calt/)

File Purpose
center.fea Centering rules for specific ligature combinations
conj_disj.fea Conjunction/disjunction operator ligatures
cross.fea Cross-shaped operator ligatures
dashes.fea Dash and hyphen sequence ligatures
equal_arrows.fea Equal-sign arrow ligatures (==>, =>>, etc.)
fi_fl.fea Classic fi/fl typographic ligatures
greek.fea Greek letter-related rules
hyphen_arrows.fea Hyphen-based arrow ligatures (-->, ->>, etc.)
match_case.fea Case-matching rules
numbersigns.fea Hash/numbersign sequence handling
underscores.fea Underscore sequence ligatures

Glyph Classes (classes/)

File Class Name Contents
ClosingBracket.fea ClosingBracket Closing bracket glyphs
Digit.fea Digit Decimal digit glyphs (0–9)
DigitTosf.fea DigitTosf Tabular/oldstyle figure digit variants
HexDigit.fea HexDigit Hexadecimal digit glyphs (0–9, a–f, A–F)
OpeningBracket.fea OpeningBracket Opening bracket glyphs
Tall.fea Tall Tall character glyphs (for vertical metrics)

4. Deployment & Scaling

Standard Build

# 1. Bootstrap environment (one-time)
script/bootstrap_linux.sh   # or bootstrap_macos.sh

# 2. Update Glyphs file with generated features
script/update_glyphs.sh

# 3. Build all formats
cd script && ./build.sh

Build output structure:

distr/
├── otf/Fira Code/
│   ├── FiraCode-Light.otf
│   ├── FiraCode-Regular.otf
│   ├── FiraCode-Retina.otf
│   ├── FiraCode-Medium.otf
│   ├── FiraCode-SemiBold.otf
│   └── FiraCode-Bold.otf
├── ttf/Fira Code/
│   └── (same 6 weights as .ttf)
├── variable_ttf/Fira Code/
│   └── FiraCode-VF.ttf
├── woff/Fira Code/
│   └── (5 weights, no Retina)
├── woff2/Fira Code/
│   └── (5 weights, no Retina)
├── fira_code.css
├── specimen.html
└── README.txt

Note

The Retina weight is deliberately excluded from WOFF and WOFF2 output — it is removed after the conversion step in build_woff.sh and build_woff2.sh.

Docker Build

script/build_docker.sh

This builds a Docker image from the repo's Dockerfile and runs the build pipeline inside a container with the repo mounted at /opt/FiraCode. All output goes to the distr/ directory on the host.

Custom Feature Builds

Build a variant with specific features baked into the calt table:

cd script
./build.sh -f cv01,cv02,ss03 -n "Fira Code Custom" -w Regular,Bold

This:

  1. Copies FiraCode.glyphs to a temp file
  2. Runs bake_in_features.sh to inject the specified feature code into the calt feature
  3. Optionally renames the font family
  4. Compiles only the specified weights

Tip

Use -g (generate glyphs only) for quick iteration when developing new features — it skips the slow font compilation step and outputs only the enriched .glyphs file.

Release Process

The release script (script/release.py) handles:

  1. Packaging distr/ into a versioned ZIP (Fira_Code_v{version}.zip)
  2. Creating a GitHub release with the ZIP attached
  3. Placeholder hooks for npm, Homebrew, Scoop, and Google Fonts publishing (currently skipped)
python3 script/release.py --version 6.2

Warning

The release script requires network access and valid GitHub authentication. The npm_publish, update_homebrew, update_scoop, and update_google_fonts functions are currently stubs that print "Skip" — manual publishing is required for those channels.

Version Management

Update the font version in the Glyphs source:

python3 script/update_version.py --version 6.3

This modifies versionMajor and versionMinor fields in FiraCode.glyphs.

5. Operations

Build Pipeline Scripts

Script Purpose Dependencies
script/build.sh Master orchestrator — compiles all formats All build tools
script/build_otf.sh Compile OTF static fonts fontmake
script/build_ttf.sh Compile TTF static fonts + auto-hint fontmake, ttfautohint
script/build_variable.sh Compile variable TTF fontmake, gftools
script/build_woff.sh Convert TTF → WOFF sfnt2woff-zopfli
script/build_woff2.sh Convert TTF → WOFF2 woff2_compress
script/bake_in_features.sh Inject feature code into calt in .glyphs file sed, grep
script/update_glyphs.sh Run Clojure engine to regenerate features Clojure
script/update_version.py Update font version numbers Python
script/release.py Package and publish release Python, GitHub API
script/package.sh Create distribution ZIP zip
script/clean.sh Remove all built artifacts from distr/ (none)
script/bootstrap_linux.sh Install build deps on Linux apt, pip
script/bootstrap_macos.sh Install build deps on macOS Homebrew, pip
script/repl.sh Start Clojure REPL for development Clojure

Tip

The Clojure REPL (script/repl.sh) starts a dev server with hot-reload via clj-reload. The clojure/user.clj namespace configures pretty-printing and error formatting automatically. Call (reload) in the REPL to pick up changes without restarting.

Monitoring Build Health

The Clojure engine emits diagnostic messages during processing:

Parsing 'FiraCode.glyphs'...
  generated calt: XX pairs, XX triples, XX quadruples, XX total
  replacing feature ss01 with XX lines
  appending to feature calt XX lines
  regenerated NotSpace: XXXX glyphs
  added glyphs: X.spacer Y.spacer ...
WARN glyph 'X' has unexpected width=YYY
Saving 'FiraCode.glyphs'...

Note

Width warnings (WARN glyph ... has unexpected width) indicate glyphs that are not 0-width (non-exporting) or 1200 units wide (standard monospace width). These are informational — the font will still build, but mismatched widths can cause alignment issues in monospace contexts.

Variable Font Build Details

The variable font build (build_variable.sh) includes special handling:

  1. Creates a temp copy of the Glyphs file
  2. Disables the Retina master (exports = 0) via awk injection — Retina is excluded because it is not on the interpolation axis
  3. Runs fontmake with -o variable flag
  4. Applies post-processing fixes:
    • gftools fix-nonhinting — fixes non-hinting metadata
    • gftools fix-gasp — fixes grid-fitting and scan-conversion procedure table

Clean Build

script/clean.sh

Removes distr/ttf, distr/variable_ttf, distr/woff2, and distr/woff directories. OTF output is not cleaned (it lives in distr/otf).

6. Performance

Build Times

Font compilation is CPU-bound. The heaviest steps are:

  1. fontmake compilation — compiling each weight from Glyphs source to OTF/TTF. Each weight takes 10–30 seconds depending on hardware.
  2. ttfautohint — auto-hinting each TTF weight adds 5–15 seconds per weight.
  3. Variable font compilation — single pass but produces a larger, more complex file.
  4. WOFF/WOFF2 compression — relatively fast (seconds per file).

Total build time for all formats: approximately 3–10 minutes depending on hardware.

Optimization: Partial Builds

Use --weights to compile only the weights you need during development:

./build.sh -w Regular

Use --generate-glyphs-only to skip font compilation entirely when iterating on ligature rules:

./build.sh -g

7. Security

Supply Chain

  • All Python dependencies are pinned to exact versions in requirements.txt
  • The googlefonts-qa/scripts/requirements.txt uses unpinned versions and a git dependency (git+https://github.com/googlefonts/gftools.git) — this is only for QA, not production builds

Warning

The main requirements.txt pins exact versions, but googlefonts-qa/scripts/requirements.txt does not. If running Google Fonts QA checks, be aware that unpinned dependencies may introduce breaking changes.

Release Authentication

The release script supports three authentication methods:

  1. GITHUB_BASIC — Base64-encoded username:token (Basic auth)
  2. API_TOKEN — GitHub personal access token
  3. GITHUB_TOKEN — GitHub Actions automatic token

All are read from environment variables. No credentials are stored in the repository.

Caution

The GITHUB_BASIC method transmits credentials in Base64 (not encrypted). Prefer GITHUB_TOKEN (short-lived, scoped) when running in GitHub Actions, or API_TOKEN with minimal scopes for manual releases.

License

SIL Open Font License 1.1 — permits use, modification, and redistribution with attribution. The license is in the LICENSE file at the repo root.

8. Developer Internals

Repository Structure

tonsky/FiraCode/
├── FiraCode.glyphs          Master font source file
├── Dockerfile               Docker build environment
├── Makefile                 Build automation
├── deps.edn                Clojure dependencies
├── package.json            npm package (v6.2.0)
├── requirements.txt        Python build dependencies
├── LICENSE                 SIL OFL-1.1
├── README.md               Project readme (+ CN, JA, ES, PT translations)
├── CHANGELOG.md            Version history
├── AUTHORS                 Contributors
│
├── clojure/
│   ├── user.clj            Dev REPL config (hot-reload, pretty-print)
│   └── fira_code/
│       ├── main.clj        Entry point — orchestrates full pipeline
│       ├── calt.clj        Ligature rule generation (priorities, ignores, conflict avoidance)
│       ├── checks.clj      Glyph width validation
│       ├── classes.clj     Glyph class injection from .fea files
│       ├── coll.clj        Collection utility functions
│       ├── features.clj    OpenType feature injection from .fea files
│       ├── files.clj       File finding utilities
│       ├── glyphs.clj      Glyphs file parser/serializer (custom recursive descent)
│       ├── not_space.clj   NotSpace class regeneration
│       ├── spacers.clj     Spacer glyph generation for ligatures
│       └── time.clj        UTC timestamp formatting
│
├── classes/                Glyph class definitions (.fea)
├── features/               Character variants + stylistic sets (.fea)
│   └── calt/              Additional contextual alternate rules
├── script/                 Build and release scripts
├── distr/                  Built font distribution
├── extras/                 Marketing images, logo, specimens
├── docs/                   Performance documentation
└── googlefonts-qa/         Google Fonts submission QA

Module Reference

clojure/fira_code/main.clj — Entry Point

The -main function orchestrates the full Clojure pipeline:

  1. Load and parse FiraCode.glyphs via glyphs/load
  2. Extract all ligature definitions (glyphs ending in .liga that are exported)
  3. Split ligature names on _ to get glyph sequences (e.g., dash_greater_greater.liga → ["dash" "greater" "greater"])
  4. Apply transformations in order:
    • calt/replace-calt — generate and inject calt feature code
    • classes/fill-all — load class definitions from classes/*.fea
    • features/fill-all — load feature definitions from features/*.fea + append calt sub-features
    • spacers/add-spacers — create spacer glyphs for ligature rendering
    • not-space/regen-not-space — rebuild the NotSpace glyph class
    • checks/widths — validate all glyph widths
  5. Save the enriched .glyphs file

clojure/fira_code/glyphs.clj — Glyphs File Parser

A complete recursive-descent parser for the Glyphs.app file format (a plist-like syntax with { key = value; } maps and ( item, item ) lists). Key details:

  • Parsing: Character-by-character state machine using mutable atoms (*str, *pos)
  • Data model: Uses flatland.ordered.map to preserve key insertion order (critical for reproducible output)
  • Serialization: Round-trip capable — parse → modify → serialize produces valid Glyphs files
  • Escape handling: Supports \" and \\ in quoted strings
  • Type inference: Integers (-?[1-9][0-9]*), floats (-?[0-9]+\.[0-9]+), keywords ([a-zA-Z][a-zA-Z.0-9]*), and bare strings
  • Special cases: .appVersion is always quoted (per glyphsLib compatibility); stemValues uses a specific list format

clojure/fira_code/calt.clj — Ligature Rule Engine

The core ligature generation module. Key concepts:

Priority system: Ligatures are sorted by priority before rule generation. Lower priority numbers are processed first:

  • Priority 0: <|> (pipe operators with angle brackets)
  • Priority 1: Single/multi-bar-angle combinations (|>, <|, ||>, <||, |||>, <|||)
  • Priority 2: Repeated operators (<<, >>, ||, <<<, >>>, |||)
  • Default (MAX_VALUE): All other ligatures, sorted by length (longer first), then alphabetically

Ignore rules: Prevent false ligatures in specific contexts. The ignores map defines context-sensitive exclusions keyed by ligature glyph sequence. Examples:

  • /* */ sequences prevent internal false ligatures
  • :: prevents ligation before < or > (issue #1061)
  • [== ==] bracket-equality patterns suppressed (issues #948, #968)
  • =:=, =!= prevented from double-ligating (issue #346)
  • <||> handled as a special four-glyph case (issue #621)
  • {|}, [|] bracket-pipe suppressed (issue #593)
  • //= suppressed (issue #816)

Ignore prefixes: A general mechanism (gen-ignore-prefixes) that prevents ligatures from triggering when preceded by specific character sequences. This handles:

  • Regex lookahead: (?:, (?=, (?<=, (?!, (?<! (issues #578, #624)
  • PHP embed: <?= (issue #850)

Rule generation (liga->rule): Generates OpenType lookup blocks for 2, 3, 4, and 5-glyph ligatures using a spacer-based substitution chain. The algorithm:

  1. Replace rightmost glyph with the ligature glyph
  2. Replace intermediate glyphs right-to-left with spacer glyphs
  3. Replace leftmost glyph with its spacer

Skip-ignores and manual sets: Some ligatures skip ignore generation (skip-ignores? set: <*>, <+>, <$> combinations per issue #410) or are marked manual and excluded from auto-generation (/\, \/).

clojure/fira_code/features.clj — Feature Injection

Two-phase feature loading:

  1. append-calt: Reads all .fea files from features/calt/, trims whitespace, and appends to the existing calt feature code
  2. fill-features: Reads each .fea file from features/, parses the header comment for a display name (### Name), creates a feature entry with tag and optional label, then inserts or replaces it in the font

For ss (stylistic set) features, the header name is stored as a labels entry with language: dflt — this becomes the user-visible feature name in font selection UIs.

clojure/fira_code/spacers.clj — Spacer Glyph Management

Ligatures require spacer glyphs to maintain monospace alignment. For each unique glyph name in any ligature, a corresponding .spacer glyph is needed. The spacer is a zero-content glyph with:

  • Width: 1200 (standard monospace cell width)
  • Two layers: Light and Bold (keyed by UUID)
  • Color: 3 (visual marker in Glyphs.app)

The module diffs existing spacers against needed spacers and only adds missing ones.

clojure/fira_code/checks.clj — Width Validation

Validates that all exported glyphs have consistent widths across layers. Acceptable widths are:

  • "0" or 0 — zero-width (combining marks, etc.)
  • 1200 — standard monospace width

Warnings are emitted for:

  • Glyphs with different widths across layers (Light/Regular/Bold inconsistency)
  • Glyphs with unexpected widths (not 0 or 1200)

clojure/fira_code/glyphs.clj — Weight Constants

Three master weights are defined by UUID:

Weight UUID
Light B67F0F2D-EC95-4CB8-966E-23AE86958A69
Regular UUID0
Bold 4B7A3BAF-EAD8-4024-9BEA-BB1DE86CFCFA

These UUIDs are used to identify layers in the Glyphs source file.

script/build.sh — Build Orchestrator

The main build script:

  1. Parses CLI flags (-f, -w, -n, -g)
  2. Copies FiraCode.glyphs to a temp file (avoids mutating the original)
  3. If features specified: runs bake_in_features.sh to inject them
  4. If custom family name: rewrites familyName in the temp file via awk
  5. Saves the custom .glyphs file as {Family Name}.glyphs
  6. Unless -g flag: runs all format-specific build scripts sequentially
  7. Cleans up temp files

script/bake_in_features.sh — Feature Injection

Injects feature code directly into the calt section of the .glyphs file via text manipulation:

  1. For each specified feature name, reads the corresponding .fea file from features/
  2. Strips lookup wrappers, comments, and blank lines
  3. Locates the calt feature declaration line in the .glyphs file
  4. Injects the extracted code before the closing delimiter via sed

script/common.py — Version Helper

Resolves version from two sources (in order):

  1. --version CLI argument
  2. GITHUB_REF environment variable (strips refs/tags/ prefix)

Raises Exception: Can't identify version if neither source provides a version.

script/release.py — Release Pipeline

  1. package(version) — creates Fira_Code_v{version}.zip from distr/ contents
  2. github_release(version) — creates a GitHub release and uploads the ZIP
  3. npm_publish, update_homebrew, update_scoop, update_google_fonts — all currently stubs ("Skip")

The @log_errors decorator wraps each publish step so failures in one channel do not block others.

Code Patterns and Conventions

Clojure conventions:

  • Namespaces match directory structure (fira-code.calt → clojure/fira_code/calt.clj)
  • Entry points use -main convention
  • Ordered maps (flatland.ordered.map) used throughout for deterministic output
  • String-heavy OpenType feature code generation via str/join and str/replace with regex digit substitution
  • Functional pipeline style: (-> font transform1 transform2 ...) threading macro

Shell conventions:

  • All scripts use set -o errexit -o nounset -o pipefail (strict mode)
  • All scripts cd to repo root via cd "$(dirname "$0")/.."
  • Virtual environment auto-activation: [ -d venv ] && source venv/bin/activate
  • Environment variables with defaults: ${FIRACODE_FAMILY_NAME:-"Fira Code"}

Python conventions:

  • Minimal dependencies — uses only stdlib (argparse, os, re, subprocess, urllib, zipfile, json, glob)
  • common.py shared module for version resolution
  • @log_errors decorator pattern for non-critical release steps

Google Fonts QA

The googlefonts-qa/ directory contains:

  • METADATA.pb — Google Fonts metadata in Protocol Buffer text format
  • gfonts-description.html — HTML description for Google Fonts listing
  • checks/ — fontbakery check results (.checks.md files) for static and variable fonts
  • notes/ — QA notes with visual comparison screenshots
  • scripts/ — QA-specific build and check scripts (separate requirements.txt)

Testing

The Clojure engine includes a width-checking module (checks.clj) that validates all exported glyphs at build time. There is no formal test suite — the build pipeline itself serves as an integration test (compilation failures indicate regressions).

The script/check and script/check_widths scripts provide additional validation:

  • check — runs general font validation
  • check_widths — verifies monospace width consistency

Potential Improvements

Based on source analysis:

  1. Variable font hinting: The build_variable.sh script contains a TODO noting that TTFautohint-VF support is needed for better variable font hinting
  2. npm/Homebrew/Scoop publish automation: The release script has stub functions for these channels — automating them would streamline releases
  3. Release script modernization: Uses urllib.request for GitHub API; migrating to requests or gh CLI would simplify auth handling
  4. CI/CD integration: Version detection relies on GITHUB_REF environment variable, suggesting GitHub Actions usage, but no workflow files are present in the repo
  5. OTF not cleaned by clean.sh: The clean script removes TTF, variable TTF, WOFF, and WOFF2 but leaves OTF — likely intentional but undocumented
  6. fontbakery QA checks are dated: The check markdown files in googlefonts-qa/checks/ appear to be point-in-time snapshots, not part of an automated pipeline

Contributing

The project uses a Clojure development workflow:

  1. Start the REPL: script/repl.sh
  2. Edit Clojure source files
  3. Call (reload) in the REPL to pick up changes (via clj-reload)
  4. Run the pipeline: (fira-code.main/-main) or script/update_glyphs.sh
  5. Build fonts: cd script && ./build.sh

The clojure/user.clj dev namespace installs:

  • hashp — debug printing (#p reader tag)
  • print — pretty-printed output
  • error — enhanced error formatting

9. Integration Points

npm Distribution

The package.json defines:

  • Package name: firacode
  • Version: 6.2.0
  • Main entry: distr/fira_code.css
  • Files included: distr/ directory only
  • License: OFL-1.1

After npm install firacode, consumers access font files at node_modules/firacode/distr/.

Google Fonts

Fira Code is distributed via Google Fonts. The googlefonts-qa/ directory contains all assets for the submission:

  • METADATA.pb defines the font family metadata
  • gfonts-description.html provides the HTML description
  • QA checks validate compliance with Google Fonts standards

Homebrew / Scoop / Chocolatey

Distribution through OS-level package managers is handled externally:

  • Homebrew: homebrew-cask-fonts repository
  • Scoop: scoop-nerd-fonts bucket
  • Chocolatey: community-maintained package

The release script has placeholder hooks for updating these, but they currently print "Skip" and require manual intervention.