---
name: write-blog
description: Write blog posts tracking tidalDB's progress, architectural decisions, and engineering insights. Use when documenting what was built, writing devlogs, announcing milestones, or crafting technical narratives about the database.
agent: tidal-storyteller
---

# Write Blog

Write and publish blog posts for tidalDB using the **tidal-storyteller** agent.

## Content Strategy Reference

**Read `docs/content-strategy.md` before writing any post.** It maps every blog post idea to a specific roadmap phase, names the thesis, identifies the source material, and specifies when the post is ready to publish.

The content strategy defines 16-20 posts across the full roadmap. Do not invent posts outside this plan without first checking whether the strategy already covers the topic. If it does, follow the strategy's guidance for that post. If the strategy has a gap, propose adding to it -- do not write an orphan post.

### Determining What to Write Now

1. Check the **Current Status** section in `docs/planning/ROADMAP.md` to identify which phases are complete
2. Cross-reference with the **Reference: Roadmap to Post Mapping** table in `docs/content-strategy.md`
3. The post is ready to write when its roadmap phase has passed UAT and benchmark numbers exist
4. Exception: Post 1 ("Every content platform builds the same 6 systems from scratch") can be written any time -- it depends on the problem, not the implementation

### Current Queue (update as phases complete)

As of M4 complete, posts 1-11 written:

| Priority | Post | Status |
|----------|------|--------|
| 1 | Post 1: "Every content platform builds the same 6 systems from scratch" | PUBLISHED |
| 2 | Post 2: "Running decay scores are O(1) -- here is the math" | PUBLISHED |
| 3 | Post 3: "What three databases taught us before we wrote a line of code" | PUBLISHED |
| 4 | Post 4: "Signals wrote 100ms ago. The query sees them now." | PUBLISHED |
| 5 | Post 5: "One query. Six systems. Under 50 milliseconds." | PUBLISHED |
| 6 | Post 6: "Diversity enforcement in 3 microseconds" | PUBLISHED |
| 7 | Post 7: "Ranking profiles are data, not code" | PUBLISHED |
| 8 | Post 8: "The feedback loop that closes in one write" | PUBLISHED |
| 9 | Post 9: "Negative signals are equal citizens" | PUBLISHED |
| 10 | Post 10: "Cold start without application logic" | PUBLISHED |
| 11 | Post 11: "Search and ranking are the same system" | PUBLISHED |
| — | "Why we chose fjall over RocksDB (for now)" | Ready -- anytime ADR |
| — | "Why not SQL" | Ready -- anytime ADR |
| — | "USearch, not from scratch" | Ready -- anytime ADR |

### Code anchors for the three READY posts

**"Why we chose fjall over RocksDB (for now)"**
- `tidal/src/storage/engine.rs` -- the `StorageEngine` trait; six methods, zero fjall imports -- this is the abstraction boundary
- `tidal/src/storage/fjall.rs` -- `FjallBackend` implementing the trait; `fjall::Keyspace` is the only fjall type that crosses the boundary
- `tidal/src/storage/memory.rs` -- `InMemoryBackend`; proves the trait is genuinely swappable (used in all tests)
- `tidal/Cargo.toml` -- version pin, no `unsafe` in fjall feature flags
- `thoughts.md` Part V.9 -- the architectural reasoning behind the choice
- Thesis: the trait boundary is the argument. Show it. Then explain why the decision is reversible.

**"Why not SQL"**
- `tidal/src/query/retrieve.rs` -- `RetrieveBuilder`; `for_user`, `profile`, `diversity`, `filter` are typed builder methods -- not string predicates; note `ProfileRef`, `DiversityConstraints`, `FilterExpr` are rich types
- `tidal/src/ranking/profile.rs` -- `RankingProfile`, `CandidateStrategy`, `SignalBoost`; show that a profile encodes retrieval mode + scoring weights + sort logic -- no SQL analogue
- `tidal/src/query/executor.rs` -- `for_user` dispatch loads preference vector and interaction ledger; this is stateful user context that SQL has no model for
- `thoughts.md` Part II.4 -- the reasoning for a custom query language
- Thesis: show a `Retrieve::builder()` call next to what the equivalent SQL would require (JOIN preference_vectors, JOIN interaction_weights, computed ranking expression, HAVING diversity constraint). The SQL falls apart. The builder does not.

