building my personal writing app


I'm open-sourcing my personal writing app, Raw2Draft. It's the first of several tools I'll be releasing over the coming months. Next is the knowledge base framework I use. Then an agent harness setup build on top of Pi (if it goes well).

Personal tools have gotten cheap to build. Tools that work exactly how you think. Should you use mine? Probably not. It wasn't designed for you.

But if writing is part of what you do, you should consider building your own. Point your agent at this repo (and others) and have it help you extract the parts you like. And remember to show support and acknowledgement for any open project you used!

How Raw2Draft Works

I built a markdown editor called Raw2Draft. It has an embedded terminal running Claude Code, a preview pane that matches my blog’s typography, and an iA Writer-inspired styling layer. The interesting part is the agent skills that power my AI writing workflow. They’re portable: they work in Raw2Draft, in a plain terminal, and in other agents.

Portable Skills

The skills that power my writing workflow are Claude Code skills: markdown files with plain English instructions. The same skill files work in Raw2Draft, in a plain terminal session, in Codex, or any other agent. If I switch editors tomorrow, the skills come with me.

On first launch, Raw2Draft clones two public GitHub repos: agent-starter-skills (skills for blog writing, transcription, social media, publishing, scheduling, and video editing) and agent-starter-wiki (a knowledge base with reference docs like writing style guides). Both get passed to Claude Code as context directories via --add-dir. Both are designed to be forked and replaced with your own.

The skills are procedural: do this, then this, then this. The knowledge base is about taste and judgment: how I write, what I’ve learned about specific APIs, style decisions I’ve made. That separation keeps the skills clean. I’ll write about my personal knowledge base separately.

Composition

I use a “parent skill” pattern. /content-blog calls /transcribe if there’s a video, calls /screenshot to capture key frames, sends everything to Gemini with my writing style guide, and runs two editing passes. I don’t call the sub-skills manually. I call the parent, and it orchestrates.

The same sub-skills get reused in different contexts. When I’m writing a spec, I call the screenshot skill directly. When I’m editing video, the transcription skill uses a different provider because video editing needs filler words preserved for accurate cut detection. Different parent skills compose them differently, and I compose them by hand when I need something one-off.

I don’t write a script until the plain English version fails. Scripts handle Gemini calls, S3 uploads, frontmatter parsing. The decisions about what to do and when live in plain English.

What a Writing Session Looks Like

A post starts as a voice transcription (my wife calls it recliner rambling) saved alongside screenshots, videos, or reference files. I call /content-blog and get a first draft. The first draft saves hours, but editing is where the post becomes mine. I rewrite sections, reorder arguments, cut two paragraphs of AI writing down to a sentence. I read passages aloud to check rhythm. I use Claude Code as a reviewer, asking it to find clutter or critique the argument from different angles. I wrote about this in more detail in my full writing process post.

When the post is ready, /publish validates frontmatter, syncs images to S3, rebuilds the search index, and deploys.

Embedding Claude Code

Raw2Draft doesn’t have its own AI. It launches Claude Code as a subprocess in an embedded Ghostty terminal, passing it the project directory and a set of context directories. Claude Code provides the reasoning, file editing, and skill execution. Raw2Draft provides the writing surface and the glue between them.

That glue is small. The app writes the current file path to ~/.raw2draft/active-file whenever I switch tabs, so Claude Code always knows what I’m looking at. When Claude Code edits a file, the editor picks up the change. A command palette (Cmd+P) sends slash commands to the terminal. The editor and Claude Code work as one system, but the boundary between them is clean.

The Terminal

The hardest part was the terminal. I tried xterm.js (too many edge cases), then SwiftTerm (rendering bugs because Claude Code assumes a full terminal). I switched to libghostty, the core of the Ghostty terminal emulator. I already used Ghostty as my daily terminal, so embedding its core felt right. I haven’t had a terminal issue since.

The Editor

The markdown editor uses CodeMirror. It handles markdown well, it’s extensible, and the styling system let me build the look I wanted. The whole thing is a small JavaScript project embedded inside the native app.

The native app and the editor talk through a bridge: Swift sends content in, JavaScript sends keystrokes back. That bridge has been fragile.

One example: I pasted an image URL and the entire editor went blank. CodeMirror has two ways to attach visual elements to text, and I picked the one that silently fails on full-line elements. No error, no partial render. Just white.

It’s stable now, but the bridge is still the trickiest place to add new features. Every new interaction between the editor and the native layer means getting Swift and JavaScript to agree on timing and state.

The sidebar switches between two modes based on one check: does a posts/ directory exist? If yes, it loads the content studio with visual indicators for draft, scheduled, and published posts. If not, it’s a file browser. No commercial software would ship that detection strategy. But this is a personal tool. If I restructure my blog, I’ll change the check. Good enough.

What Made This Possible

I started with three separate repos: the blog, Raw2Draft, and a knowledge base. Skills and reference docs were duplicated across all of them. I consolidated into one monorepo so everything could share context.

Then I built the knowledge base into its own system, and that let me decouple again. The skills and knowledge live in their own repos. Raw2Draft, the blog, and any future tool can pull from the same source. The consolidation taught me what needed to be shared. The knowledge base made sharing possible without coupling.

The skill architecture means adding a new capability is writing a markdown file. When I designed a social media skill, I wrote three rules in English: find the hook, maximize white space, preserve voice. A year ago, writing instructions in a markdown file would not have been enough. Now it is.

I like Raw2Draft better than any other writing tool I’ve used. Better than Google Docs. Better than Typora. Not because it’s more polished. Because it does exactly what I need, the way I need it, and nothing else.

Thanks,

Isaac

p.s. If you were forwarded this email, all my writing is available on my website

Isaac Flath

Every post comes from something I've done on a real project. AI tools, development approaches, how I actually build things. You're getting a curation of my taste, not takes on stuff I don't use. Subscribers also get extras: things that went wrong, how my thinking about AI is changing, hacky workflows I use every day, and the occasional personal update. Stuff I share with subscribers because it's a little too personal or unpolished to blast across the internet.

Read more from Isaac Flath

Today's post is about a project that I will take concepts from to improve my own work. So I studied the OSS prototype of it to understand how it works. Point and Talk: How Clicky’s AI Interface Works Clicky is an AI buddy made by Farza that lives on your Mac. You press a key, talk, and a glowing blue triangle flies across your screen, points at whatever you asked about, and talks you through the answer. Most apps with an agent should have something like this. Point and talk is closer to how...

Last week I shared my knowledge base tool, agentkb. This week I am OSSing my pi harness that uses it, Harpy. The most interesting part of the harness is that knowledge base <-> harness integration so that's what this week post dives into. It covers what RLM is, how it drives a python loop with state, how Pi (typscript) extension talks to python, and how that allows for smart delegation and fan-out to smaller models to give more accurate search results. How My RLM Tool Works An LLM writes...

Hey, This was a week of context switching 😅. Product release weeks are always odd. The goal is super specific, and yet the work is scattered small tasks (testing, polish, docs, marketing copy, etc.). We shipped the stoa beta, and I kept wishing my agents could remember more. That's why I'm open sourcing `agentkb`, my work-in-progress knowledge base framework today. The Pi harness built around it will be open sourced next. AgentKB: A Local Knowledge Base for Agents My agent should learn from...