A multi-connector daily brief: Calendar plus Gmail plus iMessage events flow through the Wake brain into a TLDR plus source-tagged claims, with semantic search via Hindsight and durable per-day persistence. Fixture-mode fallback when WAKE_MCP_URL is unset so the template runs on a fresh checkout with no live Wake stack reachable.
ck new <name> --template morning-brief --host <name>.highline.work
cd ~/Work/<name>
python3 validate_brief.py # 9/0/0 expected
.venv/bin/uvicorn server.serve:app # local preview at :18212
What is in the box
| Path | Purpose |
|---|---|
content/fixtures/connectors-2026-05-03.json | Synthetic multi-connector dump (4 calendar events, 3 gmail threads, 2 iMessage threads) returned in fixture mode by wake_client.collect_connectors. |
content/fixtures/brief-2026-05-03.json | Synthetic synthesized brief (5 source-tagged claims) returned in fixture mode by wake_client.synthesize_brief. Schema creator_kit.morning_brief.v1. |
content/fixtures/search-results.json | Canned semantic-search results returned in fixture mode by wake_client.search. Schema creator_kit.morning_brief.search.v1. |
server/wake_client.py | Stdlib-only JSON-RPC client. Hits $WAKE_MCP_URL when set; falls back to fixtures when unset, on URL errors, or on JSON-RPC errors. Three calls: collect_connectors, synthesize_brief, search. |
server/render.py | Persistence and brief generation. generate_and_persist(user, date) writes to ~/.creator-kit/briefs/<user>/<date>.json (mode 0o600). CK_BRIEFS_DIR overrides the location for hermetic testing. |
server/serve.py | FastAPI server, seven routes (see below). Basic Auth pattern matching essay-series and estimator-demo. |
server/templates/{base,index,brief,search}.html | Jinja2 templates. /brief and /search content-negotiate (JSON default, HTML on ?format=html or Accept: text/html). |
public/_system/{_system,_patterns,_example}.css | Three-stylesheet load order: vendored CDS primitives plus kit-authored semantic patterns plus example-specific shapes (claim tags, search hit list, search form). |
validate_brief.py | Per-template validator. Five check groups: fixture integrity, voice rules, /brief route shape, /search route shape, persistence shape (mode 0o600 plus source-tag coverage). FLAG-skips route checks when fastapi is unavailable. |
tests/test_brief.py | 23 stdlib unittest tests across wake_client fixture mode, render persistence, validator, and routes. Routes auto-skip if fastapi is unavailable. |
tests/visual-targets.json | Three visual-regression targets (index, brief, search) for the kit’s harness. |
ck.config.json | Template manifest (port 18212 — avoids essay-series 18210 and estimator-demo 18211). |
Routes
| Method | Path | Returns |
|---|---|---|
| GET | /health | {"status":"ok","briefs":<count>,"wake_brain_configured":"0"} or 1. Open. |
| GET | / | HTML index. Latest brief inline plus history list plus search form. |
| GET | /brief?date=<iso> | Brief JSON for that date. Default: today. Auto-generates today’s brief if absent. Returns HTML on ?format=html. |
| GET | /briefs/<date> | Historical brief by date. Never auto-generates; 404 if absent. |
| GET | /search?q=<query> | Semantic-search hits via Hindsight. Returns HTML on ?format=html. |
| POST | /generate | Trigger today’s brief generation; persist; return the JSON. |
| GET | /_system/<path> | Static CDS chrome assets. |
Wake-MCP integration
wake_client.py posts JSON-RPC to $WAKE_MCP_URL (default https://wake.highline.work/mcp) and calls three tools:
tools/call("morning_brief_collect", {"user": ..., "date": ...})— multi-connector dump.tools/call("morning_brief_synthesize", {"user": ..., "date": ..., "connectors": ...})— TLDR plus source-tagged claims.tools/call("search", {"q": ..., "limit": 8})— Hindsight semantic search.
When WAKE_MCP_URL is unset, or any of those calls fail (transport, JSON-RPC error, parse failure), the client returns canned fixture data and the persisted brief carries wake_brain_used: false. This keeps the template runnable in CI and ship-test without a live Wake stack — the route shapes are exercised even in fixture mode.
To switch to live mode:
export WAKE_MCP_URL=https://wake.highline.work/mcp
.venv/bin/uvicorn server.serve:app --port 18212 --reload
curl -X POST http://localhost:18212/generate
Persistence
Every generated brief is written to ~/.creator-kit/briefs/<user>/<YYYY-MM-DD>.json (mode 0o600; the per-user dir is mode 0o700). CK_BRIEFS_DIR overrides for hermetic tests.
Briefs accumulate forever. The kit ships no expiry policy — the data is small (a few KB per day) and the user controls disk. If you need rotation, write a cron that prunes anything older than N days.
Voice rules (enforced by validate_brief.py)
Every claim in synthesis.claims[] and every hit in hits[] must carry a tag field with one of:
source-backed— directly supported by a connector record (a specific gmail message id, calendar event id, etc).inferred— plausible from source-backed facts but not directly proven.demo-only— synthetic for demonstration, not implementation-grade.
The validator’s route.brief_shape check rejects any persisted brief whose claims carry a tag outside this set. Same for route.search_shape against hits.
In addition: no emoji, no exclamation points outside fenced code, em-dashes preferred over double-hyphens. Standard kit register; matches essay-series and estimator-demo.
Out of scope (v1)
- Slack and Read.ai connectors. The kit ships Calendar plus Gmail plus iMessage as a starter set; extend
wake_client.collect_connectorsto add more. - Background generation. v1 generates on
POST /generateor on firstGET /brieffor today; no cron-driven scheduling. M3 W11 may add a launchd-driven daily generate. - Brief diffing. Each day’s brief is independent; v2 could compute deltas from the prior day.
- LLM streaming. Wake brain returns a single JSON response; the kit does not stream.
What forking this template gets you
A working FastAPI surface with four kit-standard patterns:
- JSON-RPC client with fixture-mode fallback.
wake_client.pyis the model — every external service call has a canned-data fallback so the template runs without live infrastructure. - Persistent state at
~/.creator-kit/<feature>/. The same pattern applies to any future template that needs durable per-user state. - Source-tagged claims as a contract. Every synthesized claim and every search hit carries a tag. The validator enforces it; the surface chrome renders the tag in colour. A creator forking this template gets the lane discipline by default.
- Three-route shape: index plus item plus history.
/,/brief,/briefs/<date>. Drop-in for any per-day artifact (digests, recaps, journal entries).
See also
- essay-series — longform writing template.
- estimator-demo — synthetic permit-set surface.