bradtraversy.dev — 2026-05-21-linesmith-spec.md
home.md projects/ tools/ devlog/ × articles/ now.md about.md
2026-05-21 · #devlog #decision #typescript

# linesmith, typesmith's sibling for code

typesmith types prose into whatever window has focus. i built it back in april to write narration into davinci resolve while recording. it works because prose targets are dumb pipes. code editors are not. vs code autocompletes, auto-indents, pairs brackets, finishes snippets. a keystroke-injection tool would spend its life fighting the editor.

so the sibling tool is an extension instead. linesmith is in the same family, with “lines of code” as the unit it operates on. types code into the active vs code editor during tutorial recording, using TextEditor.edit() directly into the buffer instead of synthesizing keystrokes. no autocomplete to fight, no platform-specific deps, works in remote sessions (ssh, wsl, codespaces) where keystroke injection often can’t reach.

an extension is the only honest answer

three implementation paths were on the table at the start: keystroke injection (the typesmith approach), a vs code extension, or a hybrid. the killer feature pulled hard toward extension and never let go.

real tutorial editing isn’t top-to-bottom. you write a function signature, jump back into the parens to add types, then up two lines to drop in a docstring. that’s cursor choreography. keystroke injection literally cannot do it. the cursor is wherever the user last clicked. a scripted extension owns the cursor. ships in v0.2 and becomes the thing a typesmith-style tool can’t match.

the input model is a file

first draft of the spec had a textarea inside the panel for “type your script here.” that’s a strict downgrade once you think about it. a .linesmith file lives in version control, opens in any vs code tab with the full editor chrome (find/replace, multi-cursor, ai completions), and persists across sessions.

format is plain text. one separator: --- on its own line, marking chunk boundaries. that’s the whole format:

import { useState } from 'react'
---
const [count, setCount] = useState(0)
---
return <button onClick={() => setCount(count + 1)}>{count}</button>

language-agnostic by design. the typing engine inserts characters; whether they’re rust, python, html, or yaml is the target editor’s concern. indentation preserved literally, which matters for python and yaml.

v0 ships smaller than the killer feature

v0.1 is clean typing into vs code with .linesmith files, a chunk-list panel with a play next button, and a .linesmith language contribution (file icon + --- separator highlight). no cursor choreography yet. that ships in v0.2 with @directive frontmatter (@cursor end-of-line, @speed 60). picked @-prefixed syntax because --- is already load-bearing and yaml-style frontmatter would have collided with the chunk separator.

published on the vs code marketplace and open vsx from day one. cursor and windsurf both pull from open vsx, not the official marketplace, so both registries is non-negotiable.

repo is next.

// EOF 2026-05-21-linesmith-spec.md
main
2026-05-21-linesmith-spec.md
UTF-8
LF
Markdown
Ln 1, Col 1