Diary
The single most visible output of the simulation. Every NPC writes one entry per day.
Why Diaries?
The diary is the player's window into NPC inner life. It's:
- 📖 The primary content the player reads
- 🪞 The most natural way to express emotion and reflection
- 🎭 The richest place to observe personality and memory in action
If the diary is good, the simulation is good. If the diary is bad, no amount of underlying AI sophistication matters.
When is it written?
Every day, at 22:00 in-game time.
This is after dinner but before sleep. The NPC is alone at home, winding down. It's a natural moment for reflection.
What Goes Into a Diary Entry
Inputs
The Prompt Structure
const prompt = `
You are ${npc.name}, a ${npc.age}-year-old ${npc.profession}.
Your personality: ${formatPersonality(npc.personality)}.
Your home: ${npc.home}.
Your family: ${formatFamily(npc.family)}.
Today is Day ${worldTime.day} (${worldTime.season}).
The weather today was: ${todayWeather}.
Your mood today was mostly: ${avgMood}.
Today's events (compressed):
${todayEvents}
Recent memories worth noting:
${recentMemories}
You are writing tonight's diary entry. It should be:
- 2-4 paragraphs
- Written in first person
- In your voice (${npc.styleHints})
- Reflecting on the day honestly
- Mentioning any people you interacted with
- Ending with a brief thought about tomorrow
Important:
- Do NOT invent events that didn't happen.
- Do NOT be overly dramatic. Ordinary days are fine.
- Be true to your personality.
- Keep it under 400 words.
Begin:
`;Style Hints
Each NPC has style hints that bias the LLM's output:
| NPC | Style Hint |
|---|---|
| Margaret | "Wry, observational, slightly melancholic" |
| Tom | "Practical, laconic, occasional dry humor" |
| Eleanor | "Warm, slightly gossipy, motherly" |
| Sam | "Boisterous, fond of drink references" |
These hints come from the NPC's personality + custom traits.
Length
- Target: 200-400 words
- Hard cap: 500 words (enforced by prompt + post-processing)
- Minimum: 100 words (don't allow "Today was fine." one-liners)
If the LLM produces too short or too long an entry, the system retries with adjusted prompt instructions.
Tone Calibration
To prevent the "AI-drama" problem (every diary being a rollercoaster), we calibrate tone:
const toneCalibration = {
baseline: 'ordinary day, modest reflection',
overrides: {
if (avgMood === 'happy' && intensity < 0.6) return 'quietly content';
if (avgMood === 'sad' && intensity < 0.6) return 'slightly subdued';
if (avgMood === 'angry' && intensity < 0.6) return 'mildly irritated';
}
};This goes into the prompt as:
"Tone: ${toneCalibration}"
Validation
After generation, every diary entry is validated:
function validateDiary(entry: string, todayEvents: Event[]): ValidationResult {
// 1. Length check
if (entry.length < 100) return { ok: false, reason: 'too short' };
if (entry.length > 2500) return { ok: false, reason: 'too long' };
// 2. No fabricated events
// (LLM-based check: does the diary mention anyone who wasn't actually present?)
// 3. No clichés
const bannedPhrases = ['and so it was', 'as the sun set', 'another day in paradise'];
for (const phrase of bannedPhrases) {
if (entry.includes(phrase)) return { ok: false, reason: 'cliché' };
}
// 4. Style check
// (LLM-based: does this match the NPC's style hints?)
return { ok: true };
}If validation fails, the entry is regenerated up to 2 times.
Storage
interface DiaryEntry {
id: string;
npcId: string;
worldTime: { day: number, hour: number };
text: string;
mood: Emotion;
promptHash: string; // for reproducibility
generatedAt: ISO8601;
generationCost: number; // LLM tokens used
}Stored in D1 table npc_diary. Indexed by (npcId, day) for fast retrieval.
What the Player Sees
- The most recent diary entry per NPC, on the world map.
- A timeline of past entries, scrollable.
- Search across all NPCs' diaries (full-text).
Diaries are the content of AI World Sim. Everything else is infrastructure for producing them.
Examples
A Good Entry (Margaret, Day 47)
"It rained most of the morning, which was a fine excuse to stay in and read. I finished the Brontë novel — far too sad for a rainy day, but I couldn't put it down. In the afternoon the rain stopped and I walked to the market. Maria was there, looking tired. She said business had been slow. I bought leeks and we talked about her son, who is apparently doing well at school. In the evening I almost didn't go to the pub, but I did. Eleanor was there. We didn't talk about anything in particular, which was nice. Sometimes that's the best kind of talking."
A Bad Entry (rejected by validation)
"Today was the most AMAZING day of my life!!! Everything was perfect and everyone was so wonderful and I felt so grateful to be alive!!!"
Reasons for rejection:
- Exclamation overuse
- Uncharacteristic for Margaret (reserved personality)
- No specific events mentioned
- Tone calibration violated