All notes
Field notes from the studio.
Short essays from inside the work. No listicles, no SEO, no posting cadence. Published when we have something to say.
-
Detecting drift every night is not the same as fixing it
For 21 straight nights Janus re-flagged the identical roadmap drift it had no way to fix, re-confirming its own prior finding and turning a real signal into ritual noise. An observability agent with no actuator breeds alert fatigue — design the shortest path from detection to remediation.
-
Keyset pagination needs the clock it was indexed on
Moving list endpoints to keyset pagination silently skipped rows at page boundaries: the JS Date cursor carried milliseconds while the column stored microseconds, so the '> cursor' comparison landed inside a same-instant cluster. Keyset is only correct when cursor precision exactly matches the stored column.
-
?raw is empty under the test runner
A ?raw CSS import inlined fine in the app build but resolved to an empty string under the test runner, so tests exercised a rendering engine with no styles. Bundler-specific import mechanisms aren't guaranteed under your test runner — emit a real module the whole toolchain understands.
-
The LLM proposes; explicit intent decides
In an early human-plus-LLM authoring loop, model inference could overwrite structure the user had already stated. The fix was an authority order: explicit intent outranks inference — the model fills gaps and proposes, but never silently clobbers a fact the user stated directly.
-
A smoke test that never touches the fragile path proves nothing
Janus's CI smoke ran `janus --help`, which never loads an embedded asset, so it missed an ENOENT that broke every asset path in the compiled binary. Point the smoke at the fragile path on purpose — a compiled binary has a different filesystem than your dev tree.
-
Ship all four checksums, or none of them installed
A generic Homebrew bump action patched only one of four platform checksums per release, silently breaking brew install on three targets since v0.2.4. If you ship N platforms, own the checksum step and patch all N from the canonical SHA256SUMS in one atomic write.
-
The redaction that never redacted
Janus's documented path-redaction layer was dead code: the orchestrator never passed repoPath, so the `<repo>` substitution never fired despite living in code and docs. A data-egress guard needs a test that asserts the sensitive token is actually gone from the output.
-
An idle project needs an aging counter, not a heartbeat
Janus generated nearly a month of near-identical pulses for a project with zero commits, but each blocker carried a first-seen date and a live day-counter that auto-escalated at day 25. A status reporter that says the same thing daily is noise unless it ages its findings.
-
Stub the provider, not the state machine
To make Whet's LLM-backed E2E suite deterministic and free, the stub sits only at the provider I/O seam while the orchestration, persistence, and UI around it still run. Cut at the narrowest seam so the test verifies real wiring minus cost and nondeterminism.
-
Inside the container, the public URL points at nothing
Whet's backend delivered internal webhooks by dialing the app's public URL. Inside the container that origin resolved back to the backend itself and events vanished. Give server-to-server traffic its own base URL — the browser origin often isn't routable from inside.
-
Two 'pre-existing failures' rot the whole suite
Two failing tests were skipped as 'pre-existing' for three weeks, surfacing as a recurring risk in every daily pulse. A permanently-quarantined failure trains the team to ignore red and drains the whole suite of signal — fix it or delete it with a documented reason.
-
A queue with no handler fails by piling up
Whet's OAuth token-refresh cron kept enqueuing jobs no handler ever drained, and 46 piled up silently before anyone noticed. When enqueue and handler-registration are decoupled, assert every enqueued task type has a registered consumer instead of waiting on queue depth.
-
Validate the URL your own worker will dial
Any user-supplied URL a server-side worker will later fetch is an SSRF surface. Whet rejects loopback, private, link-local, and cloud-metadata hosts at endpoint-creation time rather than trusting the delivery path to be safe.
-
The style guide that failed its own check
Janus got a new voice rule: a checklist for catching AI slop in its own prose, imported from a public copy-quality guide. The first thing the rule caught was the voice spec itself — its opening line was the exact manufactured-contrast cadence the rule bans.
-
The database came with the download
A PoC asked whether the full stack (backend, database, MCP bridge) could ship as a native desktop app with no server. It booted in about 10 seconds: Postgres running in WebAssembly via PGlite, the backend as a Tauri sidecar, reusing the web build's migrations and protocol unchanged.
-
Name the role, not the value
A semantic token audit during a UX rework found the same color decision scattered across primitive tokens and raw hex in a dozen places. The hard part wasn't finding the raw values; it was naming what role each one actually played: a card background, a disabled fill, and a divider had silently shared one primitive.
-
The score is the signal
An Intelligence board ranked content with a composite of engagement proxies, recency decay, and source weights that couldn't explain itself. Moving scoring to an LLM that returns a number and a one-sentence reason deleted 719 lines and produced a table curators can actually argue with.
-
Four cascading bugs, one missing registry
A source-kind adapter registry looked like a code-quality cleanup: replace a scattered if/else with a dispatch table. Closing it closed four bugs that had accumulated across three versions, each one a downstream consequence of branching logic that lived in too many places at once.
-
An agent defaults to bullets
LLMs default to consulting-deck output — bullets, bold headers, passive constructions — because that's the most common form of structured prose in their training data. Aspirational instructions like 'be concise' don't override it. Falsifiable rules and before/after examples do.
-
Seven waves to a workbench
Building the session canvas didn't start with infrastructure — it started with mocks. Seven waves later it has real DB persistence, LLM streaming, MCP parity, and a cross-schema org bridge. The waves weren't sprints. They were sequencing decisions about what had to be true before the next thing could exist.
-
The scaffold that puts itself back together
A vault built to run for months drifts — folders renamed, templates outdated, indexes out of sync. The fix wasn't discipline, it was a scaffold that ensures the structure on every run: idempotent, silent, untestable to break.
-
I built a night agent for myself
Janus runs every night, reads my projects, and writes the engineering narrative I won't remember on Friday — pulse per project, compounded into weekly, monthly, and a continuous per-project spine.
-
Provider-portable agent runtimes
If your product depends on a single coding-agent CLI you have a vendor problem. Here's the shape of the abstraction I settled on after wiring the same orchestrator to two providers.
-
Coding agents leave a paper trail — read it
Git tells you what shipped. The session transcripts your coding agent already writes tell you what was decided, attempted, and dropped — and that's where the engineering narrative actually lives.
-
Building Whet: lessons from an agent-native product
Three decisions that mattered when shipping a product where the CLI and the MCP server are first-class citizens, not afterthoughts.
-
Compound-engineering, in practice
Every project at Crewtives starts with a KICKOFF.md and ends with skills you can run, not docs you have to read. The test is whether someone — human or agent — can resume your work without you in the room.