Getting started¶
Bob is a CLI for an Obsidian vault that uses #task checkboxes and a daily
Pomodoro ledger. Basic capture and native queries run without desktop Obsidian.
Dashboard badges, review keymaps, and the Task Card are provided by the custom
Bob plugins; installing the CLI alone does not install that interface.
Ready, Next, and Pending name task statuses ("lanes"). Pending is another
name for In Progress ([/]), not a waiting or Blocked state.
Install and select a vault¶
From a checkout, run just install. Run just install-all to also deploy the
Bob plugins (and, on macOS, Bob Mac Capture) from sibling checkouts (offering
to clone any that are missing), restarting a running Obsidian when the plugins
change (on macOS that restart posts a notification first). With Cargo alone, run:
cargo install --path . --locked
bob completion install
See the installation guide for remote installation and completion for Bash/Zsh setup. Completion installation does not edit shell rc files.
Select an existing vault directory and inspect it:
export BOB_DIR=/path/to/your/bob-vault
bob --help
bob capture-targets
bob projects list
The default vault is ~/bob. Commands that accept --bob-dir let you override
it for one invocation. bob does not bootstrap a vault, its daily notes,
Obsidian settings, or Git remote.
Vault requirements¶
Bob writes Dataview-style task metadata such as [created::2026-10-04] and
[scheduled::2026-10-05]. Configure Obsidian Tasks to use the Dataview task
format and the #task global filter. Its status registry should include:
| Checkbox | Bob meaning | Tasks type |
|---|---|---|
[ ] |
Ready | TODO |
[*] |
Next | ON_HOLD |
[/] |
In Progress, also called Pending or WIP | IN_PROGRESS |
[?] |
Blocked | ON_HOLD |
[x] |
Done | DONE |
[-] |
Canceled | CANCELLED |
The CLI reads settings from
.obsidian/plugins/obsidian-tasks-plugin/data.json. Without that file, native
Tasks queries use the default emoji format; bob freshness and bob ready
refuse a non-Dataview format. Blocked transitions also require the compatible
? definition described in task status hooks
(bob task reconcile; formerly bob task-status-hooks, still accepted).
Capture routes select root-level notes: @work writes work.md. Route names
are lowercased and accept ASCII letters, digits, _, and -; picker-discovered
filenames must already have lowercase stems. A missing target note
is created when needed, and an existing ## Tasks section is the preferred
insertion point. Ordinary capture does not create that heading or give the
note an area/project type. The : task-link and + parent-task pickers
discover the inbox, area notes, and non-terminal project notes.
Give area/project notes the appropriate frontmatter type
("[[area]]" or "[[project]]") to include them in those catalogs and in
per-note Ready reports. Nested prerequisites use a separate path-aware &
syntax; see dependency capture.
For the desktop interface, use the plugin deployment guide:
select a local bob-plugins source checkout, deploy with bob plugins sync,
then enable the installed plugins in Obsidian's Community plugins settings.
Review requires Bob Ledger Tools and Bob Navigation Hotkeys. Sync copies
plugin assets; it does not enable plugins or create dashboard notes.
Capture a first task¶
Preview the exact task, then write it:
bob capture --dry-run 'Write an outline @mac_inbox^outline'
bob capture 'Write an outline @mac_inbox^outline'
bob query --tasks '' --format markdown
The task lands in mac_inbox.md with a created date and ^outline block ID.
New tasks have no freshness stamp: they await human confirmation. Use a unique
ID for each task in a note. Reusing this creation command does not edit the
existing task; a duplicate requested ID is an error.
For an ordinary task without an ID, bob capture 'Buy milk' uses the same inbox.
An eligible bare public URL queues a reference job instead of creating a task;
use bob capture --no-ref 'https://example.com/article' to keep it in the inbox.
For several tasks, separate items with blank lines; later bullet lines within
an item become children. The batch is planned before it writes, so a failed
item aborts the capture. See Capture for routing, clipboard,
scheduling, prerequisites, and JSON interfaces.
Plan and run a session¶
Use today's daily note at YYYY/YYYYMMDD.md inside the vault (for example,
2026/20261004.md on October 4), or set BOB_DAY_FILE to its full path.
Create the note if needed. Add a Pomodoros section with an unindented open
entry like the one below; linking needs an open entry, and the bare =3
start needs an untimed () placeholder with no other timed session open.
---
parent: "[[day]]"
---
# Daily note
## Pomodoros
- [ ] () โ WORK
Link the task created above to that session, then start it for 15 minutes:
bob capture '@mac_inbox:outline'
bob plan
bob capture '=3'
bob pomodoro
The marker-only @mac_inbox:outline links the existing task and raises Ready
to Next. A Task Link is the dedicated [[mac_inbox#^outline]] child bullet
in the daily note; the task itself stays in mac_inbox.md. =3 starts the
queued session's timer and leaves the task Next; the close records its work
outcome. Units are five minutes, and bare = means 25 minutes.
Quote session tokens in Zsh. Linking and starting can also
be one transaction: bob capture '@mac_inbox:outline=3'.
When finished, preview bob capture --dry-run 'x' to see the session's
numbered Task Links and proposed outcomes, then submit one close command:
| Command | Outcome |
|---|---|
bob capture 'x' |
Close; ordinary plain links count as worked, eligible tasks become Pending, and their links carry to the next session |
bob capture 'x*' |
Close; park all numbered links, eligible tasks become Pending, and none of those links carry to the next session |
bob capture 'x!' |
Close and complete every numbered Task Link |
bob capture 'x1!2' |
Keep task 1 in progress, complete task 2, and defer the remaining links |
For this one-task example, use x! if the outline is done, or x* if it
still needs work but should leave today's queue. The numbered x1!2
example requires at least two links. "Deferred" means carry the link to the
next session without changing the task's lane or scheduled date. Plain x
also respects existing link markers: a trailing # defers a link, while an
embed (![[note#^id]]) requests completion. Unresolved or ineligible targets
can be skipped with warnings; check the capture report. See
close outcomes for the full rules.
When the close completes a planned task, Bob recovers newly unblocked
dependents immediately and offers them as successor offers
(plan.link_unblocked: true by default). Nothing is auto-linked; pick
which tasks to pull in through the Obsidian picker, the Bob Mac Capture
choice step, or bob capture -p/--pull-in. There is no five-successor
cap. If the project has no remaining work under the project surfacing
rules and no open sub-projects, its completion tracker (^prj) is
offered the same way after #hide is removed, raising Ready or newly
unblocked trackers to Next only when picked, and preserving In Progress.
You still decide whether the project is complete. Future dates and
remaining prerequisites or inherited project blocking prevent that
offer. See completion follow-ups
and project pull-in for eligibility.
Inspect bob task reconcile --dry-run, then run bob task reconcile to
reconcile statuses and clean up links. Next and Pending are sticky: unlinking
a task keeps its lane. The explicit release gesture in Obsidian is Alt+N.
Blocked ([?]) is derived from open prerequisites, a future scheduled date,
or project blocking. A project's prerequisites and date live on its ^prj
completion tracker. While those inputs block the project, its other open
tasks become Blocked and carry #prj_is_blocked. Blocking also passes
through sub-projects linked by their parent frontmatter, including their
^prj lines and open tasks. See
task dependencies ยง13.
With the cursor on a Pomodoro Task Link, Alt+[ / Alt+] toggles the linked task between Next and In Progress (asking once for an optional Work Log summary when moving back to Next); In Progress targets show a rendered โ mark in today's daily note.
Review the backlog¶
bob plan
bob freshness list --limit 10
bob ready
bob plan reports today's themes and Task Links plus Next/Pending pressure.
bob freshness shows the due review queue in PRE โ NEW โ PROJECTS โ PENDING โ
NEXT โ RECURRING โ TICKLER โ ROTTEN โ POST order. These are review groups,
separate from task statuses. A visible recurring occurrence joins RECURRING
when the earliest of its scheduled, due, and start dates arrives;
complete it in Obsidian so Tasks writes the next occurrence. Recurring tasks
never receive a freshness confirmation date ([fresh:: YYYY-MM-DD], a
"stamp"). An ordinary Ready task with a stamp is a TICKLER when a later
scheduled date arrives, or its recorded [unblocked::] date is on or after
the stamp and no later than today. Without a stamp, it stays NEW. Due
project completion trackers (^prj) use PROJECTS instead.
bob ready counts each area's or project's visible, non-recurring Ready
tasks, including NEW and ROTTEN, and excludes its ^prj tracker. The
dashboard READY backlog filters out those review buckets and Today-linked
work. Today means linked under an open Pomodoro in the selected daily
note; it is not a task status. Today-linked tasks and
tasks in canonical daily notes (YYYY/YYYYMMDD.md) are excluded from
ordinary review. Checklist rows tagged #gtd #pre or #gtd #post still
walk in PRE or POST in those places, even when recurring; resolve them by
completion. Hidden, blocked, and future-scheduled tasks stay out.
bob stats is a separate read-only glance at derived daily metrics.
bob themes lists remembered Pomodoro names and their stable hues.
Use bob ready NOTE for one note's
worklist, or bob ready --check to exit 3 when notes are crowded.
With the review plugins enabled in Obsidian, [S or ]s from outside the
queue starts at PRE. Every gesture that answers the landed row advances the
walk once to the next remaining item in the same keystroke: Ctrl+Enter
completes (never crossing the PRE/POST boundary โ Ctrl+Alt+F does),
Ctrl+Alt+F keeps an ordinary non-recurring task, Alt+N releases,
Ctrl+Shift+Enter picks a Pomodoro (โต takes the current/next one), and a
resolving Task Card commit moves on. On an inbox task, every non-closing Task Card answer and
Ctrl+Shift+Enter asks where the task goes as the last step before writing, then answers and moves there.
Ctrl+Shift+M never advances: it follows
the moved task to its destination note, and the next ]s resumes the walk.
Alt+F is the one answer that stays, ]s skips,
and <C-o> returns to the row just answered. Away from the
current review task, ]s / [s first bring you back to it. Review the
commitment groups from PRE through TICKLER until the footer says
Commitments done. Use Ctrl+Alt+F to keep an ordinary task or complete
a PRE/POST checklist row. On RECURRING it writes nothing and stays;
complete the occurrence with Ctrl+Enter, reschedule it into the future,
link it to Today, or cancel it. ]s skips a row without resolving it.
ROTTEN follows for backlog upkeep. ]S jumps to POST; complete the
Morning review checklist last with Ctrl+Enter or Alt+F (on a checklist,
Alt+F completes the row).
Ctrl+Alt+J/K also walks due tasks. Alt+F confirms an eligible non-recurring,
non-checklist task under the cursor. ]s / [s are the equivalent configured
Vim bindings, not shortcuts installed by the CLI. On those ordinary tasks,
Ctrl+Alt+F confirms and advances (Control+Option+F on a Mac).
Hand edits alone do not stamp freshness.
bob freshness list only reports the queue; it does not confirm tasks.
bob freshness seed is a one-time migration for an
existing backlog; it is not the command to confirm today's new captures.
See Freshness for review gestures and tracker cadence.
Optional config lives at ~/.config/bob/config.yml, selected by
BOB_CONFIG_FILE or XDG_CONFIG_HOME. Plan documents caps;
Freshness documents review
intervals. BLOCKS lines documents
dependencies.blocks_lines, and Task
relations
documents relations.linked_from_lines. $1โ$4 capture and bob task reroll also
require the priority configuration.
Save and read references¶
Bob's reference pipeline files the PDF into lib/, writes its note under
ref/, and creates a reading task. A bare link capture does this in a
background job. The success line says queued โฆ โ reading queue as soon as
the job is saved. If intake cannot run, the PDF remains in xlib/ and the
host's local intake timer or bob ref scan -i finishes filing it.
bob capture --dry-run 'https://example.com/article'
bob capture 'https://example.com/article'
bob ref jobs
bob ref find 'https://example.com/article' --include-intake
The capture preview reads local state and writes nothing. The submit queues
the job; the worker fetches the link independently of the capture process.
bob ref jobs shows that job. While the PDF is queued in xlib/,
find --include-intake can locate it. Once filed, plain bob ref find
finds the note.
An eligible URL fills the capture item, optionally with a parent route
and a listen marker: URL @route, URL %, or URL % @route. Put the
standalone % immediately after the URL to request companion audio;
URL @ is an alias. Extra prose, child bullets, or other capture markers
keep it a task. Hosts without a dot, such as http://go/x and localhost, IP
literals, and the default excluded hosts (google.com, googleplex.com,
youtube.com, youtu.be, github.com, x.com, twitter.com, and their
subdomains) stay tasks. Use --no-ref for a task, or configure the
URL routing policy.
When the job's state is clipped, preview and run the scan, then open the
reading queue:
bob ref scan --dry-run
bob ref scan
bob ref list
scan previews the whole configured library, so review that preview before
writing. Pending jobs and intake PDFs stay out of ref list until the scan
creates a reference note. The human and JSON job state for a finished clip is
clipped; the done.jsonl record stores outcome: created. If background
capture fails, the worker writes the link as an inbox task with a warning and
retry command. See ref jobs for recovery.
Check dependencies with bob ref doctor. To import a local PDF, Markdown
report, or URL immediately, run bob ref create <TARGET> -P <area-or-project>.
This writes the intake PDF; then run the scan steps above. Local PDFs are
stamped as-is; Markdown needs pandoc, XeLaTeX, DejaVu fonts, and LaTeX
packages; web articles need uv and a browser. bob ref create --dry-run
skips installing the final PDF, and a web article, PDF URL, or arXiv target
still contacts the network. Use bob capture --dry-run for an offline link
preview. See the target guide. Lookup commands
require the configured ref/ directory to exist.
To read a note's annotations and your own comments, use its path or an exact
identifier returned by find or list:
bob ref show ref/blogs/article.md
bob ref show ref/blogs/article.md --comments-only --format markdown
The path above is illustrative; use the actual note path Bob reports.
What commands change¶
| Commands | Effects |
|---|---|
query, plan, ready, freshness list, stats, capture discovery, capture-complete, projects list |
Read local vault state |
capture-parse |
Classify the draft without opening the vault. It reads the URL routing config unless --no-ref is set; it does not validate vault targets |
capture-rewrite |
Rewrite the draft in memory. It does not open the vault, the clipboard, or the URL routing config |
ref find, ref list, ref show, ref today --dry-run, ref jobs [list], ref migrate-tasks, ref migrate-zorg without --write |
Inspect local references, jobs, or a migration plan without vault writes |
capture, capture-task-id, capture-pomodoro-name, projects sync, task reconcile, freshness seed, ref today |
Write vault notes; a bare public link queues a job that later writes an intake PDF or a fallback task; URL % asks that job for companion audio; capture --dry-run is offline |
vault-sync, nightly |
Reconcile the vault with Git, including commits, merges, and pushes |
task archive |
Archive task blocks and repair links; in a Git vault, commit touched files and push |
task move |
Move open tasks and repair vault references; --dry-run previews without state changes; live Git runs sync before/after and commit touched notes; --offline commits locally |
task reroll |
Re-roll schedules; in a Git worktree, sync before/after and commit rewritten notes; --offline skips sync but still commits locally |
plugins list, plugins sync |
Pull the plugin source repo by default, including for sync --dry-run (--no-pull skips); sync deploys plugin assets with backups. -f json prints one object instead of the table |
gkeep list, gkeep pull |
Contact Keep; pull writes inbox tasks or intake PDFs, commits the Keep inbox note when tasks were written unless --no-commit, then archives verified Keep notes unless --no-archive; a clips-only pull skips that commit; pull --dry-run still contacts Keep and does not clip. A valid note @route chooses a clip's parent ahead of -P |
gkeep migrate-markers, gkeep migrate-tasks |
Rewrite Keep task Markdown and local import evidence offline, with no Keep credentials or network. --dry-run previews. In a Git vault, a live run commits changed notes and import evidence unless --no-commit |
ref create, ref scan, ref sync |
Write PDFs and reference notes inline; create --dry-run still downloads or opens URL targets; create --listen also narrates companion audio; writing scans can run a configured pre-scan hook. scan -f json prints one report |
ref jobs run |
Fetch queued links for their stored destination vaults; write intake PDFs or fallback inbox tasks |
ref migrate-tasks --write, ref migrate-zorg --write |
Copy legacy reading records into ref/zorg/ or move open ref tasks into parent notes and commit them; sync before and after unless --offline |
completion install, completion uninstall |
Change shell adapter files and the completion manifest |
Native vault reading and basic capture need no Git setup. Git workflows expect
the configured remote and credentials; vault-sync uses origin/master.
Follow the Git sync runbook before enabling maintenance.
If a command refuses¶
| Symptom | What to check |
|---|---|
| Task absent from a picker | Root-level route, inbox/area/project type, project status, task status, and Tasks global filter; & has a broader catalog than :/+ |
| Freshness or Ready reports reject the task format | Tasks must use taskFormat: "dataview"; missing settings fall back to emoji |
| Ready rejects invalid freshness config | bob ready shares the freshness scan; fix freshness: as well as plan: config |
| Linking fails | Daily note, Pomodoros heading, open entry, and a unique task block ID |
| Start says to finish the current Pomodoro | Close the running timed entry first; bob capture 'x =3' closes and starts atomically |
| Hooks refuse a Blocked transition | The Tasks registry's ? status must match the required definition |
| A native query using plugin-dependent dashboard filters omits tasks | Native queries do not load desktop Bob plugins; use bob freshness for the headless review queue |
A captured link is absent from ref list |
Inspect bob ref jobs; a clipped intake PDF needs bob ref scan before it has a note |
| A link stays a task | Extra prose, unsupported markers, children, a parent-task destination, --no-ref, a host without a dot, an IP address, an excluded host, or routing disabled in config. A simple @route parent and a % listen marker immediately after the URL are supported |
| Markdown PDF creation fails | Check the pandoc, xelatex, and latex_packages rows in bob ref doctor. Missing packages produce one tlmgr install line in the warnings section. Doctor does not check fonts; install DejaVu Serif, DejaVu Sans, and DejaVu Sans Mono when XeLaTeX cannot find them |
Use bob <command> --help for accepted options and the contract index
for detailed behavior, output formats, and recovery steps.