How Hallmark's Project Memory Uses `.hallmark/log.json` to Track Diversification
Hallmark stores a lightweight JSON array at .hallmark/log.json and prepends each run's macrostructure, theme axes, and enrichment choices to enforce diversification rules across consecutive builds.
Hallmark's project memory system ensures no two consecutive page generations repeat the same macrostructure or theme combination. This article explains how the .hallmark/log.json file works, what data it captures, and how Hallmark uses it to guarantee visual variety—even when re-running identical briefs.
What .hallmark/log.json Stores
Hallmark creates .hallmark/log.json at the project root after its first successful run. Each entry is a JSON object appended to the front of the array (newest first), following the structure defined in skills/hallmark/SKILL.md §2.5.
Standard Fields (All Runs)
- date: ISO date string (
YYYY-MM-DD) - macrostructure: Selected layout pattern (e.g.,
"Bento Grid","Long Document","Stat-Led") - theme: Catalog theme name (
"Coral","Bloom") or"custom"for user-defined runs - enrichment: Hero enrichment archetype (
"E1 clipped-edge","none", etc.) - brief: One-line summary of the source brief
Custom-Run Additional Fields
When theme: "custom", Hallmark records two extra fields per custom-theme.md §F:
- theme_axes: The three diversification axes as a slash-separated string—
"paper band / display style / accent hue"(e.g.,"light / italic-serif / chromatic-terracotta") - vibe: The user's shorthand vibe phrase (e.g.,
"archival warmth, hand-set, no varnish")
[
{
"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"
}
]
How Hallmark Reads Project Memory
Before selecting any macrostructure or theme, Hallmark checks for .hallmark/log.json existence. The logic is implemented in skills/hallmark/SKILL.md §2.5.
If the File Exists
Hallmark loads the last 3–5 entries and applies two guardrails:
-
Macrostructure diversification: The candidate macrostructure must not match any of the last three entries. If it does, Hallmark rejects it and selects an alternative.
-
Theme diversification: The new theme must differ on at least one axis (paper band, display style, or accent hue) from the most recent entry.
If the File Does Not Exist
Hallmark treats the run as a first run with no constraints, then creates .hallmark/log.json after the build completes with the initial entry.
Diversification Logic in Practice
The diversification system follows a strict read-evaluate-record loop:
Step 1: Load Recent History
Hallmark slices the first 5 entries from log.json to establish the exclusion window.
Step 2: Enforce Macrostructure Variety
// Pseudocode reflecting SKILL.md §2.5 logic
const recentMacros = recent.slice(0, 3).map(e => e.macrostructure);
let candidateMacro = pickMacrostructure();
while (recentMacros.includes(candidateMacro)) {
candidateMacro = pickAlternativeMacrostructure();
}
Step 3: Enforce Theme Variety
For catalog themes, Hallmark reads axis values from site/css/tokens.css:
const prevAxes = getAxesFromTokensCss(recent[0].theme);
const candidateAxes = getAxesFromTokensCss(candidateTheme);
// Must differ on at least one axis
if (axesMatch(prevAxes, candidateAxes)) {
candidateTheme = pickAlternativeTheme();
}
For custom themes, axes are parsed directly from the previous entry's theme_axes string:
// From custom-theme.md §F implementation
const prevAxes = recent[0].theme_axes?.split(' / ');
const candidateAxes = computeCustomAxes(); // e.g., ["light", "italic-serif", "chromatic-terracotta"]
if (prevAxes && candidateAxes.every((a, i) => a === prevAxes[i])) {
// Reject—at least one axis must change
candidateAxes = perturbAxes(candidateAxes);
}
Step 4: Record the Decision
Hallmark prepends the finalized entry:
log.unshift({
date: new Date().toISOString().split('T')[0],
macrostructure: candidateMacro,
theme: candidateTheme,
...(candidateTheme === 'custom' && {
theme_axes: candidateAxes.join(' / '),
vibe: userVibe
}),
enrichment: chosenEnrichment,
brief: briefSummary
});
fs.writeFileSync('.hallmark/log.json', JSON.stringify(log, null, 2));
Multi-Page and Redesign Scenarios
For app-level redesigns, Hallmark writes a single combined entry rather than per-page records. Per skills/hallmark/references/verbs/redesign.md, these entries use "scope": "app" and capture the full macrostructure stamp including nav and footer archetype selections.
Key Source Files
| File | Purpose |
|---|---|
skills/hallmark/SKILL.md |
Core diversification workflow, log read/write logic, and guardrail rules |
skills/hallmark/references/custom-theme.md |
Log entry schema for custom runs, theme_axes and vibe field definitions |
skills/hallmark/references/verbs/redesign.md |
Combined log entry format for multi-page redesigns |
site/css/tokens.css |
Axis value storage for catalog theme diversification checks |
.hallmark/log.json |
Generated project memory file (created after first run) |
Summary
- Hallmark's
.hallmark/log.jsonacts as persistent project memory, storing the most recent 3–5 runs in a front-appended JSON array. - Macrostructure diversification blocks repetition within the last three entries.
- Theme diversification requires at least one axis change (paper band, display style, or accent hue) from the immediate previous entry.
- Custom themes record
theme_axesandvibedirectly; catalog themes resolve axes viasite/css/tokens.css. - The system is route-blind: a custom run following a catalog run (or vice versa) must still satisfy the same axis-difference rule.
Frequently Asked Questions
What happens on the very first Hallmark run?
If .hallmark/log.json does not exist, Hallmark generates without constraints and creates the file afterward with the first entry. The second run then begins enforcing diversification rules.
Can I manually edit .hallmark/log.json?
Yes—the file is standard JSON. Removing entries or changing macrostructure values adjusts what Hallmark considers "recent." However, malformed JSON will cause Hallmark to treat the next run as a fresh start.
How does Hallmark handle theme axes for catalog versus custom themes?
Catalog themes store axis values in site/css/tokens.css; Hallmark looks up the previous theme's axes there. Custom themes embed theme_axes directly in the log entry, so Hallmark parses that string without external lookup.
Does the diversification apply across different project directories?
No—.hallmark/log.json is project-scoped. Each directory maintains independent memory. Running Hallmark in /project-a does not affect diversification rules in /project-b.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →