Build Drafts Pro

YESreplaces $1.67/mosaves $20.04/yrback to the verdict

0%0 of 16 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A capture surface whose only hard requirement is that it appears the instant you ask for it, plus a scriptable action system that sends the captured text onward, with a queue so an action failing never costs you what you wrote.

estimated effort weekendthe files for this build are in the project pack

RuntimeTypeScript with a local application and SQLiteLaunchA global hotkey to a pre-warmed windowActionsSandboxed scripts over a small APIDeliveryA queue with retries for anything leaving the machineStorageEvery draft kept, including sent ones

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Runs the application and the action sandbox.

    Get it nodejs.org, or nvm install 22. open ↗

    Verify node --version prints v22 or higher

  2. installfree

    Why Everything depends on the window appearing instantly from anywhere, and this is platform-specific work.

    Get it Whatever your desktop framework provides, and check it works when another application is fullscreen.

    Verify The hotkey fires from a fullscreen application and the window appears above it

  3. have readyfree

    Why The queue and retry behaviour are only testable against something that can actually be unreachable.

    Get it A note-taking service, a task tool, or a webhook endpoint you control. One is enough.

    Verify An action posts to it successfully and queues when it is unreachable

  4. decidefree

    Why It is the primary requirement, and a threshold you did not write down becomes whatever the implementation happens to do.

    Get it Pick a number in milliseconds you would notice, and measure against it from phase 1 rather than at the end.

    Verify A number is written down and the measurement is in the test output

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- drafts(id, body, created_at, updated_at, state, source) · state is inbox, archived or trashed
- tags(draft_id, tag) · assigned by hand or by an action
- actions(id, name, script, hotkey, requires_network, enabled)
- runs(id, draft_id, action_id, started_at, ended_at, status, output, error)
- queue(id, draft_id, action_id, attempts, next_attempt_at, delivered_at, last_error)
- versions(draft_id, ordinal, body, at) · because a destructive action should never be the only copy
- A draft is never deleted by an action succeeding, which is what makes running actions safe.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
DB_PATHrequired~/.local/share/drafts/drafts.dbEvery draft ever captured, including archived ones. Back it up.
CAPTURE_HOTKEYrequiredCmd+Shift+SpaceThe global hotkey. Choose one nothing else claims, which is harder than it sounds.
MAX_CAPTURE_DELAY_MSrequired120The threshold that fails the build. The primary requirement made checkable.
ACTION_DIRrequired~/.config/drafts/actionsAction scripts. Imported ones sit here disabled until you enable them.
SYNC_REMOTEoptionals3://my-drafts/storePhase 5 only. Absent means one machine, which is a fine way to run.

The build, in order

  1. A box that is already there

    The hotkey produces a cursor in an empty box with no perceptible delay.

    1. Show a built window, do not build one. The first capture is the one that matters.

      Files src/window.ts

    2. Keypress to typeable, logged. A number, not an impression.

      Files src/metrics.ts

    3. Killing the process mid-word must lose nothing.

      Files src/persist.ts

    done when · tick each as it passes
    watch out
    • Creating the window on the hotkey means the first capture of a session takes a second or more, which is exactly long enough for the thought to be gone, and it is the failure the whole tool exists to prevent. Keep a window warm and show it, rather than building one.
  2. Actions that do something with the text

    One keystroke sends the draft somewhere useful.

    1. Body, tags, a few operations. Small is what keeps it sandboxable.

      Files src/api.ts

    2. Declared capabilities only. Test that an undeclared access fails.

      Files src/sandbox.tssrc/sandbox.test.ts

    3. Output and error. Debugging an action without the record is guesswork.

      Files src/runs.ts

    done when · tick each as it passes
    watch out
    • Running action scripts with the application's full privileges means one copied script can read every file you own, and people copy scripts from forums constantly. Sandbox by default and require an action to declare network or filesystem access explicitly, which also makes the queue decision in phase 3 possible.
  3. Nothing lost when the destination is down

    An action sending somewhere unreachable retries instead of failing you.

    1. The declaration from phase 2 is what makes this automatic.

      Files src/queue.ts

    2. Then surface as failed rather than retrying forever.

      Files src/worker.ts

    3. Delivery is not deletion. The archive is what makes capture safe.

      Files src/drafts.ts

    done when · tick each as it passes
    watch out
    • An action that posts to a service and reports success on a request that was never acknowledged loses the note quietly, and you find out when you go looking for something you are sure you wrote down. Only mark delivered on a confirmed response, and keep the draft regardless.
  4. Finding what you captured

    Six months of captures are searchable in the time it takes to type.

    1. State is a filter, not a boundary. Archived is where things live.

      Files src/search.ts

    2. At ten thousand drafts. Anything slower breaks the habit.

      Files src/search.ts

    3. So an action that rewrote a draft did not hide the original.

      Files src/versions.ts

    done when · tick each as it passes
    watch out
    • Excluding archived drafts from search makes the archive worthless, and archived is where almost everything ends up. Search everything by default and let state be a filter rather than a boundary.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more writing tools.