tavva7k downloadsImplements key processes in David Allen's Getting Things Done (GTD) methodology
GTD-powered task management for Obsidian.
Flow captures everything demanding your attention and helps you focus on what matters. Built on David Allen's Getting Things Done methodology.
Your mind is constantly interrupted by things you need to remember: tasks, ideas, commitments, follow-ups. These open loops consume mental energy that should go towards your actual work.
Flow gets everything out of your head and into a trusted system, so you can focus completely on what you're doing right now. It's based on GTD principles but doesn't require you to follow the methodology rigidly.
The first version of Flow was handcrafted, but all my code now is written by AI, including code in this plugin. I've been a software engineer for 29 years, have been CTO at several companies, and have built a lot of software both individually and as part of different-sized teams. I stand by the architecture and code in this plugin, and have checks in my workflow to manage security and correctness.
To try unreleased builds before they reach the stable community plugin listing:
tavva/flow and enable itBRAT will automatically update to the latest beta when new versions are released. To switch back to stable, remove the plugin from BRAT.
If you use a beta build we'd love to hear from you in the repo Discussions.
Capture — When something has your attention, add it to your inbox. Don't organise yet, just get it out of your head.
Process — Review your inbox regularly. For each item you choose:

Screenshot from the current inbox processing flow.
Plan — Open a sphere view, enter planning mode, and click actions to add them to your focus. Your focus is your curated list of what to work on.
Do — Work from your focus. When done, mark complete. When blocked, convert to waiting-for.
Choose Settings → Flow → Output Files & Folders → Focus File to set the vault-relative path for your focus list. The default is flow-focus-data/focus.md; leaving the setting blank uses this default. Click Apply to move your focus file to the new location.
Flow creates missing folders and moves your existing focus file automatically. If the destination already exists, Flow asks whether to use that file instead; neither file is overwritten or merged. Cancelling or a failed move keeps your current location.
Other Obsidian plugins can put items into your focus that have no line in your vault, such as a ticket from an issue tracker. These items show in the Focus view under their source's name. Clicking one opens it at its source, and the pencil button changes its wording. Completing or removing one tells the plugin that added it.
Flow publishes an API on its plugin instance. Look it up once the workspace layout is ready, because Obsidian loads plugins in no set order:
this.app.workspace.onLayoutReady(() => {
const flow = this.app.plugins.getPlugin("flow")?.api;
if (flow?.apiVersion === 1) {
// Use the API
}
});
app.plugins isn't in Obsidian's public typings, so declare the narrow type you use. Flow also fires flow:api-ready (with the API) on the workspace when it loads and flow:api-unloaded when it unloads, so you can notice Flow being enabled, disabled or reloaded later.
The interface is FlowApi in src/focus-api.ts; copy it into your plugin.
| Method | What it does |
|---|---|
addFocusItem(input) |
Adds an item with text, sphere, sourceName, sourceLabel, url, externalId and optionally projectName, and returns its new id |
updateFocusItem(id, changes) |
Changes any of text, sphere, sourceLabel, url, externalId or projectName |
completeFocusItem(id) |
Marks the item complete; it stays in Focus under Completed Today |
removeFocusItem(id) |
Takes the item out of Focus |
getFocusItems(sourceName) |
Returns your source's items, including completed ones |
getSpheres() |
Returns the sphere names set in Flow's settings |
onFocusChange(sourceName, callback) |
Calls callback with added, edited, completed or removed changes to your source's items, and returns a function to stop |
sourceName identifies your plugin's items (for example "linear"); sourceLabel is what the user sees (for example a workspace name). externalId is your record's own ID, and one record can have several items.projectName is the project the record belongs to in your tool (for example a Linear project). Flow shows it under the item's wording, so items from the same source can be told apart. It's optional: pass null or "" to updateFocusItem to clear it.url must be an http or https link. Flow won't open anything else.id reject with an error. addFocusItem rejects empty text, sphere, sourceName, sourceLabel or externalId, and updateFocusItem rejects an empty value for any field it changes.flow:api-ready.getFocusItems or in change events, are your own copies. Changing them doesn't change Focus.getFocusItems and work from that.flow:api-ready handler, before Flow has read the file, are part of the starting state and get no added event. An item added and removed between two comparisons isn't reported at all.removed. A sync can briefly leave the focus file empty or cut short, or bring back an older copy from a device that was offline, and an out-of-date Flow on another device can remove your items. Before you act on a removed event outside Flow, such as removing a label in your own tool, wait a few seconds and confirm with getFocusItems that the item is still gone.apiVersion changes only when an existing method changes in a way that breaks callers. New methods don't change it.The focus file (flow-focus-data/focus.md unless changed in settings) is JSONL: one JSON object per line, in the order the Focus view shows them. Other tools may read it directly. A vault item looks like:
{
"file": "Projects/Ship v1.0.md",
"lineNumber": 12,
"lineContent": "- [ ] Write release notes",
"text": "Write release notes",
"sphere": "work",
"isGeneral": false,
"addedAt": 1793520000000,
"contexts": []
}
An item from another plugin looks like:
{
"id": "7c1e…",
"text": "Draft section 2 of the evals plan",
"sphere": "work",
"addedAt": 1793520000000,
"external": {
"sourceName": "linear",
"sourceLabel": "Rootcause",
"url": "https://linear.app/rootcause/issue/ROO-123/evals-plan",
"externalId": "ROO-123",
"projectName": "Proptics"
},
"contexts": []
}
external is an item from another plugin. Any other line is a vault item with file (vault-relative path), lineNumber, lineContent, text, sphere, isGeneral and addedAt.external.projectName is the item's project in the other plugin's tool. It's optional: a line without it has no project. Writers should leave the field out rather than write null; Flow ignores a value that isn't text and keeps the item.addedAt and completedAt are milliseconds since the epoch.isPinned: true means the item is in the Pinned section.completedAt is set once the item is completed. Completed items stay in the file until they're removed or auto-cleared.Flow projects use YAML frontmatter:
---
priority: 2
tags: project/work
status: live
parent-project: "[[Parent Project]]"
---
# Ship v1.0
## Next actions
- [ ] Write release notes
- [ ] Update documentation
- [w] Waiting for design review from Sarah
Add GTD context tags to your actions to filter by where or how you can do them:
- [ ] Call dentist #context/phone
- [ ] Review budget spreadsheet #context/computer
- [ ] Pick up dry cleaning #context/errands
Context tags appear as filters in sphere and waiting-for views. The prefix is configurable in settings — change context to at, ctx, or whatever suits your workflow.
Flow can generate cover images for projects using AI. Configure an image-capable model via OpenRouter in Settings → Flow (openai/gpt-5-image creates great cover images in our experience).
GPL-3.0-or-later — see LICENSE for details.