Open development / Amp Code / 173+ threads
Built with AI, in the open
Token is a multi-cursor text editor written in Rust — around 15,000 lines of code built primarily through 173+ conversations with Amp Code. Every feature, every bug fix, every architectural decision is documented publicly.
The framework
Before each session, explicitly state which mode you're in. This prevents scope creep and keeps AI contributions coherent across sessions.
New behavior that didn't exist
"Implement split view (Phase 3)" Better architecture, same behavior
"Extract modules from main.rs" Fix a cluster of related bugs
"Multi-cursor selection bugs" Design before code
Complex features get upfront specification. Reference docs define cross-cutting concerns like viewport math. Feature specs define data structures, invariants, and phased plans. Gap docs list what's missing when a feature is 60-90% complete.
Development timeline
Token's development followed distinct phases, each with focused objectives.
Setup, reference docs, Elm Architecture in Rust
Split view, undo/redo, multi-cursor selection
Extract modules from main.rs (3100→20 lines)
Configurable YAML keybindings, 74 default bindings
Tree-sitter integration, 17 languages supported
Spreadsheet view with cell editing (Phases 1-2)
Sidebar file tree, focus system, global shortcuts
EditableState system, modal/CSV clipboard & selection
Event loop fix (7→60 FPS), find/replace modal
Docked panels, markdown/HTML preview, file dialogs
Complete redesign, 5 new themes, bracket matching
Auto-surround selection, bracket highlighting
Highlight pipeline rewrite, deadline timers, shift-on-edit
Cmd+E modal, persistent MRU list, fuzzy filtering
Tree-sitter symbol extraction, 10 languages, dock panel
Notable threads
Highlights from 173+ conversations. Each links to the full Amp Code thread.
The Oracle performed a deep review of EDITOR_UI_REFERENCE.md and caught 15+ bugs — off-by-one errors in viewport calculations, division-by-zero edge cases in scrollbar math, and mismatched struct field semantics — before any of them became code bugs.
Undo/redo was completely broken on macOS. Pressing Cmd+Z inserted the letter 'z' into the document. Root cause: the key handler only checked control_key(), not super_key() (macOS Command key). A one-line fix.
Implementing multi-pane editing required a shared-documents/independent-editors architecture. Documents live in a HashMap, multiple editors can view the same document with independent cursors and viewports. Migration helpers like single_document() enabled phased refactoring.
Arrow keys and all movement operations only affected the primary cursor — secondary cursors were frozen. Every movement handler assumed cursor_mut() returned the only cursor, but it was actually cursors[0]. Fixed by creating per-cursor primitives and all-cursor wrappers.
A complete spreadsheet UI for CSV/TSV files built across 6 sessions: RFC 4180 parsing, grid rendering with column headers, arrow key navigation, Tab/Shift+Tab cell movement, inline cell editing with proper CSV escaping, and Enter to confirm + move down.
Five separate text editing implementations (main editor, command palette, go-to-line, find/replace, CSV cells) with duplicated logic. Solved by creating a unified EditableState<B: TextBuffer> abstraction that shares editing logic across all contexts. All modals gained full cursor navigation, selection, and clipboard support.
Multi-split view caused ~7 FPS with 100% CPU even when idle. Root cause: ControlFlow::Poll was spinning the event loop constantly. Fixed by switching to ControlFlow::WaitUntil — idle CPU dropped from 100% to 0%, FPS jumped to 60.
Built a full docked panel system with webview-based markdown/HTML preview across 9 sessions. DockPanel abstraction with resizable panels, WKWebView on macOS with custom token:// protocol for local resources, and live preview updates on tab switch.
Mouse handling was ad-hoc if/else chains checking pixel coordinates. Replaced with a priority-ordered HitTarget enum and hit-test system. Each target knows its bounds, first match wins — clean, extensible, and testable.
Clicking below the midpoint of the editor caused unwanted scrolling. A Mermaid diagram revealed the root cause: new editors initialized with visible_lines=25 (hardcoded default) but the actual viewport showed ~45 lines. The model thought line 30 was "off-screen" and scrolled to compensate. Fixed by syncing viewport dimensions on tab/split creation and adding no-padding scroll for clicks.
Every keystroke spawned a new thread for syntax highlighting debouncing, causing visible highlight flashing. Fixed with two changes: replaced thread-per-debounce with event-loop deadline timers (no new threads per keystroke), and added immediate highlight shifting that adjusts existing highlights by the edit delta before the background parse completes.
No way to quickly switch between recently opened files. Built a persistent MRU list with Cmd+E modal across 5 phases: JSON persistence for up to 50 entries, fuzzy filtering with file type icons and "time ago" timestamps, and automatic tracking from all file-open methods (CLI, dialog, sidebar, drag-and-drop).
Built a tree-sitter-based code outline panel supporting 10 languages (Rust, TypeScript, JavaScript, Python, Go, Java, PHP, C/C++, Markdown, YAML). Uses range-containment algorithm for code and level-based hierarchy for Markdown. Runs on the syntax worker thread alongside highlighting. Critical bug: dock clicks fell through to the editor because hit-test priority didn't include docks.
Lessons learned
Key takeaways from building Token with AI assistance.
Structure enables autonomy
The more explicit your documentation, the more independently AI agents can work.
Modes prevent scope creep
Declaring Build/Improve/Sweep at session start keeps both human and AI focused.
Gap docs are underrated
When a feature is "mostly done," a gap document transforms fuzzy incompleteness into a concrete checklist.
Review docs before code
Having AI review reference documentation catches algorithmic bugs before they become code bugs.
Per-item primitives scale
When extending single-item code to multi-item, the "primitive + wrapper" pattern works reliably.
Want to see the conversations?
All 173+ threads are public. See how every feature was planned, implemented, and debugged.
Browse threads on Amp →