Tortoise
Forge

First Blood

  • #workhorse
  • #journal-cli
  • #esm
  • #vault-writer

Workhorse had two commands and both of them printed “not yet implemented.” The project was configured as CommonJS despite every constraint doc requiring ESM. No vault writer. No API connectors. A skeleton with a name and nothing else.

Session one needed to change that. Two tasks: build the journal command end-to-end, and update tortoisehq.io so the public site reflects what’s actually being built.

The journal command is the first real feature. You run workhorse journal, it records your voice through SoX, ships the audio to OpenAI Whisper for transcription, sends the transcript to Claude for structured extraction (mood, energy, themes, key events, action items, gratitude), and writes a markdown entry to the vault at endure/journal/YYYY-MM-DD.md. Every API call has retry caps. Anthropic has a kill switch, a single env var called ANTHROPIC_ENABLED that stops all spend instantly. The railway analog writes itself: this is the emergency brake handle. It doesn’t diagnose the problem. It stops the train. Every external API connector Workhorse builds from here will have its own.

The vault writer was the piece I thought hardest about. The temptation is to write frontmatter first, then body, then sections, each as a separate file write. But a crash between any two writes leaves a partial entry that corrupts every subsequent read. The fix is boring and correct: build the complete entry as a single string in memory, then commit with one write call. One write is functionally atomic for small strings. Multiple writes have gaps where corruption lives. This principle carries forward to every future vault write in the system.

Before any of that could happen, the project needed to migrate from CommonJS to ESM. One existing file to change. Every session that passes with CommonJS makes the migration harder. First feature is always the cheapest time, so we did it now. package.json gets "type": "module", tsconfig.json gets nodenext, every import gets its .js extension. Done. Every file written from this point forward is ESM from birth.

The site update was lighter. tortoisehq.io had four lanes: Forge, Encode, Engram, Endure. Engram was memory training, and it was too much scope for year one. The concepts that matter will surface through Encode naturally. So Engram came off the nav, two orphaned blog posts moved to Encode, and a new “Current Build: Workhorse” section went on the homepage between the category grid and recent posts. The public build has started. Visitors can see what’s actually happening.

What matters about this session isn’t the journal command itself. It’s the patterns it established. The vault writer exists, so any future connector can write to the vault. The API connector pattern exists, with retry logic, timeouts, and kill switches, so Whoop or any other integration follows the same shape. ESM is done. The site shows Workhorse.

One known gap carried forward: the timeout wrapper in the Whisper connector creates a cancellation signal but never passes it to the SDK call. The timeout fires but doesn’t cancel the HTTP request. It’s P1 debt, logged, and it gets fixed when the agent loop arrives, where runaway risk is real.

Next session builds the voice journal as a web app. Express routes in Workhorse, React page for mobile tap-to-talk. That’s the feature that makes this usable from a phone instead of a terminal.