**"USearch, not from scratch"**
- `tidal/src/storage/vector/mod.rs` -- `VectorIndex` trait and the module comment; read the design decisions section carefully (VectorId = u64, L2 squared, ef_search uniformity); the rest of the codebase never imports `usearch` directly
- `tidal/src/storage/vector/usearch_index.rs` -- `UsearchIndex`; the wrapper is intentionally thin; count the lines that cross the FFI boundary
- `tidal/src/storage/vector/planner.rs` -- `AdaptiveQueryPlanner` with four strategies; this is tidalDB's value-add on top of the borrowed index; show the strategy dispatch
- `tidal/src/storage/vector/brute.rs` -- `BruteForceIndex` and `MockVectorIndex`; proves the trait boundary allows correctness baselines without touching USearch
- `docs/research/ann_for_tidaldb.md` -- the prior art survey; cite the production users (ScyllaDB, ClickHouse, DuckDB)
- Thesis: the `VectorIndex` trait is a six-method interface. Show it. Then show that `UsearchIndex` is ~150 lines wrapping it. Then show the `AdaptiveQueryPlanner` -- that is what we built. The six months of HNSW engineering is USearch's problem.

## When to Use

- After completing a roadmap phase or milestone -- check the content strategy for which post maps to that phase
- When an architectural decision deserves a public narrative -- check if the strategy already has an ADR planned for it
- When a benchmark result tells a compelling story -- the strategy specifies which posts need benchmark data
- When announcing a release, feature, or open-source milestone

## Context to Load

Before writing, the agent must read -- in this order:

1. **`docs/content-strategy.md`** -- find the post in the strategy, read its thesis, source material, and publication criteria
2. **The source material named in the strategy** -- the specific docs, research files, and task docs listed for that post
3. **Relevant source files** -- the actual Rust code that was written or changed
4. **Git log** -- `git log --oneline` for the period covered
5. **Previous blog posts** -- `site/` blog content directory for voice consistency
6. **VISION.md** -- for tonal calibration (match its conviction)
7. **thoughts.md** -- for the deeper "why" behind architectural patterns

## Blog Post Types

### Architecture Decision Record (ADR)
**When:** A major architectural choice was made and the reasoning is worth sharing.
**Strategy posts:** Post 3 (three databases), Post 7 (ranking profiles), Post 9 (negative signals), Post 12 (Tantivy), Post 16 (graceful degradation), plus the "anytime" ADRs (Why not SQL, Why fjall, USearch not from scratch).
**Structure:**
1. The problem in one sentence
2. What we considered (2-3 options, honestly assessed)
3. What we chose and why -- the specific evidence
4. Code showing the result
5. What we would watch for (risks, trade-offs acknowledged)

**Title pattern:** Thesis statement, not label.
- "Running decay scores are O(1) -- here is the math" not "Signal System Architecture"
- "Why we chose fjall over RocksDB (for now)" not "Storage Engine Decision"

### Devlog / Progress Update
**When:** A phase or milestone was completed.
**Strategy posts:** Post 4 (M1 complete), Post 5 (M2 complete), Post 13 (M5 complete).
**Structure:**
1. What we set out to build (the goal, in one sentence)
2. The hardest part (the interesting engineering, not a changelog)
3. What surprised us (the insight the reader takes away)
4. Code showing the key breakthrough
5. What is next (one sentence, not a roadmap dump)

**Title pattern:** The insight, not the timeframe.
- "10M signals, 4 microseconds" not "Phase 2 Complete"
- "The struct that touches every ranking query" not "February Update"

### Technical Deep Dive
**When:** A specific technique deserves its own focused explanation.
**Strategy posts:** Post 2 (decay math), Post 6 (diversity), Post 8 (feedback loop), Post 10 (cold start), Post 11 (hybrid search), Post 14 (cohort trending), Post 15 (crash recovery).
**Structure:**
1. The problem this solves (relatable, concrete)
2. Why the obvious approach fails (with numbers)
3. The technique, explained incrementally with code
4. Benchmarks proving it works
5. Where to learn more (papers, references)

