# How Hallmark's Project Memory Uses `.hallmark/log.json` to Track Diversification

> Learn how Hallmark's project memory uses .hallmark/log.json to track diversification by storing run data and enforcing rules across builds. Discover its approach to theme axes and enrichment.

- Repository: [Hassan El Mghari/hallmark](https://github.com/Nutlope/hallmark)
- Tags: how-to-guide
- Published: 2026-08-04

---

**Hallmark stores a lightweight JSON array at [`.hallmark/log.json`](https://github.com/Nutlope/hallmark/blob/main/.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`](https://github.com/Nutlope/hallmark/blob/main/.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`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/log.json) Stores

Hallmark creates [`.hallmark/log.json`](https://github.com/Nutlope/hallmark/blob/main/.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`](https://github.com/Nutlope/hallmark/blob/main/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`](https://github.com/Nutlope/hallmark/blob/main/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"`)

```json
[
  {
    "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`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/log.json) existence. The logic is implemented in [`skills/hallmark/SKILL.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/SKILL.md) §2.5.

### If the File Exists

Hallmark loads the **last 3–5 entries** and applies two guardrails:

1. **Macrostructure diversification**: The candidate macrostructure **must not match any of the last three** entries. If it does, Hallmark rejects it and selects an alternative.

2. **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`](https://github.com/Nutlope/hallmark/blob/main/.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`](https://github.com/Nutlope/hallmark/blob/main/log.json) to establish the exclusion window.

### Step 2: Enforce Macrostructure Variety

```javascript
// 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`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css):

```javascript
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:

```javascript
// 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:

```javascript
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`](https://github.com/Nutlope/hallmark/blob/main/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`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/SKILL.md) | Core diversification workflow, log read/write logic, and guardrail rules |
| [`skills/hallmark/references/custom-theme.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/custom-theme.md) | Log entry schema for custom runs, `theme_axes` and `vibe` field definitions |
| [`skills/hallmark/references/verbs/redesign.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/verbs/redesign.md) | Combined log entry format for multi-page redesigns |
| [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/css/tokens.css) | Axis value storage for catalog theme diversification checks |
| [`.hallmark/log.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/log.json) | Generated project memory file (created after first run) |

---

## Summary

- Hallmark's **[`.hallmark/log.json`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/log.json)** acts 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_axes` and `vibe` directly; **catalog themes** resolve axes via [`site/css/tokens.css`](https://github.com/Nutlope/hallmark/blob/main/site/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`](https://github.com/Nutlope/hallmark/blob/main/.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`](https://github.com/Nutlope/hallmark/blob/main/.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`](https://github.com/Nutlope/hallmark/blob/main/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`](https://github.com/Nutlope/hallmark/blob/main/.hallmark/log.json) is **project-scoped**. Each directory maintains independent memory. Running Hallmark in `/project-a` does not affect diversification rules in `/project-b`.