How `.hallmark/log.json` Tracks Build Diversification in the Hallmark Project

.hallmark/log.json is a JSON ledger that records every successful build's macrostructure, theme, diversification axes, enrichment, and brief summary, enabling Hallmark to enforce rotation rules across successive builds.

The Nutlope/hallmark repository implements a build diversification system that prevents repetitive designs by consulting a project-level history file. This file—.hallmark/log.json—stores chronological records of previous choices and drives intelligent rotation across macrostructures, themes, and layout components.

The Log File Structure

.hallmark/log.json exists at your project root and contains a JSON array with newest entries first. Each entry captures the essential parameters of a build:

[
  {
    "date": "2026-04-30",
    "macrostructure": "Bento Grid",
    "theme": "Coral",
    "enrichment": "E1 clipped-edge",
    "brief": "Tracejam · SaaS observability"
  }
]

According to skills/hallmark/SKILL.md §2.5, this schema enables Hallmark to compare incoming choices against recent history. The file is created automatically after your first build and updated after each successful run.

How Diversification Logic Reads the Log

When Hallmark initiates a new build, it reads .hallmark/log.json (if present) and applies three rotation constraints:

  1. Macrostructure rotation — The candidate macrostructure must not appear in any of the last 3–5 entries
  2. Theme rotation — The new theme must differ on at least one of three axes from the previous entry (catalog vs. catalog, or custom vs. custom)
  3. Nav/Footer rotation — Navigation and footer archetypes stored in the same stamp must be unique across successive builds

If .hallmark/log.json is missing, Hallmark bypasses these constraints, creates the .hallmark/ directory, and initializes a fresh log after completion.

Custom Theme Entries and Axis Tracking

For custom themes, .hallmark/log.json stores two additional fields so diversification checks can operate without parsing CSS token files:

  • theme_axes: The three axis values as a slash-delimited string
  • vibe: An optional descriptive field
{
  "date": "2026-05-01",
  "macrostructure": "Stat-Led",
  "theme": "custom",
  "theme_axes": "light / italic-serif / chromatic-terracotta",
  "vibe": "archival warmth, hand-set, no varnish",
  "enrichment": "none",
  "brief": "Coffeebox · subscription"
}

As defined in skills/hallmark/references/custom-theme.md §F, this extended schema allows direct axis comparison during the diversification check.

Implementing Log Operations in TypeScript

The following implementation shows how to read .hallmark/log.json and validate diversification constraints:

import { readFileSync, writeFileSync } from 'fs';
import { join } from 'path';

type LogEntry = {
  date: string;
  macrostructure: string;
  theme: string;
  theme_axes?: string;   // only for custom themes
  enrichment: string;
  brief: string;
};

const LOG_PATH = join(process.cwd(), '.hallmark', 'log.json');

/** Load the log, creating an empty array if the file does not exist */
function loadLog(): LogEntry[] {
  try {
    const raw = readFileSync(LOG_PATH, 'utf8');
    return JSON.parse(raw);
  } catch {
    return [];
  }
}

/** Return true if the candidate macrostructure is allowed */
function macrostructureAllowed(candidate: string, recent: LogEntry[]): boolean {
  return !recent.slice(0, 3).some(e => e.macrostructure === candidate);
}

/** Return true if the candidate theme differs on at least one axis */
function themeDiversified(candidate: { name: string; axes?: string }, recent: LogEntry[]): boolean {
  if (!candidate.axes) return true;
  const last = recent[0];
  if (!last || !last.theme_axes) return true;
  
  const candAxes = candidate.axes.split(' / ');
  const lastAxes = last.theme_axes!.split(' / ');
  
  return candAxes.some((a, i) => a !== lastAxes[i]);
}

Appending New Build Records

After a successful build, prepend the entry and maintain a rolling window of history:

function appendLog(entry: LogEntry) {
  const log = loadLog();
  log.unshift(entry);
  const trimmed = log.slice(0, 20);  // retain last 20 builds
  writeFileSync(LOG_PATH, JSON.stringify(trimmed, null, 2), 'utf8');
}

/* Example entry for a catalog theme build */
appendLog({
  date: new Date().toISOString().split('T')[0],
  macrostructure: 'Stat-Led',
  theme: 'Garden',
  enrichment: 'none',
  brief: 'Maple Street Bread · bakery'
});

Key Source Files

File Purpose
skills/hallmark/SKILL.md §2.5–2.6 Documents the diversification algorithm and log schema
skills/hallmark/references/custom-theme.md §F Defines custom theme entry structure with axis tracking
site/css/tokens.css Stores catalog theme axis values for reference
.gitignore Allows .hallmark/ exclusion from version control

Summary

  • .hallmark/log.json serves as the persistent record for build diversification in Hallmark projects
  • Each entry captures date, macrostructure, theme, enrichment, and brief—plus theme_axes for custom themes
  • The diversification engine checks the last 3–5 entries for macrostructure conflicts and requires at least one axis difference for themes
  • The JSON array format with newest-first ordering enables efficient recency-based constraint checking
  • The TypeScript loadLog() pattern provides graceful handling of missing files during first runs

Frequently Asked Questions

What happens on the first build when .hallmark/log.json doesn't exist?

Hallmark skips diversification constraints, creates the .hallmark/ directory automatically, and writes the initial log.json after the build completes. No manual setup is required.

How many previous builds does Hallmark consider for rotation rules?

The macrostructure constraint examines the last 3–5 entries, while theme diversification compares against the immediate previous entry for axis differences. The log retains 20 entries by default.

Can I manually edit .hallmark/log.json to influence future builds?

Yes. The file is plain JSON—modifying macrostructure, theme, or theme_axes values will affect how Hallmark applies diversification rules on the next run. However, manual edits may produce unexpected constraint violations if history appears inconsistent.

What's the difference between catalog and custom theme entries in the log?

Catalog themes store only the theme name and reference site/css/tokens.css for axis values. Custom themes embed theme_axes directly in the log entry and may include an optional vibe field, enabling self-contained diversification checks without external file parsing.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →