# 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](<https://bobs-org.github.io/start/install/index.md>) for remote installation and [completion](<https://bobs-org.github.io/completion/index.md>) 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](<https://bobs-org.github.io/task-status-hooks/#derived-blocked-status>) (`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](<https://bobs-org.github.io/capture/#adding-prerequisites-with>).

For the desktop interface, use the [plugin deployment guide](<https://bobs-org.github.io/plugins/index.md>): 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](<https://bobs-org.github.io/capture/index.md>) 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](<https://bobs-org.github.io/capture/#closing-the-running-pomodoro>) 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](<https://bobs-org.github.io/task-dependencies/#12-successor-offers>) and [project pull-in](<https://bobs-org.github.io/task-dependencies/#1210-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](<https://bobs-org.github.io/task-dependencies/#13-project-dependencies>).

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](<https://bobs-org.github.io/freshness/index.md>) for review gestures and tracker cadence.

Optional config lives at `~/.config/bob/config.yml`, selected by `BOB_CONFIG_FILE` or `XDG_CONFIG_HOME`. [Plan](<https://bobs-org.github.io/plan/#config>) documents caps; [Freshness](<https://bobs-org.github.io/freshness/#2-fields-overrides-and-config>) documents review intervals. [BLOCKS lines](<https://bobs-org.github.io/task-dependencies/#1410-kill-switch>) documents `dependencies.blocks_lines`, and [Task relations](<https://bobs-org.github.io/task-relations/#12-kill-switch-outputs-and-warnings>) documents `relations.linked_from_lines`. `$1`–`$4` capture and `bob task reroll` also require the [priority configuration](<https://bobs-org.github.io/projects/#priority-property-and-scheduled-rolls>).

## 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](<https://bobs-org.github.io/ref/#url-routing>).

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](<https://bobs-org.github.io/ref-jobs/index.md>) 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](<https://bobs-org.github.io/highlights-create/index.md>). 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](<https://bobs-org.github.io/vault-git-sync/index.md>) 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](<https://bobs-org.github.io/develop/contracts/index.md>) for detailed behavior, output formats, and recovery steps.
