Case study/Deep read

Inkling

A markdown workspace that keeps every note as a plain file on your own disk, lets a crew edit one document live, and refuses to touch git unless a person presses push.

long-form write-up

Inkling in use

Inkling, the local-first markdown workspace.
inkling.octyn.co
Two cursors editing the same Inkling document live.
live editing

Inkling is OCTYN's own product. We built it, we write in it every day, and the server behind it is deployed and operated by us.

1. The situation

A notes app that owns your notes is the trap. The file is inside a database you cannot open, the sync is a subscription, and the day you stop paying, the writing is hostage. The other half of the trap is the opposite one: keep everything as plain files in a git repo and you get ownership with no collaboration at all, because two people cannot type into the same file and git is not a real-time protocol.

Inkling was started on 2026-07-11 to take both halves. Every note is a plain markdown file in a real folder on the writer's own disk, greppable and backed up by whatever already backs up that folder, and a crew can still sit in one document together.

2. Why it was hard

Git is the hard part, and the danger is not merge conflicts. It is the automatic write.

The first version treated the local working tree as the live source of truth and pushed on an eight second debounce. The design note that killed that, written 2026-07-12, states the problem plainly: a bad autosave or a background operation can land in git without a human deciding to, which is exactly the one wrong move and we lose a document risk. It also names the behaviour that fear produces in users, which is cloning the same branch several times so there is always a spare, and then having the same document in four places.

The second hard part is that real-time editing and branches disagree about what a document is. A live session is keyed to the document. A branch is keyed to the repository. Two people can be in the same paragraph while sitting on different branches, and the system has to hold both facts at once without either of them discovering it the hard way.

3. What was built

Electron, with a renderer of plain ES modules and no framework. The editor is CodeMirror 6 with a live preview layer written for it, after a pivot away from a WYSIWYG component that caused drag duplication, over-granular undo and could not show raw syntax on the active line. The read view is markdown-it with highlight.js, mermaid, heading anchors and a wiki-link plugin.

Real-time editing is Yjs over a websocket, wired into CodeMirror through y-codemirror.next. The room is keyed to the document rather than the branch, it is persisted server side, and a late joiner gets the current state on arrival rather than an empty buffer. Every keystroke is also mirrored to that participant's own disk copy, so the server is a relay and never the only place the writing lives.

Branches are the spine. Each (repository, branch) pair gets its own checkout on disk, worktree style, so switching branch is switching directory rather than running a checkout over somebody's uncommitted work, and several branches can be open at once. Push is a deliberate, confirmed act: it takes the session's current text and commits it to the branch that person chose. There is no auto-commit and no auto-push anywhere in the model.

Around the editor: a multi-root file explorer, a command palette instead of a toolbar, twelve desaturated themes, tiling panes, a freeform canvas of note cards, and a force-directed graph of notes and the links between them. There is also an MCP server that exposes the vault to an outside assistant, which is how an agent reads and edits the same notes a person is looking at.

The AI assistant is provider agnostic and its key never ships in the client. Requests go through an OpenAI-compatible proxy on OCTYN's own server, which means the key can be rotated and the feature can be switched off remotely without anybody reinstalling anything.

4. What it does under load

Honestly: not measured, and that is the state as of 2026-09-14. There is no download telemetry in the repo and no usage instrumentation, so there is no install count to publish and no concurrent-session figure. Publishing one would mean inventing it.

What can be stated with a date: version 0.2.3 on 2026-07-14, with Windows and Linux builds produced by electron-builder and an auto-update feed served from OCTYN's own server. 144 commits between 2026-07-11 and 2026-07-14, across 86 tracked files. The server is a container on the OCTYN VPS with its own volume, and it redeploys when a push to main touches the server directory.

The one load-shaped design decision that is already made: the live session is persisted, so the number that matters later is participants per document rather than documents per server, and nothing in the current build pretends to know what that ceiling is.

5. What happens when it breaks

Of the eight test files in the repo on 2026-07-14, every one is about git or workspace safety rather than about editing: safe-git, clone-guard, checkout-path, push-noop, roots-dedup, workspaces, and two about share spaces. That distribution is the whole risk model written down. An editor bug loses a keystroke. A git bug loses a document.

The failure paths that follow from the model:

Lose the network and the editor keeps working, because the file is already on disk and autosave writes there. What stops is the session, not the writing.

Lose the server and the same thing is true, plus push still works, because push goes to GitHub and not through us.

Edit a file from outside, with an agent, a terminal or a git pull, and the file watcher refreshes the tree and reloads clean open notes. It ignores writes the app made itself, so the app does not chase its own tail.

The push path is guarded rather than trusted: a push that would be a no-op is one of the cases with a test against it, because a confirm dialog that promises to save your work and then does nothing is worse than an error.

The unresolved one, and it is worth saying out loud: the desktop build is not code signed, so Windows SmartScreen warns on first run. That is a cost paid by every person who downloads it and it is not fixed by anything in the code.

6. Who maintains it, and what that costs in attention

The person who wrote it, which is the same arrangement as everything else here.

Steady state is quiet, because the parts that could page somebody are the parts that were deliberately made optional. Notes are local, so a server outage is a degraded feature and not an outage of the product. Git is manual, so nothing runs unattended against a repository.

What costs real attention is Electron packaging, and it is seasonal rather than continuous. The main process is bundled with all dependencies inlined specifically because module resolution failed inside the installed app while working perfectly in development, which is a class of bug that only appears after you have shipped. Linux artefacts cannot be built on Windows at all, so the release is a two machine job.

7. What changes when requirements change in six months

Configuration, no release: which model the assistant uses, whether the built-in assistant is on at all, and the update feed. All three are server side by design, which is the reason the proxy exists.

A small code change: another theme, another export format, another view over the same index. The renderer is plain modules, so a view is a file.

A larger code change: anything that alters what a document is. Comments, suggestions, or per-block permissions all sit on top of the Yjs document and touch the branch model at the same time, and those two were deliberately kept apart.

A rebuild: a mobile or browser-only client. The whole premise is a real folder on a real disk, and a phone does not have one in the sense this design means. The shared editor that already runs in a browser is a viewer on a session, not the app.

8. What we would do differently

Write the branch model first. The autosave-to-git version existed, was used, and had to be argued out of the product a day later, and the argument was won by a design note rather than by a fix.

Instrument downloads on day one. The claim being made about this product is that people can have it, and there is currently no number attached to that claim.

And pick the editor before building on it. Two editors were in the dependency list at once for longer than was comfortable, one of them unused, which is the kind of thing that looks like optionality and is really an unmade decision.

  • 2026-07-14

    Version 0.2.3, Windows and Linux builds

    package.json, octynhq/inkling
  • 2026-07-11 to 2026-07-14

    144 commits across 86 tracked files

    git log and git ls-files, octynhq/inkling
  • 2026-07-14

    8 test files, all of them about git or workspace safety

    test/, octynhq/inkling
  • 2026-09-14

    No install count recorded

    no download telemetry in the repo

Want something like Inkling for your operation?

Book a call →