bob capture-complete¶
Complete the capture marker at the cursor
bob capture-complete --help
Return cursor-aware completion candidates for in-progress capture TEXT.
It shares the phase-grammar tokenizer and `@token` classification with `bob capture-parse`, so a completion can never disagree with the marker highlighting derived from that command. TEXT accepts the same blank-line-separated batch draft `bob capture` does; completion always scopes to the item and physical line the cursor is on, so only that item's first (parent) line offers a leading marker and a later column-zero or valid two-space nested authored line only completes its own trailing marker. A cursor on a blank separator row returns an empty success. The service decides whether completion applies at all: an unrecognized marker, a cursor in plain body text, a cursor on an authored line's indentation or bullet marker itself, an orphaned nested line, or a cursor on a token in the middle of a line all return a successful empty result rather than an error.
Route completion covers a bare '@', a still-typing '@fragment', and the missing route portion of '@^...', '@+...', '@:...', and '@#...', plus the route component of a '@@', '@@fragment', or '@@route+...' declaration anywhere in the draft. Replacement ranges for that declaration exclude both '@' sigils and the '+'. Parent-task completion covers '@@route+fragment' the same way it covers '@route+fragment', including -a/--all-tasks missing-ID candidates. An inherited global route also becomes the current note for same-note wikilink heading/block completion unless that item overrides it. Route completion is backed by the same scan as `bob capture-targets`. Section completion covers '@route#prefix', backed by the same scan as `bob capture-sections`. Task-section completion covers '@route+id#prefix' and a bare '@route+id#', backed by the same scanner as `bob capture-task-sections`; replacement text is the section slug. Pomodoro-name completion covers '@route:id#prefix', a bare '@route:id#', '@route:#prefix', '@route^id+#prefix', and a bare '@route^id+#'; Today rows come from `bob capture-pomodoros`: link-name completion offers open entries, while start-name completion also offers completed names as `again` rows. Duplicate theme keys collapse without merging distinct names that happen to share a selector slug. Both contexts compose their menu as Today matches, Recent exact/prefix matches, an optional create row, Recent substring matches, then utility rows. Recent comes from canonical daily notes, excludes hidden themes and components already represented by Today, and is capped at five rows for an empty query or twelve otherwise. Hidden themes still work when typed and still appear in Today. An exact Today or Recent match suppresses a separate create row; a prefix match does not. A create row sets creates_pomodoro and replaces the query with the canonical selector; accepting it edits only the draft, and `bob capture` creates the named placeholder later.
Recent rows set origin=history, last_used, days_used, and creates_pomodoro. Named rows expose their component themes and hues. A create row may set hidden or similar_to to explain an existing preference or nearby name. Recent, create, and again rows preview the plan budget with plan_themes_after and plan_themes_cap (omitted when the daily note or plan config is unavailable). Replacements preserve the displayed name, using an exact-name quoted literal when a plain selector would change it or select another theme. Partial quoted names match theme-key prefixes; plain names also match slug substrings.
Pomodoro-start-name completion covers the name part of a `=<X>#name` named start and the `=<X>#` incomplete state. A planned placeholder that a bare `=` would start carries next_up. Nameable utility rows set requires_name and use an empty replacement that clients must not insert; the running entry is last in start-name completion. A missing daily note, a missing Pomodoros section, and multiple open timed Pomodoros stay write-free warnings without a create row. On a `@<route>:<block-id>[#<name>]=<X>` marker the `=<X>` start suffix is never completable: block and Pomodoro-name replacement ranges end before the `=`, a cursor inside the suffix returns an empty success, and accepting a candidate preserves the typed suffix. The `=x[<N>][*<P>][!<M>][~<K>]` close suffix behaves the same way: it is never a completion field, replacements still stop before `#`/`=`, and a cursor anywhere inside the suffix, including the task-number lists and a dangling `,`/`~` separator, returns an empty success. A whole-item `+[N]`/`-[N]` Pomodoro adjustment, `++[N]`/`--[N]` Pomodoro shift (a bare `+`, `-`, `++`, or `--` is one unit), `x[<N>][*<P>][!<M>][~<K>][@<N>]` close, or a bare `=`/`=<X>` start (a bare `=` starts 25 minutes) is an action and requests no route or task completion candidates: a cursor on such an item returns an empty success. Work Log text completes like a bullet line whether it sits below the close or on it: inline entry text requests no marker, `:`/`^`, or `wikilink_block` candidates, while note and heading wikilinks keep completing. A `=<X>#name` named start instead completes the name after `#` as `pomodoro_start_name`, per token inside chains; a cursor on `=<X>` or at the `#` byte itself returns an empty success, the `pomodoro_start_name` replacement range ends before a trailing `~<K>` drop part so accepting a name keeps the typed list, and a cursor anywhere inside the drop part, including a dangling `~`/`,` separator, returns an empty success. Pomodoro block-ID completion covers '@route:prefix' and parent-task completion covers '@route+prefix', both backed by the same open-task scan as `bob capture-tasks` and, by default, only offer tasks that already carry a block ID. Pass -a/--all-tasks to include open tasks that still need an ID, but only in the '@route+' task context; Pomodoro '@route:' completion stays identified-only so older callers never receive action candidates they cannot handle. Missing-ID task candidates keep a placeholder replacement that must not be inserted, expose a nullable block_id, carry the route and stale-safe ref, and set requires_block_id. Task search matches block ID, description, section, and status name or symbol; identified tasks stay ahead of unidentified tasks, and prefix matches precede substring matches inside each group. A terminal bare `+query` on an item parent line or eligible authored child line uses the `task_parent` context: it searches all linkable open tasks across the vault, returns the stripped query and a server-authored picker descriptor, and replaces the whole selector. ID-less rows carry `requires_block_id` plus suggested IDs and an empty replacement, so clients must offer Add block ID rather than insert the row. A lone `+` is the intentional dual-use case: completion opens this picker and its descriptor returns the action continuation keys `0` through `9` and `+`, allowing an editor to preserve the Pomodoro adjustment. Scoped `@route+id` and `@@route+id` keep the `task` context, with picker scope and removal ranges identifying the note-local parent marker. When either parent-task picker has complete `&` or `*` modifiers on its item, `picker.relationship` reports the resolved relationship rows (`raw`, `note_path`, `block_id`, and optional `text`). Self-edges, dependency cycles, and project-resident conflicts set `disabled_reason` and an empty replacement; shell completion omits those rows. For `task_dependency` and `blocked_task`, `owner` adds the resolved task's `text`, `note_path`, `status_symbol`, and `status_name`; a new-task owner carries its non-empty draft text. Unresolved owners keep the lexical owner fields. A draft with no complete relationship modifiers keeps the existing response shape. A `~` / `~~` modifier opens `relation_to` / `relation_from` over the full task catalog. Rows report `already_linked`, an existing label when present, and `also_prerequisite`; read-only sources and malformed source LINKS lines are disabled in `relation_from`. A `|label` field opens `relation_label`, whose suggestions count labels across all LINKS lines and return canonical `|label` or `|"multi word"` replacements. A `||label` probe keeps the `||` spelling in `replacement`, gains `one_off: true`, and every row also carries `hide_replacement` (always the `||` form). A typed invalid label stays first with a `disabled_reason` and an empty replacement. A solo leading '^' token completes active tasks instead: the `route:block-id` part offers In Progress and Next tasks with block IDs, ordered by today's open-Pomodoro Task Links (queued first, then In Progress, then Next), and accepting a row inserts the full `route:block-id` in one step while a typed `#name`/`=<X>` suffix survives. A `#name` after `^route:block-id` completes Pomodoro names exactly as it does after `@route:block-id`, and a cursor inside `=<X>` or `=x[<N>][*<P>][!<M>][~<K>][@<N>]` offers nothing. A whole-item `!` token completes `task_complete`: every open task (Ready, Blocked, Next, In Progress) in the vault-wide completable catalog, today rows first and ranked by the query with today matches on top; the replacement covers the whole `!` token, sigil included, and the response carries a vault-scoped `picker` descriptor plus the `!`/`[` continuation keys on a bare `!`. A solo leading `:` token completes `task_link`: every linkable open task (Ready, Blocked, Next, In Progress) in the routable inbox, area, and non-terminal project notes, in canonical picker order and ranked by the query with ID-less tasks always included; the replacement covers the whole `:` token, sigil included, because accepting rewrites the query into the canonical `@route:block-id` link. A whole-draft `/` token completes `task_goto`: the same rows and order as `task_link`, with `note_path` and absolute `target` for opening the task; the replacement covers the whole token and is never inserted. The right-hand side of '@route^block-id' completes as `task_block_id` once the route resolves, with empty candidates and an additive `block_id` object carrying intent, used IDs, and suggestions. A project-note `+` directly after the `^` block-ID part is never part of the replacement; a `+` after a `:` block ID is the retired project-note form and offers nothing. A trailing ` :id` or ` ^id` on a first-level bullet of a project-note item completes as `project_task_block_id`, with empty candidates and an additive `block_id` object carrying intent `new`, the project-note stem, the sigil range, the bullet body, used IDs (`prj` plus sibling task IDs), and suggestions. An empty block-ID component ('@route+#') returns a successful empty task-section list; an unresolvable parent task returns a successful empty list plus one bounded warning. Other contexts still rank exact prefix matches before substring matches, case-insensitively, while keeping each discovery source's stable order. Task-section ranking uses slug-prefix matches first, then slug-substring matches, in document order inside each tier.
When the cursor is inside an Obsidian wikilink, wikilink completion takes precedence over capture-marker completion. Note completion covers `[[note` and offers Markdown note paths, stems, and aliases. Heading and block completion cover target-qualified links like `[[note#Head` and `[[note#^block`, same-destination links like `[[#Head`, and vault-wide searches like `[[##Head` and `[[^^block`. Candidate replacements own the missing closing delimiter when needed and report the final cursor offset.
Usage: bob capture-complete [OPTIONS] --cursor <BYTE> [TEXT]...
Arguments:
[TEXT]...
Capture text; multiple args are joined with spaces; unknown `--flag` before `--` is rejected
Options:
-a, --all-tasks
Include open tasks that still need a block ID (task context only)
-b, --bob-dir <DIR>
Bob vault root; defaults to BOB_DIR or ~/bob
-c, --cursor <BYTE>
UTF-8 byte offset of the cursor within TEXT
-f, --format <FORMAT>
Output format: human or json
[default: human]
[possible values: human, json]
-h, --help
Show help
Examples:
bob capture-complete --cursor 1 --format json -- '@'
bob capture-complete -c 4 -- '@@fo'
bob capture-complete -c 20 -- 'Buy milk @@gro'
bob capture-complete -c 19 -f json -- 'jot idea @notes#Id'
bob capture-complete -c 20 -f json -- 'Fix flaky test @sase^'
bob capture-complete -c 12 -b ~/bob -- 'Do work @Dev^new-id'
bob capture-complete -c 16 -b ~/bob -- 'Do work @Dev:foc'
bob capture-complete -c 16 -b ~/bob -- 'note @foo+bar#'
bob capture-complete -a -c 6 -f json -- '@file+'
bob capture-complete -a -c 8 -f json -- '@@file+'
bob capture-complete -c 5 -- '[[sas'
bob capture-complete -c 1 -- '^'
bob capture-complete -c 1 -- ':'
bob capture-complete -c 1 -f json -- '/'
Contexts:
route, section, pomodoro_block_id, task_block_id, project_task_block_id, pomodoro_name, pomodoro_start_name, task, task_section, active_task, task_link, task_goto, task_parent, task_dependency, blocked_task, relation_to, relation_from, relation_label, task_complete, wikilink_note, wikilink_heading, wikilink_block