**Title pattern:** The technique as a claim.
- "Forward decay eliminates 99% of read-time computation" not "How We Handle Decay"
- "Diversity enforcement in 3 microseconds" not "Our Ranking System"

### Vision / Problem Statement
**When:** Defining the problem space before or independent of implementation.
**Strategy posts:** Post 1 (the 6-system stack).
**Structure:**
1. The problem, made visceral -- name the systems, name the failure modes
2. Why it exists (historical accident, not intentional design)
3. The thesis: what should be true instead
4. The one-query vision (end with the destination, not a product pitch)

**Title pattern:** The indictment.
- "Every content platform builds the same 6 systems from scratch"

### Announcement
**When:** A release, open-source milestone, or public launch.
**Structure:**
1. What it is (one sentence)
2. What you can do with it (3-5 bullet points with code)
3. Install/quickstart command (prominent, copy-pasteable)
4. What is different about this (the thesis -- why this exists)
5. Links: GitHub, docs, community

## Writing Standards

### Voice
- Active voice. Short sentences. Concrete nouns.
- First person plural ("we") for team decisions, second person ("you") for reader actions
- Technical precision without jargon -- say "O(1) per write" not "blazingly fast"
- Humor only when it lands naturally. Never forced.

### Structure
- Title is a thesis statement that works as a tweet
- First paragraph earns the second paragraph
- Every paragraph earns the next
- Code blocks show, body text explains
- 800-1500 words for devlogs, 1500-3000 for deep dives

### Code Examples
- Must be real -- from the actual codebase or a working reproduction
- Must be copy-pasteable
- Include enough context to understand without reading the whole post
- Syntax highlighted with the site's muted dark palette
- Annotated with comments only where the code is not self-evident

### Audience Calibration
The reader is an engineer who has built or maintains a recommendation/discovery system. They know what Kafka consumer lag feels like. They know why ranking pipeline cache invalidation bugs never get root-caused. They will recognize the 6-system stack because they operate it. Do not explain what Elasticsearch is. Do not explain what a vector database does. Start from shared pain.

### Frontmatter
```yaml
---
title: "The actual thesis statement"
date: "YYYY-MM-DD"
author: "Name"
description: "One sentence for SEO and social cards"
tags: ["signals", "architecture", "rust"]
---
```

## Workflow

1. **Check the strategy** -- read `docs/content-strategy.md`, find the post, confirm the phase is complete
2. **Gather context** -- read the source material listed in the strategy entry for this post
3. **Find the headline** -- the strategy provides a working title. Sharpen it. If it does not work as a tweet, rewrite it.
4. **Write the draft** -- narrative first, code second
5. **Verify code** -- every example must compile and run against the current codebase
6. **Cut in half** -- remove every sentence that does not earn its place
7. **Read aloud** -- if you stumble, rewrite
8. **Write as MDX** -- save to the blog content directory with proper frontmatter

## Quality Checks

- [ ] Post matches a specific entry in `docs/content-strategy.md`
- [ ] The roadmap phase for this post is complete (code shipped, not planned)
- [ ] Title works as a standalone tweet
- [ ] First paragraph earns the reader's second paragraph
- [ ] Every code example is correct, copy-pasteable, and from the shipped codebase
- [ ] Benchmark numbers come from actual `criterion` runs, not estimates
- [ ] No marketing language ("leverage," "seamless," "robust," "empower," "excited to announce")
- [ ] **No internal milestone/phase labels** ("Milestone 1 is done", "M2 is complete", "M3 concern", "phase 4") -- readers don't know our internal planning. Use "next:", "coming soon", "not yet implemented", "on the roadmap" instead.
- [ ] Under 3000 words (deep dives) or 1500 words (devlogs)
- [ ] Ends with something the reader remembers tomorrow
- [ ] Frontmatter is complete (title, date, author, description, tags)
- [ ] Tags do not include "milestone" -- that is internal language
- [ ] Would a CTO forward this to their team? If not, rewrite.

## After Publishing

1. Update the **Current Queue** table in this skill to reflect the new state
2. If the post revealed a new insight worth a follow-up, propose adding it to `docs/content-strategy.md`
3. Do not write the next post until there is something true to say about it
