v0.6.0

How Tine was — and is — built

The first month in retrospect: what mattered once implementation became cheap, and how the process is changing so speed can compound instead of merely accumulating risk.

AI disclosure: I asked the agents that built Tine to analyze our development history and draft this post. I read it to check it, but it was written by GPT-5.6-Sol despite being written in the first person. The underlying, more detailed observations are also public in Fable's findings and Sol's findings.

A few people have asked how it was possible to build Tine this quickly, and whether I use some special harness, prompt library, or vibe-coding trick. For scale: the first Rust-core commit was on June 14; by July 12 Tine had gone through five feature series, shipped desktop and Android builds, and accumulated 73 cataloged UI regressions. Release count and commit count are poor measures of quality, but this has plainly been a lot of software in 29 days.

The short answer is that I have no magic prompt. At the beginning I used ordinary Claude Code in a terminal and talked to it normally. My prompts are often short, conversational, and uncertain: “I may not be understanding,” “what do you think?”, or a description of something that felt wrong while using the app. Most of the implementation bandwidth comes from how capable current models and coding harnesses are.

What may be unusual is how I organize judgment, evidence, and feedback around that code. Once implementation becomes cheap, those become the bottlenecks. The process around Tine is mostly an attempt to spend my attention on decisions only I need to make, while making the agents prove as much else as possible.

The core loop is use, notice, fix, repeat

For most of the project the practical loop was:

  1. an agent implemented, tested, built, and deployed a production binary;
  2. I used that binary on my real graph;
  3. I reported the next thing that felt wrong;
  4. the agent traced it, added a regression test where possible, and deployed again.

The reports are often tiny interaction details: where the caret lands when it crosses into a multiline block, whether entering edit mode spreads Markdown delimiters apart, what shift-clicking a bullet does, or whether a quick-capture window accepts typing without a preparatory click. These are difficult to derive from a feature checklist, but they make much of the difference between software that merely works and software that feels good.

That is why “tests pass” is not done: a fix normally has to be deployed into the copy I actually use. Newer harnesses reduce how often I rediscover old failures; they do not replace dogfooding.

Start with constraints strong enough to decide things

Tine did not begin as “make a note-taking app.” The target was a fast, local-first, Logseq-compatible outliner that works directly on an existing Markdown or Org graph. That gives us several non-negotiable constraints:

  • files remain ordinary, interoperable files;
  • original Logseq is the default behavioral reference;
  • speed is part of the product, not a cleanup task for later;
  • saving is extremely conservative, because one data-loss incident matters more than several missing features.

These are practical decision rules. Logseq compatibility supplies the default answer to many interaction disputes. Plain-file compatibility rules out convenient proprietary-storage shortcuts. A feature that threatens the performance budget can be stopped even if it is otherwise useful.

I have a computer-science background, but I rarely tell an agent which class or function to change. I specify observable behavior: moving upward into a wrapped block should land on its bottom visual line; quick capture should mean “press the shortcut, then type”; selecting text and typing a Markdown delimiter should behave like Logseq. The agent finds the mechanism. I preserve the product model and notice when a locally plausible fix violates it.

Twenty-two years of using Linux and following open-source software probably matter too. Plain files, honest limitations, ecosystem compatibility, and respect for upstream feel like defaults. When a feature is requested, we compare it with the best relevant prior art instead of assuming either the request or our first design is optimal. Sometimes the useful comparison is surprising — for command search, Gmail can be as relevant as another outliner.

Replace opinions with oracles

The most productive recurring idea has been: if there is an authority you can execute or inspect, do not settle an argument from memory.

For compatibility, the authority is original Logseq and mldoc, its parser. The agents inspect upstream source and run the same input through both implementations. This is more reliable than trying examples until the output looks right. By July, the new Rust parser lsdoc had an oracle corpus of more than a thousand cases, with known divergences explicit rather than quietly ignored.

For performance, the authority is measurement plus an architectural argument. I became suspicious of rolling baselines: if every release may become five percent slower than the previous one, a thirty-percent gate can still permit indefinite decay. Tine now keeps an immutable older baseline as an anchor. I also push back when a benchmark is used to imply a complexity claim. “This input was fast” is not proof that the algorithm is linear.

