Daeseon Yoo
Back to project
·Tech retro·3 min

Designing the project-log system (this thing you're reading)

Why I added a fourth content type for project logs, dual-wrote to a machine-facing reference and a human-facing timeline, and built explicit anti-hallucination rules.

The blog already had post / note / knowledge. I added a fourth type, log, specifically for project journals. This is one of those entries.

Why a fourth type instead of overloading note

Notes are private by default and don't surface anywhere — they're the Notion replacement. Project logs need:

Overloading note with these would mean every note carries fields that don't apply. New type is cheaper than a polluted schema.

Dual-write to two surfaces

Each non-trivial event now writes:

  1. docs/troubleshooting.md — flat, problem-indexed, terse. Optimized for "I'm hitting the same thing again, grep this first."
  2. content/logs/<project>/<date>-<slug>.mdx — narrative, date-indexed, project-scoped. Optimized for "give me the timeline of this project" and for the RAG manifest.

I tried single-source first. Both directions failed:

The duplication cost is low (the mdx is mostly a fleshed-out copy of the troubleshooting entry) and pays back the first time a bug recurs.

Anti-hallucination rules

Because Claude is writing most of these entries, the rules need to be explicit. Seven rules in docs/project-log-spec.md:

  1. Symptom is literal — paste the actual error, no paraphrase.
  2. Cause is verified, or marked Hypothesis: … Verified by: …, or marked Suspected: with caveat.
  3. Fix names actual files. git diff is the source of truth.
  4. Commit hash from git rev-parse HEAD after committing, not before.
  5. Date from git log -1 --format=%cI, not memory.
  6. Pattern only if the recurring lesson is obvious from this one incident.
  7. Don't fabricate timing or metrics.

These exist because Claude (and humans under pressure) will happily fill empty fields with plausible-sounding fiction. Plausible-sounding fiction in a problem-indexed cache is worse than the cache not existing.

Surface that exists now

What's deferred

Pattern

When a piece of structured content has at least two different reader/use patterns (grep vs timeline, machine vs human, this-project vs all-projects), denormalize on purpose. The cost of two surfaces is small if the canonical fact lives in one place (the mdx body) and the other surface is mostly metadata derived from it.