You're in a conversation about project A. It surfaces a connection to project B, and turns out to touch a problem that has no home in your notes yet. There is no time to decide where any of this belongs — and by the time you could decide, the thought is gone.
Most note systems fight that moment. Folder structures, PARA,
Zettelkasten — they impose structure up front, so that retrieval works
later. The price is paid at the worst possible time: capture. ft is
built for the opposite bet: capture can't wait, and filing can't be
predicted. Write the thought anywhere — the daily note is fine.
Name what it's about with a [[wikilink]] or two. Move on with your
day. Everything else is ft's job, and it happens later, on your
terms.
ft is a CLI and TUI over a plain-Markdown vault. It shares its file
formats with Obsidian, so the two tools can work the same vault side
by side — but ft runs where a GUI can't: over SSH, in cron, inside a
shell pipeline.
Write anywhere. Ad-hoc thought goes into today's daily note as a few lines under a heading. An inbox note or a scratch file work just as well. No filing decision is made, because none is needed yet.
Name what it's about. Drop [[concept]] mentions into the
paragraph as you write. The target note doesn't have to exist — ft
tracks links to nonexistent notes as ghosts, and they count the same.
This is the only organizing act capture asks of you, and it's the cheap
one: not "where does this go?" (a global decision — it needs your
whole system in your head) but "what is this about?" (a local
decision — you already know, because you're thinking it). If you write
in Neovim, ft.nvim autocompletes
concept names when you type [[; Obsidian does the same out of the
box.
Resurface on demand. Because paragraphs are tagged with what they're about, the unsorted pile stays retrievable. Two directions:
- Pull — you need everything on a topic, now, maybe minutes before a
meeting:
ft notes search "[[topic]]"returns every matching paragraph, ranked by relevance (or--sort datefor newest first). - Sweep — you want to know what accumulated:
ft notes pulseranks the concepts most mentioned in a recent window, andft notes recentfeeds back every paragraph you touched in it.
Consolidate when a topic earns it. Some concepts keep coming up.
When one does, ft notes synth scaffold compiles the scattered paragraphs
into one focused note, each excerpt pinned to the git commit it came
from. Move sections between notes, rename a ghost into a real note
with every link rewritten — the structure grows out of what you
actually wrote, instead of being guessed in advance.
The point of the four steps: retrieval never depends on filing.
You can defer the tidying for a week or a year without penalty,
because the [[links]] you dropped at capture keep the pile
queryable the whole time. Consolidation becomes something you do for
the topics that matter, when they matter — not maintenance you owe
the system.
$ ft notes pulse --since 7d # sweep: what's been on my mind?
(3) [[onboarding]]
(2) [[analytics migration]]
(1) [[activation]]?
$ ft notes search "[[onboarding]] [[analytics migration]] --any"
notes/standup-2026-06-13.md L12-14 [[onboarding]] [[analytics migration]]
More [[onboarding]] questions in standup — nobody can say what
"done" means for the [[analytics migration]].
notes/standup-2026-06-12.md L9-11 [[onboarding]] [[analytics migration]]
Talked to Priya — the new [[onboarding]] flow doubles as a dogfood
path for the [[analytics migration]] since every signup event now
flows through the new pipeline.
notes/marketing.md L4-4 [[onboarding]]
The [[onboarding]] metrics she keeps asking for are really a proxy
for activation, not setup completion.
$ ft notes synth scaffold Synthesis/onboarding-and-analytics.md \
--search "[[onboarding]] [[analytics migration]] --any"
created Synthesis/onboarding-and-analytics.md with 3 section(s)
The ? in the pulse marks a ghost — a concept mentioned three
times that has no note yet. The matched: badge marks co-occurrence:
paragraphs where the two topics collided, which is usually the
interesting part. And the scaffolded note is plain text — prose you
write, with each excerpt pinned to the commit it came from:
---
ft:
synth:
enabled: true
targets: ["[[onboarding]]", "[[analytics migration]]"]
---
Onboarding and the analytics migration keep colliding.
> [!ft-source] "daily/2026-06-12.md" L3-5 @ef2a468 #7d302f
> Talked to Priya — the new [[onboarding]] flow doubles as a dogfood
> path for the [[analytics migration]] since every signup event now
> flows through the new pipeline.
… which is really a question about activation, not setup …Breaking change: ft's frontmatter keys now live under one
ft:map (see the block above). The flatft-synth:/ft-synth-targets:/ft-tasks-section:/ft-append-section:keys are no longer read. Any note ft writes is auto-converted; existing flat-keyed notes need hand-editing to be recognized.
A note-organizing, -analyzing, and -manipulating tool, deliberately format-compatible with Obsidian so the same vault round-trips through both:
| Surface | Compatible with |
|---|---|
| Links | Obsidian's wikilink format and resolution rules |
| Tasks | the Tasks plugin emoji format |
| Time tracking | the Day Planner plugin's block format |
Where ft departs from Obsidian is that the graph is a tool, not a
visualization. In Obsidian the graph is mostly something you look
at; in ft you work on it — the interconnections between notes (and
between paragraphs inside notes) are the substrate the operations run
over. The search feed above is a scan-derived paragraph index that
surfaces every paragraph mentioning a concept; backlinks surface every
reference including ghosts; the query DSL walks the graph ad hoc.
What ft is not:
- Not a Markdown editor. Bring your own —
$EDITOR, Obsidian, whatever.ftopens your editor for the writing. - Not a Markdown renderer. Bring your own for previews, embeds,
canvas, plugins.
ftemits and consumes plain Markdown. - Not a replacement for Obsidian. It can be an alternative — you can migrate to it if you supply your own editor and renderer — but the intended relationship is side by side: the vault is the contract, and both tools honour it.
The longer version of the philosophy — including why concept links beat full-text search for this job, and what keeps concept names from drifting apart — is in docs/guide/philosophy.md.
On top of the note-flow core, ft adds exactly two things — task
management (list, filter, create, complete, and move tasks in the
Tasks-plugin emoji format) and time management (Day-Planner
timeblocks and time-spent reports) — and nothing else. They live in
the same vault, the same daily notes, and the same TUI, so triaging
tasks and capturing thoughts are one workflow, not two tools.
Because they're adjacent features, their TUI tabs are off by default —
the CLI (ft tasks, ft timeblocks) always works. Two config lines
bring the tabs back:
[tui]
tasks_tab = true
timeblocks_tab = trueObsidian and Roam suggest composing new notes from old material with
block links and block embeds — live transclusion, where editing
the source updates every note that embeds it. ft deliberately does
not: embeds require a renderer to be readable, which makes the
composed note hostile to machines and to plain-text tooling. What
ft keeps from the embed idea is the part that matters —
provenance. Each excerpt is quoted as plain text and pinned to a
git commit via an [!ft-source] callout; ft notes synth verify confirms
every excerpt still matches its pinned source. The note reads as-is,
greps as-is, and can be handed to a machine as-is. The full argument
and the callout grammar are in
docs/guide/synthesis.md.
cargo install --path ftThis drops a single ft binary in ~/.cargo/bin/. MSRV is pinned
in rust-toolchain.toml. After installing, generate completions and
man pages — see install.md.
scripts/release.sh cuts a release: it derives the next version from
the latest v* tag (patch by default; --minor / --major to
override), generates a CHANGELOG.md section from the commit subjects
since the last tag (skipping openspec:/chore:/ci:/docs:
process commits), bumps [workspace.package] version in
Cargo.toml, refreshes Cargo.lock (the workflow builds with
--locked), and creates the vX.Y.Z tag — whose push triggers
.github/workflows/release.yml to
build and upload the binaries. --dry-run previews everything,
--check runs the five build invariants from AGENTS.md first, and
--push also pushes the commit and tag.
ft auto-discovers your vault by walking up from the current
directory looking for .obsidian/ or .ft/. Override with --vault DIR,
the FT_VAULT env var, or default_vault in ~/.config/ft/config.toml.
cd ~/my-vault
ft vault # show the resolved vault + merged config
ft tasks list today
ft tuiOne thing to know up front: the resurfacing commands (recent,
pulse, and search --sort date) date paragraphs from git blame, so
the vault should be a git repository and committed to regularly —
ft git sync does commit + pull + push in one shot. Commit cadence is
the temporal resolution of your history.
Start here — the user guide walks through install, setup, every feature, common workflows, and the design philosophy:
| Chapter | Covers |
|---|---|
| install.md | Build from source, completions, man pages, first run. |
| vault-and-config.md | Vault discovery, the two config layers, periodic notes. |
| tasks.md | List / filter / create / complete / move, CLI + TUI. |
| notes.md | Open, create, periodic, rename, mv, links, gather, recent. |
| capture-and-templates.md | Append-with-template and quick-capture presets. |
| timeblocks.md | Day-planner blocks and time-spent reports. |
| graph.md | The link graph and the graph-query DSL. |
| synthesis.md | Pulse → search → synth notes. |
| tui.md | The TUI tour and the command/keymap model. |
| git-sync.md | One-shot commit + pull + push. |
| scripting.md | Pipelines, exit codes, --json-errors, ft do. |
| philosophy.md | Why the tool is shaped this way. |
Everything below is the underlying reference material — schemas, grammars, generated tables. The guide chapters link into these for depth.
- docs/architecture.md — workspace layout, key traits, where to add a new subcommand or task format
- docs/commands.md — Command/Keymap model,
ft do,ft commands list/docs, status-bar hint, adding new commands - docs/keybindings.md — generated reference of
every registered command, grouped by scope; TUI bindings are
user-configurable via
[keymap]inconfig.toml(see docs/config.md) - docs/config.md — full config schema (vault
discovery,
[periodic_notes],[editor],[git],[keymap], presets) - docs/task-format.md — exactly which Tasks-plugin emoji fields are supported, with examples and the deferred list
- docs/graph-query-dsl.md — the unified
query DSL. Powers
ft graph queryand the TUI Graph tab, and also drivesft tasks list/ the TUI Tasks tab underProfile::Tasks - docs/migrating-task-queries.md — predicate translation table for users coming from the previous task DSL
- docs/timeblocks.md — day-planner block format, tag grammar, full CLI reference, and TUI keymap
- docs/append-and-capture.md — exhaustive reference for append-with-template and quick capture
- docs/architecture.md (synthesis section) —
internals of the consolidation flow (
ft notes pulse,ft notes search,ft notes recent,ft notes synth scaffold/verify), the[!ft-source]callout grammar used in synth notes, and the[synth]config table;ft notes quote(the read-only plumbing command behind the same pinning mechanics) is documented in docs/guide/synthesis.md, and its inverseft notes export(vault-stripped CommonMark, or Slack mrkdwn with--format slack— for pasting/publishing) in docs/guide/notes.md