I built a (free) local-first AI writing partner. Here’s why.
This is an extra newsletter issue to share something I’ve been working on as a side quest. Regular issue is dropping next week. But this is also a chance to share the updated newsletter aesthetic I’ve built - WDYT?
I write a lot.
Newsletter posts, long-form guides, positioning docs, client deliverables. Most of it starts as a Markdown file on my machine and goes through several rounds of review before it’s anywhere near done.
But I’m not the only one doing this kind of work. If you’re a PM drafting a PRD, a growth lead writing a strategy doc, or a founder writing a spec that isn’t ready for anyone else’s eyes yet, you’re in the same workflow. A document, access to incredible AI tools, and a process that hasn’t quite caught up with how either of those things could actually work well together.
Writing is high leverage. There’s few (if any?) tech roles where good writing isn’t of importance.
Over the past couple of years, I’ve used AI to help with my writing process. Every month that goes by brings shiny new models that often (but not always) unlock improved output. But the workflow has always been clunky. You paste a chunk of text into a chat window along with some guidance, get a rewrite back, manually figure out what changed, copy it back into your file, and repeat. If you want the AI to focus on a specific section, you have to tell it which one in the message. Or you work on just a snippet, but then the model is missing context of the surrounding paragraphs and wider doc.
It’s a chat transcript pretending to be an editorial workflow. Square peg, round hole.
So I built Skribe.
What I actually wanted
The problem wasn’t the models. The models are good. The problem was the surface.
When I’m editing I don’t want a back-and-forth conversation. I want something that works like a document, where I can highlight a paragraph, attach a comment to it, ask a model-of-choice a focused question about that specific passage, and get a diff back I can accept or reject. Like a code review, but for writing.
I also didn’t want my drafts going anywhere. The past couple of years I’ve been adopting more and more local-first workflows, and storing my data locally with offsite backup as a final safeguard. Half-formed ideas, draft posts that are weeks away from being publishable, specs that aren’t ready yet - I generally don’t want them sitting in a third-party cloud. I want them on my machine.
And I wanted to use the models I already have running. I’m already paying for Claude Code and Codex. I have Ollama running locally for offline work (usually with Gemma 4 or Qwen 3.6 27B or 35B depending on the machine). I didn’t want a tool that forced me to route through its own API keys or pick from its approved model list.
Those three things together - document-first editing, local storage, bring your own model - don’t exist as a single product. At least they didn’t.
How it’s built
Skribe is a local server that opens in your browser. You point it at a Markdown file:
npx skribe-editor ~/draft.md
That’s it. No account. No login. It starts a local server on port 4327, opens the browser, and you’re in.
The tech stack is deliberately boring. It’s a React frontend built with Vite, using react-markdown and remark-gfm for rendering. The backend is a local Node.js server. Nothing novel.
Where the design decisions got more interesting was in the agent layer.
Skribe has two distinct surfaces for talking to the AI: threads and chat. They look similar but they serve different jobs.
Threads are anchored to a selection or passage. When you highlight a sentence and open a thread, the agent sees that specific passage, the thread history, and just enough document context to make a focused edit fit. It doesn’t need the whole document. It needs to answer the question you’re asking about that paragraph.
If you’re working on a PRD, this is where you’d highlight a user story and ask “does this actually capture the job-to-be-done, or are we describing the solution?” and get a focused answer, not a rewrite of the whole spec.
Chat is for the whole draft. Structural edits, broad review passes, skill-driven rewrites across the document. The agent sees the wider document, chat history, open proposals, and thread decisions. It’s the equivalent of handing the whole piece to an editor and saying “what do you think?”
Without that separation, you end up with a chat session where the AI loses track of what you’re talking about, forgets earlier decisions, and gives you advice that doesn’t fit the passage it’s supposed to be improving.
Diff reviews
This was the part I spent the most time on, and the part I think I miss the most in other tools / workflows.
When the AI suggests a change, Skribe doesn’t apply it automatically. It returns a reviewable proposal. You step through each change block (in split view or unified view) and accept, decline, or comment on it before anything touches your draft.
This sounds like a minor UX detail, but without it, you’re either accepting the whole rewrite or rejecting the whole rewrite. There’s no middle ground. In practice, the AI gets some things right and some things wrong in the same response. The diff review lets you take the right bits and push back on the rest without losing the context.
I’ve started thinking of it like a git diff for prose. Once you have it, editing without it feels janky. Individual word choices carry weight and you can’t afford to bulk-accept a rewrite and hope for the best.
Skills
Skribe discovers SKILL.md files from your existing local skill directories — ~/.agents/skills, ~/.claude/skills, ~/.codex/skills. They show up automatically as /slash commands in the composer.
For example have a /newsletter skill that checks for specific patterns I want to avoid in my content.
If you’re a PM, you could have a /prd-review skill that checks whether your problem statement is actually a problem statement and not a feature list in disguise. A /jtbd skill that rewrites acceptance criteria in jobs-to-be-done framing. A /ten-pager skill that enforces the structure your team has agreed on for strategy docs. Whatever playbook you’ve built up in your AI workflows comes with you.
They’re just Markdown files describing how the agent should work. Because Skribe uses your existing CLI runtime, the skills load natively, the same way they’d load in Claude Code or Codex. On the local inference path, Skribe inlines the skill instructions directly into the prompt.
Practically, that means that the same editorial playbook you’ve built up over months of working with AI tools comes with you into Skribe. You don’t have to rebuild it.
Tone of Voice
Skribe has a tone-of-voice generator. It can interview you to build that, or you can feed it a few samples of your existing writing and it reverse-engineers a style profile - your sentence shape, your stance, the words you lean on. Or skip that and pick a writing archetype preset to start in seconds, then refine later.
Either way it builds a durable profile the agent applies to every thread, chat and diff, stored locally with everything else.
What I got wrong with the prototype
The first version had no separation between threads and chat. Everything was one conversation surface. This was bad.
The context window got messy fast in longer editing sessions. A thread comment about the intro, a structural question about the conclusion, a rewrite request for the third section - all mixed together. LLM context wasn’t managed effectively, I lost track, and the conversation stopped being useful.
Splitting them was obvious in retrospect. (Duh!)
I also underestimated how much people care about Flow mode. The first version I built didn’t have it, and I missed it from my time using tools like iA Writer on Mac OS.
It’s a simple affordance - hide the agent UI entirely when you just want to write. Canvas only. Small exit button in the corner. Turns out a lot of early users agreed and told me they always start new sessions in it and only open the review surfaces when they’re ready to edit.
Local-first
This was an easy decision. It was actually the first decision, and everything else followed from it.
The document stays on your machine. Comments stay on your machine. Revision history, settings, context memory for the agent - all local. The model calls go directly to whatever runtime you’ve configured, whether that’s Claude Code, Codex CLI, or a local Ollama (or llama.cpp, or LM Studio) server. The only thing time anything leaves your machine is if you’re using non-local inference.
This does mean Skribe (intentionally) isn’t a collaboration tool right now. One document, one user, one local instance. That’s a real trade-off.
Try it
Skribe is MIT licensed and open source.
npx skribe-editor ~/draft.md
Requires Node 20+. Optionally: Codex CLI, Claude Code, or any OpenAI-compatible local inference server for live agent replies.
The repo is at github.com/devtunehq/skribe if you want to look at the code, or file an issue. The docs and a walkthrough of the main features are at skribe-editor.com.
If you try it I’d love like to know how it works for you. Reply here or open an issue on GitHub.
PS: If you found this useful, forward it to someone who spends half their week writing docs and the other half arguing with an AI chat window about them.
BEFORE YOU GO
Book a free 1:1 consultation call with me - I keep a handful of slots open each week for founders and product growth leaders to explore working together and get some free advice along the way. Book a call.
View your free public Dev Tool AI Market Presence Report - 500+ dev tools across 47+ verticals and growing, all in the Dev Tool AI Search Landscape.
Sponsor this newsletter - Reach over 13000 founders, leaders and operators working in product and growth at some of the world’s best tech companies including Paypal, Adobe, Canva, Miro, Amplitude, Google, Meta, Tailscale, Twilio and Salesforce.








