# How Hallmark Performs Pre-Flight Scanning: A Complete Technical Breakdown

> Discover how Hallmark performs pre-flight scanning. Learn about its efficient caching mechanism for faster analysis and improved developer workflows. Get the technical breakdown.

- Repository: [Hassan El Mghari/hallmark](https://github.com/Nutlope/hallmark)
- Tags: deep-dive
- Published: 2026-08-16

---

**Hallmark performs pre-flight scanning by walking the project source tree once, caching static-analysis data to [`.hallmark/preflight.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/preflight.json), and re-using that cache on subsequent runs unless configuration files have been modified.**

This article explains Hallmark's incremental preprocessing system as implemented in the Nutlope/hallmark repository. The pre-flight scanner serves as the foundation for Hallmark's design-system-aware rendering pipeline, enabling fast, deterministic builds through intelligent caching mechanisms.

## What Pre-Flight Scanning Accomplishes

When Hallmark first processes a project, it needs to understand the codebase structure before rendering any components. The scanner extracts **asset references**, **component usage patterns**, **theme settings**, and **dependency information** from files like [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json) and `tailwind.config.*`. Rather than repeating this expensive analysis on every invocation, Hallmark persists results to a hidden cache.

According to [`skills/hallmark/SKILL.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/SKILL.md) (lines 177-179), this approach transforms a potentially slow filesystem crawl into a near-instant cache lookup for typical development workflows.

## The Four-Stage Pre-Flight Process

### Initial Scan and Cache Creation

The first time Hallmark runs against a project, it executes a full scan. The scanner traverses the source tree, reads relevant configuration files, and builds a comprehensive analysis object. This data includes:

- Installed dependencies from [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json)
- Tailwind theme customizations
- Image asset references
- Component registration patterns

Once collected, the results are serialized to [`.hallmark/preflight.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/preflight.json) in the project root.

```javascript
// Simplified pre-flight generation logic
import { readFileSync, writeFileSync } from 'fs';

function runPreflight() {
  if (!isCacheStale()) {
    console.log('Re-using cached pre-flight data');
    return JSON.parse(readFileSync(preflightPath, 'utf8'));
  }

  console.log('Scanning project for pre-flight data...');
  const data = {
    dependencies: JSON.parse(readFileSync(pkgPath, 'utf8')).dependencies,
    // Additional analysis omitted
  };

  writeFileSync(preflightPath, JSON.stringify(data, null, 2));
  return data;
}

```

### Cache Re-Use on Subsequent Runs

Hallmark optimizes for the common case: multiple invocations against an unchanged codebase. On every run, it compares **modification timestamps (mtimes)** between the cache and primary configuration files. When [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json) and all `tailwind.config.*` files remain unmodified, Hallmark skips the scan entirely and loads [`.hallmark/preflight.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/preflight.json) directly.

This design prioritizes **developer experience**—subsequent renders complete in milliseconds rather than seconds.

### Cache Invalidation Strategy

Stale caches are automatically detected through timestamp comparison. If either [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json) or any Tailwind configuration file has a newer `mtime` than [`.hallmark/preflight.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/preflight.json), Hallmark discards the old cache and re-executes the full scan.

```javascript
// Cache staleness detection
function isCacheStale() {
  if (!fs.existsSync(preflightPath)) return true;
  
  const cacheMtime = statSync(preflightPath).mtimeMs;
  const pkgMtime = statSync(pkgPath).mtimeMs;
  const twMtime = statSync(tailwindPath).mtimeMs;
  
  return pkgMtime > cacheMtime || twMtime > cacheMtime;
}

```

This ensures that **newly added dependencies**, **theme changes**, or **style configuration updates** immediately propagate through the rendering pipeline without manual cache clearing.

### Asset Fallback Resolution

The cached pre-flight data directly powers rendering decisions. As documented in [`skills/hallmark/references/hero-enrichment.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/hero-enrichment.md) (line 30), Hallmark implements a three-tier asset resolution strategy:

1. Attached image files take priority
2. Cached entries from [`.hallmark/preflight.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/preflight.json) serve as secondary sources
3. Placeholder assets provide graceful degradation

```javascript
function getHeroImage(assetPath) {
  const preflight = JSON.parse(readFileSync('.hallmark/preflight.json', 'utf8'));

  if (fs.existsSync(assetPath)) return assetPath;
  if (preflight.heroImage) return preflight.heroImage;
  return '/assets/placeholder.svg';
}

```

Critically, Hallmark **never overwrites cached assets**—the system treats pre-flight data as read-only after initial generation.

## Key Source Files and Their Roles

| File | Purpose |
|------|---------|
| [`skills/hallmark/SKILL.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/SKILL.md) | Defines persistence logic and cache invalidation rules |
| [`skills/hallmark/references/hero-enrichment.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/hero-enrichment.md) | Documents asset handling and fallback behavior |
| [`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js) | Runtime loader that consumes pre-flight JSON |
| [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json) & `tailwind.config.*` | Configuration sources that trigger cache refresh |
| [`.hallmark/preflight.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/preflight.json) | Generated cache file (runtime only) |

## Performance Characteristics

The pre-flight scanning architecture delivers several measurable benefits:

- **First run**: Full scan overhead (acceptable as one-time cost)
- **Typical run**: Sub-millisecond cache load
- **Cache refresh**: Triggered only when configuration changes
- **Disk usage**: Single JSON file, typically under 50KB

This trade-off—accepting initial scan latency for near-zero recurring cost—aligns with Hallmark's target use case: interactive component rendering during development.

## Summary

- Hallmark's **pre-flight scanner** runs once per project to collect static-analysis data
- Results are cached to [`.hallmark/preflight.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/preflight.json) for fast subsequent access
- **Mtime comparison** against [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json) and `tailwind.config.*` enables automatic cache invalidation
- The cache supports **asset fallback chains** that never overwrite stored data
- Core logic is defined in [`SKILL.md`](https://github.com/Nutlope/hallmark/blob/main/SKILL.md) (lines 177-179) with enrichment details in [`hero-enrichment.md`](https://github.com/Nutlope/hallmark/blob/main/hero-enrichment.md)

## Frequently Asked Questions

### How does Hallmark know when to invalidate the pre-flight cache?

Hallmark compares modification timestamps. If [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json) or any `tailwind.config.*` file has been modified more recently than [`.hallmark/preflight.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/preflight.json), the cache is discarded and regenerated. This happens automatically without user intervention.

### Can I manually clear the pre-flight cache?

Deleting the [`.hallmark/preflight.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/preflight.json) file forces a fresh scan on the next invocation. Hallmark does not provide a dedicated CLI flag for cache management—the system relies on automatic invalidation based on file mtimes.

### What happens if a referenced image asset is deleted after the pre-flight scan?

Hallmark's asset resolution implements fallbacks. It first checks for the file directly, then consults the cached pre-flight data, and finally serves a placeholder. The system never corrupts the cache by writing missing asset status back to [`.hallmark/preflight.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/preflight.json).

### Does the pre-flight scanner analyze every file in the project?

The scan targets configuration files and asset references specifically. It does not perform deep static analysis of every source file—instead focusing on [`package.json`](https://github.com/Nutlope/hallmark/blob/main/package.json), Tailwind configurations, and explicitly referenced resources that influence rendering decisions.