Vibecode Drafts Pro
track this build4 phases, 12 steps, beginner friendly0%The core loop is small enough for a capable coding agent to produce a useful local version in one sitting. For Drafts Pro, capture text instantly, run reusable transformations, and file the result into local destinations. The hard boundary is its iphone and mac capture speed, action directory, and apple automation depth, plus polish, integrations, and proprietary language models.
You are building a lean indie version of Drafts Pro. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # Drafts Pro · indie build 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: **weekend**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | TypeScript with a local application and SQLite | capture must work with no network and no login | | Launch | A global hotkey to a pre-warmed window | cold-starting a window is the difference between using this and not | | Actions | Sandboxed scripts over a small API | the value is what happens after capture, and that has to be yours to define | | Delivery | A queue with retries for anything leaving the machine | capture must never depend on a destination being reachable | | Storage | Every draft kept, including sent ones | the archive is what makes capture safe to do carelessly | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Node.js 22 or newer** · free - Why: Runs the application and the action sandbox. - Get it: nodejs.org, or nvm install 22. - Verify: node --version prints v22 or higher - [ ] **A global hotkey mechanism for your platform** · free - 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 - [ ] **One real destination for an action** · free - 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 - [ ] **Your acceptable capture delay** · free - 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 ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - Mobile capture. - Dictation and voice capture. - The large community action library. - Rich text and attachments. - its iPhone and Mac capture speed, action directory, and Apple automation depth - cross-device sync - large proprietary style models - browser and office-suite extensions - team style guides If one of those is essential to you, that is the reason to keep paying for Drafts Pro, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · Drafts Pro The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a capture box that opens instantly and sends text wherever it needs to go to replace Drafts Pro. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Runtime: TypeScript with a local application and SQLite · capture must work with no network and no login - Launch: A global hotkey to a pre-warmed window · cold-starting a window is the difference between using this and not - Actions: Sandboxed scripts over a small API · the value is what happens after capture, and that has to be yours to define - Delivery: A queue with retries for anything leaving the machine · capture must never depend on a destination being reachable - Storage: Every draft kept, including sent ones · the archive is what makes capture safe to do carelessly ### Data model (create this before Phase 1) - 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. ### Phase 1 · A box that is already there Build: A global hotkey showing a pre-warmed window with the cursor placed. Measure the delay from keypress to typeable and treat anything above a small threshold as a defect. Text persists as you type, not on close. Trap: 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. Done when: The hotkey to typeable delay is measured and below the threshold, including the first invocation after a cold start. Text persists as typed, verified by killing the process mid-word. The window appears above whatever is focused. Dismissing keeps the draft rather than discarding it. Do not build yet: No actions or queue. ### Phase 2 · Actions that do something with the text Build: A scripted action system with a small API: the draft body, tags, and a few operations. Run scripts sandboxed with no ambient filesystem or network access unless the action declares it. Record every run. Trap: 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. Done when: An action transforms a draft and the result is visible. A script attempting filesystem access without declaring it fails, tested directly. Every run is recorded with its output or error. An action that throws leaves the draft untouched rather than half-modified. Do not build yet: No queue or retries yet. ### Phase 3 · Nothing lost when the destination is down Build: Queue any action declaring network access. Retry with backoff. Show pending and failed deliveries. Capture and local actions continue to work entirely offline. Trap: 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. Done when: A network action against an unreachable destination queues and retries with backoff. Capture and local actions work fully offline, tested with networking disabled. Pending and failed deliveries are visible and retryable. A delivered action still leaves the draft in the archive. Do not build yet: No search or sync yet. ### Phase 4 · Finding what you captured Build: Full text search across drafts including archived ones, with tag and date filters. Search as you type. Include draft versions so text removed by an action is still findable. Trap: 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. Done when: Search covers archived drafts by default, verified against an archived capture. Results appear as you type across ten thousand drafts. Tag and date filters combine with text. Text removed by an action is still findable through versions. Do not build yet: No sync or sharing yet. ### Phase 5 · Two machines and a shared action library Build: Sync drafts and actions through a store you control. Import an action from a file or URL showing its declared capabilities and full source before enabling it. Never enable an imported action automatically. Trap: An imported action that runs before you read it is arbitrary code execution with a friendly name, and action libraries are exactly how people share these. Show the source and declared capabilities, require an explicit enable, and re-prompt when an updated action changes what it declares. Done when: Drafts sync between two machines without duplication. An imported action shows its source and declared capabilities and does not run until enabled. An update changing declared capabilities re-prompts. A sync conflict on one draft keeps both versions. Do not build yet: Nothing after this. ### Out of scope (and why) - Mobile capture, which is where most quick capture actually happens and is the reason the original exists on a phone. - Dictation and voice capture, which is a substantial platform integration on its own. - The large community action library, which is most of the hosted product's practical value. - Rich text and attachments, since plain text is what makes capture instant and portable. ### README must contain - That the hotkey to typeable delay is measured and treated as the primary requirement - That actions run sandboxed and must declare network or filesystem access - That network actions queue and a draft is never deleted by delivery - That search covers archived drafts and versions by default - That an imported action shows its source and does not run until enabled ===== AGENTS.md ===== # Agent instructions · Drafts Pro indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: TypeScript with a local application and SQLite, A global hotkey to a pre-warmed window, Sandboxed scripts over a small API, A queue with retries for anything leaving the machine, Every draft kept, including sent ones. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - 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. - 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. - 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. - 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. ===== BUILD_PLAN.md ===== # Build plan · Drafts Pro 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. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · A box that is already there The hotkey produces a cursor in an empty box with no perceptible delay. ### Steps 1. Pre-warm the window Show a built window, do not build one. The first capture is the one that matters. Files: `src/window.ts` 2. Measure the delay Keypress to typeable, logged. A number, not an impression. Files: `src/metrics.ts` 3. Persist as you type Killing the process mid-word must lose nothing. Files: `src/persist.ts` ### Done when - [ ] Hotkey to typeable is measured and below threshold - [ ] A cold start first capture is also fast - [ ] Killing mid-word loses nothing - [ ] Dismissing keeps the draft ### 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. ## Phase 2 · Actions that do something with the text One keystroke sends the draft somewhere useful. ### Steps 1. Define a small action API Body, tags, a few operations. Small is what keeps it sandboxable. Files: `src/api.ts` 2. Sandbox by default Declared capabilities only. Test that an undeclared access fails. Files: `src/sandbox.ts`, `src/sandbox.test.ts` 3. Record every run Output and error. Debugging an action without the record is guesswork. Files: `src/runs.ts` ### Done when - [ ] An action transforms a draft visibly - [ ] Undeclared filesystem access fails - [ ] Every run is recorded with output or error - [ ] A throwing action leaves the draft untouched ### 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. ## Phase 3 · Nothing lost when the destination is down An action sending somewhere unreachable retries instead of failing you. ### Steps 1. Queue declared network actions The declaration from phase 2 is what makes this automatic. Files: `src/queue.ts` 2. Retry with backoff and a cap Then surface as failed rather than retrying forever. Files: `src/worker.ts` 3. Keep the draft regardless Delivery is not deletion. The archive is what makes capture safe. Files: `src/drafts.ts` ### Done when - [ ] A network action queues and retries against an unreachable destination - [ ] Capture and local actions work offline - [ ] Pending and failed deliveries are visible and retryable - [ ] Delivery leaves the draft archived ### 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. ## Phase 4 · Finding what you captured Six months of captures are searchable in the time it takes to type. ### Steps 1. Index everything including archived State is a filter, not a boundary. Archived is where things live. Files: `src/search.ts` 2. Search as you type At ten thousand drafts. Anything slower breaks the habit. Files: `src/search.ts` 3. Index versions too So an action that rewrote a draft did not hide the original. Files: `src/versions.ts` ### Done when - [ ] Search covers archived drafts by default - [ ] Results appear as you type at ten thousand drafts - [ ] Tag and date filters combine with text - [ ] Text removed by an action is findable ### 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. ## Not in this build - Mobile capture. - Dictation and voice capture. - The large community action library. - Rich text and attachments. ## After v1, if you want it - Actions chained into a workflow, once single actions are reliable - Templates that pre-fill a capture for a recurring kind of note - A daily digest of what you captured, which is where an archive starts being read ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required. Every draft ever captured, including archived ones. Back it up. DB_PATH=~/.local/share/drafts/drafts.db # Required. The global hotkey. Choose one nothing else claims, which is harder than it sounds. CAPTURE_HOTKEY=Cmd+Shift+Space # Required. The threshold that fails the build. The primary requirement made checkable. MAX_CAPTURE_DELAY_MS=120 # Required. Action scripts. Imported ones sit here disabled until you enable them. ACTION_DIR=~/.config/drafts/actions # Optional. Phase 5 only. Absent means one machine, which is a fine way to run. SYNC_REMOTE=s3://my-drafts/store
You are building a lean indie version of Drafts Pro. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # Drafts Pro · indie build 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: **weekend**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | TypeScript with a local application and SQLite | capture must work with no network and no login | | Launch | A global hotkey to a pre-warmed window | cold-starting a window is the difference between using this and not | | Actions | Sandboxed scripts over a small API | the value is what happens after capture, and that has to be yours to define | | Delivery | A queue with retries for anything leaving the machine | capture must never depend on a destination being reachable | | Storage | Every draft kept, including sent ones | the archive is what makes capture safe to do carelessly | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Node.js 22 or newer** · free - Why: Runs the application and the action sandbox. - Get it: nodejs.org, or nvm install 22. - Verify: node --version prints v22 or higher - [ ] **A global hotkey mechanism for your platform** · free - 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 - [ ] **One real destination for an action** · free - 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 - [ ] **Your acceptable capture delay** · free - 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 ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - Mobile capture. - Dictation and voice capture. - The large community action library. - Rich text and attachments. - its iPhone and Mac capture speed, action directory, and Apple automation depth - cross-device sync - large proprietary style models - browser and office-suite extensions - team style guides If one of those is essential to you, that is the reason to keep paying for Drafts Pro, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · Drafts Pro The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a capture box that opens instantly and sends text wherever it needs to go to replace Drafts Pro. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Runtime: TypeScript with a local application and SQLite · capture must work with no network and no login - Launch: A global hotkey to a pre-warmed window · cold-starting a window is the difference between using this and not - Actions: Sandboxed scripts over a small API · the value is what happens after capture, and that has to be yours to define - Delivery: A queue with retries for anything leaving the machine · capture must never depend on a destination being reachable - Storage: Every draft kept, including sent ones · the archive is what makes capture safe to do carelessly ### Data model (create this before Phase 1) - 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. ### Phase 1 · A box that is already there Build: A global hotkey showing a pre-warmed window with the cursor placed. Measure the delay from keypress to typeable and treat anything above a small threshold as a defect. Text persists as you type, not on close. Trap: 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. Done when: The hotkey to typeable delay is measured and below the threshold, including the first invocation after a cold start. Text persists as typed, verified by killing the process mid-word. The window appears above whatever is focused. Dismissing keeps the draft rather than discarding it. Do not build yet: No actions or queue. ### Phase 2 · Actions that do something with the text Build: A scripted action system with a small API: the draft body, tags, and a few operations. Run scripts sandboxed with no ambient filesystem or network access unless the action declares it. Record every run. Trap: 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. Done when: An action transforms a draft and the result is visible. A script attempting filesystem access without declaring it fails, tested directly. Every run is recorded with its output or error. An action that throws leaves the draft untouched rather than half-modified. Do not build yet: No queue or retries yet. ### Phase 3 · Nothing lost when the destination is down Build: Queue any action declaring network access. Retry with backoff. Show pending and failed deliveries. Capture and local actions continue to work entirely offline. Trap: 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. Done when: A network action against an unreachable destination queues and retries with backoff. Capture and local actions work fully offline, tested with networking disabled. Pending and failed deliveries are visible and retryable. A delivered action still leaves the draft in the archive. Do not build yet: No search or sync yet. ### Phase 4 · Finding what you captured Build: Full text search across drafts including archived ones, with tag and date filters. Search as you type. Include draft versions so text removed by an action is still findable. Trap: 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. Done when: Search covers archived drafts by default, verified against an archived capture. Results appear as you type across ten thousand drafts. Tag and date filters combine with text. Text removed by an action is still findable through versions. Do not build yet: No sync or sharing yet. ### Phase 5 · Two machines and a shared action library Build: Sync drafts and actions through a store you control. Import an action from a file or URL showing its declared capabilities and full source before enabling it. Never enable an imported action automatically. Trap: An imported action that runs before you read it is arbitrary code execution with a friendly name, and action libraries are exactly how people share these. Show the source and declared capabilities, require an explicit enable, and re-prompt when an updated action changes what it declares. Done when: Drafts sync between two machines without duplication. An imported action shows its source and declared capabilities and does not run until enabled. An update changing declared capabilities re-prompts. A sync conflict on one draft keeps both versions. Do not build yet: Nothing after this. ### Out of scope (and why) - Mobile capture, which is where most quick capture actually happens and is the reason the original exists on a phone. - Dictation and voice capture, which is a substantial platform integration on its own. - The large community action library, which is most of the hosted product's practical value. - Rich text and attachments, since plain text is what makes capture instant and portable. ### README must contain - That the hotkey to typeable delay is measured and treated as the primary requirement - That actions run sandboxed and must declare network or filesystem access - That network actions queue and a draft is never deleted by delivery - That search covers archived drafts and versions by default - That an imported action shows its source and does not run until enabled ===== AGENTS.md ===== # Agent instructions · Drafts Pro indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: TypeScript with a local application and SQLite, A global hotkey to a pre-warmed window, Sandboxed scripts over a small API, A queue with retries for anything leaving the machine, Every draft kept, including sent ones. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - 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. - 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. - 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. - 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. ===== BUILD_PLAN.md ===== # Build plan · Drafts Pro 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. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · A box that is already there The hotkey produces a cursor in an empty box with no perceptible delay. ### Steps 1. Pre-warm the window Show a built window, do not build one. The first capture is the one that matters. Files: `src/window.ts` 2. Measure the delay Keypress to typeable, logged. A number, not an impression. Files: `src/metrics.ts` 3. Persist as you type Killing the process mid-word must lose nothing. Files: `src/persist.ts` ### Done when - [ ] Hotkey to typeable is measured and below threshold - [ ] A cold start first capture is also fast - [ ] Killing mid-word loses nothing - [ ] Dismissing keeps the draft ### 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. ## Phase 2 · Actions that do something with the text One keystroke sends the draft somewhere useful. ### Steps 1. Define a small action API Body, tags, a few operations. Small is what keeps it sandboxable. Files: `src/api.ts` 2. Sandbox by default Declared capabilities only. Test that an undeclared access fails. Files: `src/sandbox.ts`, `src/sandbox.test.ts` 3. Record every run Output and error. Debugging an action without the record is guesswork. Files: `src/runs.ts` ### Done when - [ ] An action transforms a draft visibly - [ ] Undeclared filesystem access fails - [ ] Every run is recorded with output or error - [ ] A throwing action leaves the draft untouched ### 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. ## Phase 3 · Nothing lost when the destination is down An action sending somewhere unreachable retries instead of failing you. ### Steps 1. Queue declared network actions The declaration from phase 2 is what makes this automatic. Files: `src/queue.ts` 2. Retry with backoff and a cap Then surface as failed rather than retrying forever. Files: `src/worker.ts` 3. Keep the draft regardless Delivery is not deletion. The archive is what makes capture safe. Files: `src/drafts.ts` ### Done when - [ ] A network action queues and retries against an unreachable destination - [ ] Capture and local actions work offline - [ ] Pending and failed deliveries are visible and retryable - [ ] Delivery leaves the draft archived ### 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. ## Phase 4 · Finding what you captured Six months of captures are searchable in the time it takes to type. ### Steps 1. Index everything including archived State is a filter, not a boundary. Archived is where things live. Files: `src/search.ts` 2. Search as you type At ten thousand drafts. Anything slower breaks the habit. Files: `src/search.ts` 3. Index versions too So an action that rewrote a draft did not hide the original. Files: `src/versions.ts` ### Done when - [ ] Search covers archived drafts by default - [ ] Results appear as you type at ten thousand drafts - [ ] Tag and date filters combine with text - [ ] Text removed by an action is findable ### 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. ## Not in this build - Mobile capture. - Dictation and voice capture. - The large community action library. - Rich text and attachments. ## After v1, if you want it - Actions chained into a workflow, once single actions are reliable - Templates that pre-fill a capture for a recurring kind of note - A daily digest of what you captured, which is where an archive starts being read ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required. Every draft ever captured, including archived ones. Back it up. DB_PATH=~/.local/share/drafts/drafts.db # Required. The global hotkey. Choose one nothing else claims, which is harder than it sounds. CAPTURE_HOTKEY=Cmd+Shift+Space # Required. The threshold that fails the build. The primary requirement made checkable. MAX_CAPTURE_DELAY_MS=120 # Required. Action scripts. Imported ones sit here disabled until you enable them. ACTION_DIR=~/.config/drafts/actions # Optional. Phase 5 only. Absent means one machine, which is a fine way to run. SYNC_REMOTE=s3://my-drafts/store
You are building a production product version of Drafts Pro. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== PRODUCT.md ===== # Drafts Pro · product brief ## Problem The core loop is small enough for a capable coding agent to produce a useful local version in one sitting. For Drafts Pro, capture text instantly, run reusable transformations, and file the result into local destinations. The hard boundary is its iphone and mac capture speed, action directory, and apple automation depth, plus polish, integrations, and proprietary language models. ## Product outcome A capture box that is already open by the time you look at it, an action system that cannot quietly read your filesystem, and an archive where nothing you typed is ever lost to a failed delivery. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - macOS, Windows, or Linux - local files - optional OpenAI or Anthropic API key for semantic rewrites ## Explicit non-goals for v1 - Mobile capture. - Dictation and voice capture. - The large community action library. - Rich text and attachments. - its iPhone and Mac capture speed, action directory, and Apple automation depth - cross-device sync - large proprietary style models - browser and office-suite extensions - team style guides ## Success criteria - Capture delay is confirmed below the threshold including a cold start - Undeclared filesystem access is confirmed to fail - An unreachable destination is confirmed to queue rather than lose the draft - Search is confirmed to cover archived drafts - An imported action is confirmed not to run until enabled ===== BRIEF.md ===== # Build brief · Drafts Pro The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a capture box that opens instantly and sends text wherever it needs to go to replace Drafts Pro. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Runtime: TypeScript with a local application and SQLite · capture must work with no network and no login - Launch: A global hotkey to a pre-warmed window · cold-starting a window is the difference between using this and not - Actions: Sandboxed scripts over a small API · the value is what happens after capture, and that has to be yours to define - Delivery: A queue with retries for anything leaving the machine · capture must never depend on a destination being reachable - Storage: Every draft kept, including sent ones · the archive is what makes capture safe to do carelessly ### Data model (create this before Phase 1) - 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. ### Phase 1 · A box that is already there Build: A global hotkey showing a pre-warmed window with the cursor placed. Measure the delay from keypress to typeable and treat anything above a small threshold as a defect. Text persists as you type, not on close. Trap: 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. Done when: The hotkey to typeable delay is measured and below the threshold, including the first invocation after a cold start. Text persists as typed, verified by killing the process mid-word. The window appears above whatever is focused. Dismissing keeps the draft rather than discarding it. Do not build yet: No actions or queue. ### Phase 2 · Actions that do something with the text Build: A scripted action system with a small API: the draft body, tags, and a few operations. Run scripts sandboxed with no ambient filesystem or network access unless the action declares it. Record every run. Trap: 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. Done when: An action transforms a draft and the result is visible. A script attempting filesystem access without declaring it fails, tested directly. Every run is recorded with its output or error. An action that throws leaves the draft untouched rather than half-modified. Do not build yet: No queue or retries yet. ### Phase 3 · Nothing lost when the destination is down Build: Queue any action declaring network access. Retry with backoff. Show pending and failed deliveries. Capture and local actions continue to work entirely offline. Trap: 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. Done when: A network action against an unreachable destination queues and retries with backoff. Capture and local actions work fully offline, tested with networking disabled. Pending and failed deliveries are visible and retryable. A delivered action still leaves the draft in the archive. Do not build yet: No search or sync yet. ### Phase 4 · Finding what you captured Build: Full text search across drafts including archived ones, with tag and date filters. Search as you type. Include draft versions so text removed by an action is still findable. Trap: 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. Done when: Search covers archived drafts by default, verified against an archived capture. Results appear as you type across ten thousand drafts. Tag and date filters combine with text. Text removed by an action is still findable through versions. Do not build yet: No sync or sharing yet. ### Phase 5 · Two machines and a shared action library Build: Sync drafts and actions through a store you control. Import an action from a file or URL showing its declared capabilities and full source before enabling it. Never enable an imported action automatically. Trap: An imported action that runs before you read it is arbitrary code execution with a friendly name, and action libraries are exactly how people share these. Show the source and declared capabilities, require an explicit enable, and re-prompt when an updated action changes what it declares. Done when: Drafts sync between two machines without duplication. An imported action shows its source and declared capabilities and does not run until enabled. An update changing declared capabilities re-prompts. A sync conflict on one draft keeps both versions. Do not build yet: Nothing after this. ### Out of scope (and why) - Mobile capture, which is where most quick capture actually happens and is the reason the original exists on a phone. - Dictation and voice capture, which is a substantial platform integration on its own. - The large community action library, which is most of the hosted product's practical value. - Rich text and attachments, since plain text is what makes capture instant and portable. ### README must contain - That the hotkey to typeable delay is measured and treated as the primary requirement - That actions run sandboxed and must declare network or filesystem access - That network actions queue and a draft is never deleted by delivery - That search covers archived drafts and versions by default - That an imported action shows its source and does not run until enabled ===== ARCHITECTURE.md ===== # Architecture · Drafts Pro ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | TypeScript with a local application and SQLite | capture must work with no network and no login | | Launch | A global hotkey to a pre-warmed window | cold-starting a window is the difference between using this and not | | Actions | Sandboxed scripts over a small API | the value is what happens after capture, and that has to be yours to define | | Delivery | A queue with retries for anything leaving the machine | capture must never depend on a destination being reachable | | Storage | Every draft kept, including sent ones | the archive is what makes capture safe to do carelessly | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | Window | Pre-warmed capture and measured delay. | Platform-specific. The measurement is what keeps it honest through changes. | | Actions | Sandboxed scripts with declared capabilities. | Any sandbox, provided undeclared access actually fails rather than warning. | | Queue | Retries for anything leaving the machine. | Any queue. Only marking delivered on a confirmed response is the requirement. | | Search | Everything including archived and versions. | Any index. Excluding archived is the mistake to avoid. | | Import | Showing source before an action runs. | Not swappable for automatic enabling, which is arbitrary code execution. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `DB_PATH` · required · Every draft ever captured, including archived ones. Back it up. - `CAPTURE_HOTKEY` · required · The global hotkey. Choose one nothing else claims, which is harder than it sounds. - `MAX_CAPTURE_DELAY_MS` · required · The threshold that fails the build. The primary requirement made checkable. - `ACTION_DIR` · required · Action scripts. Imported ones sit here disabled until you enable them. - `SYNC_REMOTE` · optional · Phase 5 only. Absent means one machine, which is a fine way to run. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it. ===== AGENTS.md ===== # Agent instructions · Drafts Pro product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: TypeScript with a local application and SQLite, A global hotkey to a pre-warmed window, Sandboxed scripts over a small API, A queue with retries for anything leaving the machine, Every draft kept, including sent ones. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - 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. - 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. - 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. - 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. - An imported action that runs before you read it is arbitrary code execution with a friendly name, and action libraries are exactly how people share these. Show the source and declared capabilities, require an explicit enable, and re-prompt when an updated action changes what it declares. ===== MILESTONES.md ===== # Delivery milestones · Drafts Pro Estimated effort: **weekend** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · A box that is already there The hotkey produces a cursor in an empty box with no perceptible delay. ### Steps 1. Pre-warm the window Show a built window, do not build one. The first capture is the one that matters. Files: `src/window.ts` 2. Measure the delay Keypress to typeable, logged. A number, not an impression. Files: `src/metrics.ts` 3. Persist as you type Killing the process mid-word must lose nothing. Files: `src/persist.ts` ### Done when - [ ] Hotkey to typeable is measured and below threshold - [ ] A cold start first capture is also fast - [ ] Killing mid-word loses nothing - [ ] Dismissing keeps the draft ### 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. ## M2 · Actions that do something with the text One keystroke sends the draft somewhere useful. ### Steps 1. Define a small action API Body, tags, a few operations. Small is what keeps it sandboxable. Files: `src/api.ts` 2. Sandbox by default Declared capabilities only. Test that an undeclared access fails. Files: `src/sandbox.ts`, `src/sandbox.test.ts` 3. Record every run Output and error. Debugging an action without the record is guesswork. Files: `src/runs.ts` ### Done when - [ ] An action transforms a draft visibly - [ ] Undeclared filesystem access fails - [ ] Every run is recorded with output or error - [ ] A throwing action leaves the draft untouched ### 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. ## M3 · Nothing lost when the destination is down An action sending somewhere unreachable retries instead of failing you. ### Steps 1. Queue declared network actions The declaration from phase 2 is what makes this automatic. Files: `src/queue.ts` 2. Retry with backoff and a cap Then surface as failed rather than retrying forever. Files: `src/worker.ts` 3. Keep the draft regardless Delivery is not deletion. The archive is what makes capture safe. Files: `src/drafts.ts` ### Done when - [ ] A network action queues and retries against an unreachable destination - [ ] Capture and local actions work offline - [ ] Pending and failed deliveries are visible and retryable - [ ] Delivery leaves the draft archived ### 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. ## M4 · Finding what you captured Six months of captures are searchable in the time it takes to type. ### Steps 1. Index everything including archived State is a filter, not a boundary. Archived is where things live. Files: `src/search.ts` 2. Search as you type At ten thousand drafts. Anything slower breaks the habit. Files: `src/search.ts` 3. Index versions too So an action that rewrote a draft did not hide the original. Files: `src/versions.ts` ### Done when - [ ] Search covers archived drafts by default - [ ] Results appear as you type at ten thousand drafts - [ ] Tag and date filters combine with text - [ ] Text removed by an action is findable ### 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. ## M5 · Two machines and a shared action library (production only) Drafts and actions follow you, and a shared action is inspected before it runs. ### Steps 1. Sync through a store you control Drafts and actions. Capture data should not require a service. Files: `src/sync.ts` 2. Show source and capabilities before enabling An imported action is arbitrary code. Read it before it runs. Files: `src/import.ts` 3. Re-prompt on changed capabilities An update that adds network access is a new decision. Files: `src/import.ts` ### Done when - [ ] Drafts sync between machines without duplication - [ ] An imported action does not run until enabled - [ ] Changed capabilities re-prompt - [ ] A sync conflict keeps both versions ### Watch out - An imported action that runs before you read it is arbitrary code execution with a friendly name, and action libraries are exactly how people share these. Show the source and declared capabilities, require an explicit enable, and re-prompt when an updated action changes what it declares. ===== OPERATIONS.md ===== # Operations · Drafts Pro ## Backup Drafts are irreplaceable and small. Back up the database frequently and test a restore by searching for an old capture. Actions are code and belong in version control separately. ## Restore Restore and confirm archived drafts and versions survived, since those are what make old captures findable and are the easiest thing to lose in a partial restore. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring Capture delay is the metric that matters and should be logged on every invocation, because it degrades gradually as the database grows. Queue depth is second. ## Incident checklist If capture becomes slow, the window is being built rather than shown, or the persistence path is doing work in the keystroke handler. If a draft is missing after an action, something deleted on success, which it must not. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] Capture delay is confirmed below the threshold including a cold start - [ ] Undeclared filesystem access is confirmed to fail - [ ] An unreachable destination is confirmed to queue rather than lose the draft - [ ] Search is confirmed to cover archived drafts - [ ] An imported action is confirmed not to run until enabled ## Launch constraint Do not market omitted Drafts Pro capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered. ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required. Every draft ever captured, including archived ones. Back it up. DB_PATH=~/.local/share/drafts/drafts.db # Required. The global hotkey. Choose one nothing else claims, which is harder than it sounds. CAPTURE_HOTKEY=Cmd+Shift+Space # Required. The threshold that fails the build. The primary requirement made checkable. MAX_CAPTURE_DELAY_MS=120 # Required. Action scripts. Imported ones sit here disabled until you enable them. ACTION_DIR=~/.config/drafts/actions # Optional. Phase 5 only. Absent means one machine, which is a fine way to run. SYNC_REMOTE=s3://my-drafts/store
# Drafts Pro · indie build 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: **weekend**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | TypeScript with a local application and SQLite | capture must work with no network and no login | | Launch | A global hotkey to a pre-warmed window | cold-starting a window is the difference between using this and not | | Actions | Sandboxed scripts over a small API | the value is what happens after capture, and that has to be yours to define | | Delivery | A queue with retries for anything leaving the machine | capture must never depend on a destination being reachable | | Storage | Every draft kept, including sent ones | the archive is what makes capture safe to do carelessly | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Node.js 22 or newer** · free - Why: Runs the application and the action sandbox. - Get it: nodejs.org, or nvm install 22. - Verify: node --version prints v22 or higher - [ ] **A global hotkey mechanism for your platform** · free - 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 - [ ] **One real destination for an action** · free - 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 - [ ] **Your acceptable capture delay** · free - 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 ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - Mobile capture. - Dictation and voice capture. - The large community action library. - Rich text and attachments. - its iPhone and Mac capture speed, action directory, and Apple automation depth - cross-device sync - large proprietary style models - browser and office-suite extensions - team style guides If one of those is essential to you, that is the reason to keep paying for Drafts Pro, and the README should say so rather than pretend.
# Build brief · Drafts Pro The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a capture box that opens instantly and sends text wherever it needs to go to replace Drafts Pro. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Runtime: TypeScript with a local application and SQLite · capture must work with no network and no login - Launch: A global hotkey to a pre-warmed window · cold-starting a window is the difference between using this and not - Actions: Sandboxed scripts over a small API · the value is what happens after capture, and that has to be yours to define - Delivery: A queue with retries for anything leaving the machine · capture must never depend on a destination being reachable - Storage: Every draft kept, including sent ones · the archive is what makes capture safe to do carelessly ### Data model (create this before Phase 1) - 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. ### Phase 1 · A box that is already there Build: A global hotkey showing a pre-warmed window with the cursor placed. Measure the delay from keypress to typeable and treat anything above a small threshold as a defect. Text persists as you type, not on close. Trap: 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. Done when: The hotkey to typeable delay is measured and below the threshold, including the first invocation after a cold start. Text persists as typed, verified by killing the process mid-word. The window appears above whatever is focused. Dismissing keeps the draft rather than discarding it. Do not build yet: No actions or queue. ### Phase 2 · Actions that do something with the text Build: A scripted action system with a small API: the draft body, tags, and a few operations. Run scripts sandboxed with no ambient filesystem or network access unless the action declares it. Record every run. Trap: 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. Done when: An action transforms a draft and the result is visible. A script attempting filesystem access without declaring it fails, tested directly. Every run is recorded with its output or error. An action that throws leaves the draft untouched rather than half-modified. Do not build yet: No queue or retries yet. ### Phase 3 · Nothing lost when the destination is down Build: Queue any action declaring network access. Retry with backoff. Show pending and failed deliveries. Capture and local actions continue to work entirely offline. Trap: 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. Done when: A network action against an unreachable destination queues and retries with backoff. Capture and local actions work fully offline, tested with networking disabled. Pending and failed deliveries are visible and retryable. A delivered action still leaves the draft in the archive. Do not build yet: No search or sync yet. ### Phase 4 · Finding what you captured Build: Full text search across drafts including archived ones, with tag and date filters. Search as you type. Include draft versions so text removed by an action is still findable. Trap: 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. Done when: Search covers archived drafts by default, verified against an archived capture. Results appear as you type across ten thousand drafts. Tag and date filters combine with text. Text removed by an action is still findable through versions. Do not build yet: No sync or sharing yet. ### Phase 5 · Two machines and a shared action library Build: Sync drafts and actions through a store you control. Import an action from a file or URL showing its declared capabilities and full source before enabling it. Never enable an imported action automatically. Trap: An imported action that runs before you read it is arbitrary code execution with a friendly name, and action libraries are exactly how people share these. Show the source and declared capabilities, require an explicit enable, and re-prompt when an updated action changes what it declares. Done when: Drafts sync between two machines without duplication. An imported action shows its source and declared capabilities and does not run until enabled. An update changing declared capabilities re-prompts. A sync conflict on one draft keeps both versions. Do not build yet: Nothing after this. ### Out of scope (and why) - Mobile capture, which is where most quick capture actually happens and is the reason the original exists on a phone. - Dictation and voice capture, which is a substantial platform integration on its own. - The large community action library, which is most of the hosted product's practical value. - Rich text and attachments, since plain text is what makes capture instant and portable. ### README must contain - That the hotkey to typeable delay is measured and treated as the primary requirement - That actions run sandboxed and must declare network or filesystem access - That network actions queue and a draft is never deleted by delivery - That search covers archived drafts and versions by default - That an imported action shows its source and does not run until enabled
# Agent instructions · Drafts Pro indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: TypeScript with a local application and SQLite, A global hotkey to a pre-warmed window, Sandboxed scripts over a small API, A queue with retries for anything leaving the machine, Every draft kept, including sent ones. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - 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. - 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. - 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. - 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.
# Build plan · Drafts Pro 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. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · A box that is already there The hotkey produces a cursor in an empty box with no perceptible delay. ### Steps 1. Pre-warm the window Show a built window, do not build one. The first capture is the one that matters. Files: `src/window.ts` 2. Measure the delay Keypress to typeable, logged. A number, not an impression. Files: `src/metrics.ts` 3. Persist as you type Killing the process mid-word must lose nothing. Files: `src/persist.ts` ### Done when - [ ] Hotkey to typeable is measured and below threshold - [ ] A cold start first capture is also fast - [ ] Killing mid-word loses nothing - [ ] Dismissing keeps the draft ### 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. ## Phase 2 · Actions that do something with the text One keystroke sends the draft somewhere useful. ### Steps 1. Define a small action API Body, tags, a few operations. Small is what keeps it sandboxable. Files: `src/api.ts` 2. Sandbox by default Declared capabilities only. Test that an undeclared access fails. Files: `src/sandbox.ts`, `src/sandbox.test.ts` 3. Record every run Output and error. Debugging an action without the record is guesswork. Files: `src/runs.ts` ### Done when - [ ] An action transforms a draft visibly - [ ] Undeclared filesystem access fails - [ ] Every run is recorded with output or error - [ ] A throwing action leaves the draft untouched ### 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. ## Phase 3 · Nothing lost when the destination is down An action sending somewhere unreachable retries instead of failing you. ### Steps 1. Queue declared network actions The declaration from phase 2 is what makes this automatic. Files: `src/queue.ts` 2. Retry with backoff and a cap Then surface as failed rather than retrying forever. Files: `src/worker.ts` 3. Keep the draft regardless Delivery is not deletion. The archive is what makes capture safe. Files: `src/drafts.ts` ### Done when - [ ] A network action queues and retries against an unreachable destination - [ ] Capture and local actions work offline - [ ] Pending and failed deliveries are visible and retryable - [ ] Delivery leaves the draft archived ### 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. ## Phase 4 · Finding what you captured Six months of captures are searchable in the time it takes to type. ### Steps 1. Index everything including archived State is a filter, not a boundary. Archived is where things live. Files: `src/search.ts` 2. Search as you type At ten thousand drafts. Anything slower breaks the habit. Files: `src/search.ts` 3. Index versions too So an action that rewrote a draft did not hide the original. Files: `src/versions.ts` ### Done when - [ ] Search covers archived drafts by default - [ ] Results appear as you type at ten thousand drafts - [ ] Tag and date filters combine with text - [ ] Text removed by an action is findable ### 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. ## Not in this build - Mobile capture. - Dictation and voice capture. - The large community action library. - Rich text and attachments. ## After v1, if you want it - Actions chained into a workflow, once single actions are reliable - Templates that pre-fill a capture for a recurring kind of note - A daily digest of what you captured, which is where an archive starts being read
# Copy to .env and fill in. Never commit .env; this file documents it. # Required. Every draft ever captured, including archived ones. Back it up. DB_PATH=~/.local/share/drafts/drafts.db # Required. The global hotkey. Choose one nothing else claims, which is harder than it sounds. CAPTURE_HOTKEY=Cmd+Shift+Space # Required. The threshold that fails the build. The primary requirement made checkable. MAX_CAPTURE_DELAY_MS=120 # Required. Action scripts. Imported ones sit here disabled until you enable them. ACTION_DIR=~/.config/drafts/actions # Optional. Phase 5 only. Absent means one machine, which is a fine way to run. SYNC_REMOTE=s3://my-drafts/store
# Drafts Pro · product brief ## Problem The core loop is small enough for a capable coding agent to produce a useful local version in one sitting. For Drafts Pro, capture text instantly, run reusable transformations, and file the result into local destinations. The hard boundary is its iphone and mac capture speed, action directory, and apple automation depth, plus polish, integrations, and proprietary language models. ## Product outcome A capture box that is already open by the time you look at it, an action system that cannot quietly read your filesystem, and an archive where nothing you typed is ever lost to a failed delivery. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - macOS, Windows, or Linux - local files - optional OpenAI or Anthropic API key for semantic rewrites ## Explicit non-goals for v1 - Mobile capture. - Dictation and voice capture. - The large community action library. - Rich text and attachments. - its iPhone and Mac capture speed, action directory, and Apple automation depth - cross-device sync - large proprietary style models - browser and office-suite extensions - team style guides ## Success criteria - Capture delay is confirmed below the threshold including a cold start - Undeclared filesystem access is confirmed to fail - An unreachable destination is confirmed to queue rather than lose the draft - Search is confirmed to cover archived drafts - An imported action is confirmed not to run until enabled
# Build brief · Drafts Pro The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a capture box that opens instantly and sends text wherever it needs to go to replace Drafts Pro. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Runtime: TypeScript with a local application and SQLite · capture must work with no network and no login - Launch: A global hotkey to a pre-warmed window · cold-starting a window is the difference between using this and not - Actions: Sandboxed scripts over a small API · the value is what happens after capture, and that has to be yours to define - Delivery: A queue with retries for anything leaving the machine · capture must never depend on a destination being reachable - Storage: Every draft kept, including sent ones · the archive is what makes capture safe to do carelessly ### Data model (create this before Phase 1) - 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. ### Phase 1 · A box that is already there Build: A global hotkey showing a pre-warmed window with the cursor placed. Measure the delay from keypress to typeable and treat anything above a small threshold as a defect. Text persists as you type, not on close. Trap: 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. Done when: The hotkey to typeable delay is measured and below the threshold, including the first invocation after a cold start. Text persists as typed, verified by killing the process mid-word. The window appears above whatever is focused. Dismissing keeps the draft rather than discarding it. Do not build yet: No actions or queue. ### Phase 2 · Actions that do something with the text Build: A scripted action system with a small API: the draft body, tags, and a few operations. Run scripts sandboxed with no ambient filesystem or network access unless the action declares it. Record every run. Trap: 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. Done when: An action transforms a draft and the result is visible. A script attempting filesystem access without declaring it fails, tested directly. Every run is recorded with its output or error. An action that throws leaves the draft untouched rather than half-modified. Do not build yet: No queue or retries yet. ### Phase 3 · Nothing lost when the destination is down Build: Queue any action declaring network access. Retry with backoff. Show pending and failed deliveries. Capture and local actions continue to work entirely offline. Trap: 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. Done when: A network action against an unreachable destination queues and retries with backoff. Capture and local actions work fully offline, tested with networking disabled. Pending and failed deliveries are visible and retryable. A delivered action still leaves the draft in the archive. Do not build yet: No search or sync yet. ### Phase 4 · Finding what you captured Build: Full text search across drafts including archived ones, with tag and date filters. Search as you type. Include draft versions so text removed by an action is still findable. Trap: 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. Done when: Search covers archived drafts by default, verified against an archived capture. Results appear as you type across ten thousand drafts. Tag and date filters combine with text. Text removed by an action is still findable through versions. Do not build yet: No sync or sharing yet. ### Phase 5 · Two machines and a shared action library Build: Sync drafts and actions through a store you control. Import an action from a file or URL showing its declared capabilities and full source before enabling it. Never enable an imported action automatically. Trap: An imported action that runs before you read it is arbitrary code execution with a friendly name, and action libraries are exactly how people share these. Show the source and declared capabilities, require an explicit enable, and re-prompt when an updated action changes what it declares. Done when: Drafts sync between two machines without duplication. An imported action shows its source and declared capabilities and does not run until enabled. An update changing declared capabilities re-prompts. A sync conflict on one draft keeps both versions. Do not build yet: Nothing after this. ### Out of scope (and why) - Mobile capture, which is where most quick capture actually happens and is the reason the original exists on a phone. - Dictation and voice capture, which is a substantial platform integration on its own. - The large community action library, which is most of the hosted product's practical value. - Rich text and attachments, since plain text is what makes capture instant and portable. ### README must contain - That the hotkey to typeable delay is measured and treated as the primary requirement - That actions run sandboxed and must declare network or filesystem access - That network actions queue and a draft is never deleted by delivery - That search covers archived drafts and versions by default - That an imported action shows its source and does not run until enabled
# Architecture · Drafts Pro ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | TypeScript with a local application and SQLite | capture must work with no network and no login | | Launch | A global hotkey to a pre-warmed window | cold-starting a window is the difference between using this and not | | Actions | Sandboxed scripts over a small API | the value is what happens after capture, and that has to be yours to define | | Delivery | A queue with retries for anything leaving the machine | capture must never depend on a destination being reachable | | Storage | Every draft kept, including sent ones | the archive is what makes capture safe to do carelessly | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | Window | Pre-warmed capture and measured delay. | Platform-specific. The measurement is what keeps it honest through changes. | | Actions | Sandboxed scripts with declared capabilities. | Any sandbox, provided undeclared access actually fails rather than warning. | | Queue | Retries for anything leaving the machine. | Any queue. Only marking delivered on a confirmed response is the requirement. | | Search | Everything including archived and versions. | Any index. Excluding archived is the mistake to avoid. | | Import | Showing source before an action runs. | Not swappable for automatic enabling, which is arbitrary code execution. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `DB_PATH` · required · Every draft ever captured, including archived ones. Back it up. - `CAPTURE_HOTKEY` · required · The global hotkey. Choose one nothing else claims, which is harder than it sounds. - `MAX_CAPTURE_DELAY_MS` · required · The threshold that fails the build. The primary requirement made checkable. - `ACTION_DIR` · required · Action scripts. Imported ones sit here disabled until you enable them. - `SYNC_REMOTE` · optional · Phase 5 only. Absent means one machine, which is a fine way to run. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it.
# Agent instructions · Drafts Pro product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: TypeScript with a local application and SQLite, A global hotkey to a pre-warmed window, Sandboxed scripts over a small API, A queue with retries for anything leaving the machine, Every draft kept, including sent ones. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - 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. - 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. - 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. - 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. - An imported action that runs before you read it is arbitrary code execution with a friendly name, and action libraries are exactly how people share these. Show the source and declared capabilities, require an explicit enable, and re-prompt when an updated action changes what it declares.
# Delivery milestones · Drafts Pro Estimated effort: **weekend** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · A box that is already there The hotkey produces a cursor in an empty box with no perceptible delay. ### Steps 1. Pre-warm the window Show a built window, do not build one. The first capture is the one that matters. Files: `src/window.ts` 2. Measure the delay Keypress to typeable, logged. A number, not an impression. Files: `src/metrics.ts` 3. Persist as you type Killing the process mid-word must lose nothing. Files: `src/persist.ts` ### Done when - [ ] Hotkey to typeable is measured and below threshold - [ ] A cold start first capture is also fast - [ ] Killing mid-word loses nothing - [ ] Dismissing keeps the draft ### 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. ## M2 · Actions that do something with the text One keystroke sends the draft somewhere useful. ### Steps 1. Define a small action API Body, tags, a few operations. Small is what keeps it sandboxable. Files: `src/api.ts` 2. Sandbox by default Declared capabilities only. Test that an undeclared access fails. Files: `src/sandbox.ts`, `src/sandbox.test.ts` 3. Record every run Output and error. Debugging an action without the record is guesswork. Files: `src/runs.ts` ### Done when - [ ] An action transforms a draft visibly - [ ] Undeclared filesystem access fails - [ ] Every run is recorded with output or error - [ ] A throwing action leaves the draft untouched ### 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. ## M3 · Nothing lost when the destination is down An action sending somewhere unreachable retries instead of failing you. ### Steps 1. Queue declared network actions The declaration from phase 2 is what makes this automatic. Files: `src/queue.ts` 2. Retry with backoff and a cap Then surface as failed rather than retrying forever. Files: `src/worker.ts` 3. Keep the draft regardless Delivery is not deletion. The archive is what makes capture safe. Files: `src/drafts.ts` ### Done when - [ ] A network action queues and retries against an unreachable destination - [ ] Capture and local actions work offline - [ ] Pending and failed deliveries are visible and retryable - [ ] Delivery leaves the draft archived ### 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. ## M4 · Finding what you captured Six months of captures are searchable in the time it takes to type. ### Steps 1. Index everything including archived State is a filter, not a boundary. Archived is where things live. Files: `src/search.ts` 2. Search as you type At ten thousand drafts. Anything slower breaks the habit. Files: `src/search.ts` 3. Index versions too So an action that rewrote a draft did not hide the original. Files: `src/versions.ts` ### Done when - [ ] Search covers archived drafts by default - [ ] Results appear as you type at ten thousand drafts - [ ] Tag and date filters combine with text - [ ] Text removed by an action is findable ### 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. ## M5 · Two machines and a shared action library (production only) Drafts and actions follow you, and a shared action is inspected before it runs. ### Steps 1. Sync through a store you control Drafts and actions. Capture data should not require a service. Files: `src/sync.ts` 2. Show source and capabilities before enabling An imported action is arbitrary code. Read it before it runs. Files: `src/import.ts` 3. Re-prompt on changed capabilities An update that adds network access is a new decision. Files: `src/import.ts` ### Done when - [ ] Drafts sync between machines without duplication - [ ] An imported action does not run until enabled - [ ] Changed capabilities re-prompt - [ ] A sync conflict keeps both versions ### Watch out - An imported action that runs before you read it is arbitrary code execution with a friendly name, and action libraries are exactly how people share these. Show the source and declared capabilities, require an explicit enable, and re-prompt when an updated action changes what it declares.
# Operations · Drafts Pro ## Backup Drafts are irreplaceable and small. Back up the database frequently and test a restore by searching for an old capture. Actions are code and belong in version control separately. ## Restore Restore and confirm archived drafts and versions survived, since those are what make old captures findable and are the easiest thing to lose in a partial restore. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring Capture delay is the metric that matters and should be logged on every invocation, because it degrades gradually as the database grows. Queue depth is second. ## Incident checklist If capture becomes slow, the window is being built rather than shown, or the persistence path is doing work in the keystroke handler. If a draft is missing after an action, something deleted on success, which it must not. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] Capture delay is confirmed below the threshold including a cold start - [ ] Undeclared filesystem access is confirmed to fail - [ ] An unreachable destination is confirmed to queue rather than lose the draft - [ ] Search is confirmed to cover archived drafts - [ ] An imported action is confirmed not to run until enabled ## Launch constraint Do not market omitted Drafts Pro capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered.
# Copy to .env and fill in. Never commit .env; this file documents it. # Required. Every draft ever captured, including archived ones. Back it up. DB_PATH=~/.local/share/drafts/drafts.db # Required. The global hotkey. Choose one nothing else claims, which is harder than it sounds. CAPTURE_HOTKEY=Cmd+Shift+Space # Required. The threshold that fails the build. The primary requirement made checkable. MAX_CAPTURE_DELAY_MS=120 # Required. Action scripts. Imported ones sit here disabled until you enable them. ACTION_DIR=~/.config/drafts/actions # Optional. Phase 5 only. Absent means one machine, which is a fine way to run. SYNC_REMOTE=s3://my-drafts/store
$ choose a build depth, inspect the files, then open the complete pack in your agent
People still pay for Drafts Pro because the paid tool is already present everywhere they write and its suggestions have been tuned across millions of documents. The recurring cost buys model quality, extension compatibility, dictionaries, releases, and sync, not just the visible interface.
xits iPhone and Mac capture speed, action directory, and Apple automation depth
xcross-device sync
xlarge proprietary style models
xbrowser and office-suite extensions
xteam style guides
Drafts Pro pricing
| plan | monthly | annual (per mo) | what you get |
|---|---|---|---|
| free | $0 | $0 | Unlimited basic text capture and iCloud sync; Pro-only custom actions, workspaces, themes and advanced automation excluded |
| drafts pro | $1.99 | $1.67 | 1 subscription across iPhone, iPad, Mac and Apple Watch; Family Sharing supported |
| drafts pro patron | — | $2.50 | Same features as Drafts Pro; no additional product limits or features |
free tierNo published numeric cap on drafts, words, devices, or sync; free use excludes Pro-only custom actions, workspaces, themes and advanced automation
billing$1.99 monthly or $19.99 annually; optional $29.99/year Patron subscription; App Store billing and Family Sharing
hidden costsThe Patron tier costs more but unlocks no additional features; purchases are App Store subscriptions and restoration depends on the platform/account used.
verified 2026-08-12 · source ↗
Vibecode Drafts Pro
Yes. A competent AI coding agent (Claude Code, Codex, Cursor) can build a usable personal Drafts Pro replacement in one session with the prompt on this page. It runs on your own machine or server with no subscription.
How much does Drafts Pro cost?
Drafts Pro costs about $1.67/month (Drafts Pro, checked 2026-07-31), which is $20.04 per year. That's what you save by replacing it with one prompt.
What do I lose by replacing Drafts Pro?
Honestly: its iPhone and Mac capture speed, action directory, and Apple automation depth; cross-device sync; large proprietary style models; browser and office-suite extensions; team style guides. If any of those are load-bearing for you, keep paying.
Is there an open-source alternative to Drafts Pro?
Yes: LanguageTool (Mature open-source grammar and style checker with desktop and server components.). Using prior art is also vibecoding; the prompt is for when you want it exactly your way.