For UI behavior, the authority increasingly is the real application rather than a simulated component. A browser-level unit test can say that a handler produced the right state while missing that WebKit put the caret on the wrong visual line or Plasma never focused a new window. The Linux release gate now launches the production Tauri app under a real window manager, drives it, takes screenshots, and verifies native focus and persistence. Linux remains by far the strongest-tested platform; I would rather say that plainly than pretend the evidence is symmetric.

The harness grew out of failures. Caret and collapse regressions became a historical catalog with executable cases. Incomplete releases became artifact-inventory checks. Each failure is expected to leave something stronger than a one-off patch.

Use agents adversarially, not only productively

A confident model explanation is cheap, including a confident explanation that a bug is impossible, irrelevant, or already solved. I delegate implementation heavily, but important claims have to become testable.

Instead of asking “is this parser linear?”, ask an auditor to disprove linearity and require a scaling family. Instead of accepting that a state is unreachable, have another agent check the proof against the actual program. Instead of fixing only the reported editing bug, audit adjacent transitions that share its state machine. In longer loops, one agent can act as prover and another as verifier.

Audits run toward a fixed point rather than as ceremony. An audit only counts for the exact source it examined; a later relevant change invalidates it. This matters particularly for data safety, where an impressive report about yesterday's tree is not evidence about today's fix.

This skepticism applies to pleasant news too. When an agent said a performance refactor had improved things, I asked why the benchmark was not faster. When it said it had researched upstream but had not read the source, I changed the process rather than merely asking it to try harder next time.

Optimize human round trips, not model labor

The scarce resource is not tokens or agent-hours. It is the number of times I must stop, reconstruct context, decide something, and test the product before a change matures.

That changed how we collaborate. We plan batches while I am available; then I say “go” and the agent executes while I am away. Decision packets use short labels so I can answer precisely without quoting paragraphs. Plans and acceptance criteria are written down so they survive context compaction. The aim is to spend my time on product judgment, not on watching builds or reconstructing issue descriptions.

Autonomy is bounded by decision type. A clear bug that can be reproduced and regression-tested may be fixed, deployed, and reported as fixed on master without waiting for me. An unclear bug gets a precise request for evidence. A feature or lasting product commitment comes back with research and a recommendation for me to decide. This workflow is recent; it explains how we are reducing the ongoing maintenance burden, not all of the project's early speed.

Releases are becoming similarly unattended. The changelog is treated as a list of obligations: what regression proves each item, whether documentation or the website must change, which issue reporters need follow-up, and which artifacts must exist. Slow platform builds run in parallel; publishing uses those exact tested artifacts. A release is not complete merely because a Git tag exists.

This operating system did not exist fully formed. Early speed came mostly from capable models, rapid deployment, and intense feedback. The regression catalog, real-app harness, release gates, and delegated issue workflow appeared because the initial process kept showing where it depended too much on my memory and availability.

What I would take from this

I do not think the lesson is “learn my prompts.” Copying the visible process wholesale would probably create ceremony around the wrong risks.

Decide what must remain true, then make those claims increasingly executable. Give agents broad implementation responsibility but clear product and risk boundaries. Research the best existing behavior before inventing a new one. Use independent agents to attack comforting conclusions. Turn real regressions into durable tests at the lowest layer that can genuinely catch them. Preserve an honest distinction between what passed locally, what passed in a simulated UI, what worked in the real app, and what a user on another platform still needs to confirm.

Modern agents can generate an astonishing amount of working software. The interesting human work shifts upward: choosing invariants, recognizing bad abstractions, deciding what belongs in the product, and designing evidence strong enough that speed can compound.

💬 Original process post ↗ 📝 Fable's findings ↗ 📝 Sol's findings ↗ 📋 Current changelog ↗

From the discussion

Checked again on July 18, 2026, this post had not collected a substantive comment thread. The questions that prompted it are summarized in the previous release's discussion.

This page preserves the Reddit post's full argument with only web-layout editing. It is a process note associated with v0.6.0, not an announcement that the release has shipped.