{"id":50547554,"url":"https://github.com/bbugyi200/bob-cli","last_synced_at":"2026-06-04T00:02:42.401Z","repository":{"id":361849875,"uuid":"1256119703","full_name":"bbugyi200/bob-cli","owner":"bbugyi200","description":"Bugyi's Obsidian - CLI Client","archived":false,"fork":false,"pushed_at":"2026-06-01T15:21:49.000Z","size":869,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-01T15:23:21.359Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bbugyi200.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-06-01T13:32:35.000Z","updated_at":"2026-06-01T15:23:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/bbugyi200/bob-cli","commit_stats":null,"previous_names":["bbugyi200/bob-cli"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/bbugyi200/bob-cli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbugyi200%2Fbob-cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbugyi200%2Fbob-cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbugyi200%2Fbob-cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbugyi200%2Fbob-cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bbugyi200","download_url":"https://codeload.github.com/bbugyi200/bob-cli/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbugyi200%2Fbob-cli/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33884738,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-03T02:00:06.370Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-04T00:02:36.279Z","updated_at":"2026-06-04T00:02:42.395Z","avatar_url":"https://github.com/bbugyi200.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Bob CLI\n\n`bob-cli` installs the `bob` command and compatibility shims for the Bob Obsidian\nvault and Pomodoro workflow. The command implementations are native Rust by\ndefault. The earlier shell implementations remain embedded as a rollback path:\nset `BOB_CLI_USE_SCRIPT=1` to extract those scripts into `XDG_CACHE_HOME` and\ndelegate to them.\n\nThe preferred interface is `bob \u003csubcommand\u003e`. Legacy command names still exist\nas installed binaries for existing tmux, shell, and automation callers.\n\n## Installation\n\nFor local development from this checkout:\n\n```bash\ncargo install --path . --locked --force\n```\n\nFor installation from the Git remote:\n\n```bash\ncargo install --git git@github.com:bbugyi200/bob-cli.git --locked --force bob-cli\n```\n\nTo smoke-test an install without replacing an existing user install:\n\n```bash\nroot=\"$(mktemp -d)\"\ncargo install --path . --locked --root \"$root\"\n\"$root/bin/bob\" --help\n\"$root/bin/bob\" bulk-git-commit --help\n\"$root/bin/bob\" cronjob --help\n\"$root/bin/bob\" dataview --help\n\"$root/bin/bob\" highlights-ref --help\n\"$root/bin/bob\" move-done-tasks --help\n\"$root/bin/bob\" notify --help\n\"$root/bin/bob\" pomodoro --help\n\"$root/bin/bob\" tmux-pomodoro --help\n\"$root/bin/bob_notify\" --help\n\"$root/bin/bob_pomodoro\" --help\n\"$root/bin/bob_sync\" --help\n\"$root/bin/tmux_bob_pomodoro\" --help\n```\n\n## Commands\n\n```bash\nbob bulk-git-commit\n```\n\nStages all Bob vault changes, commits them when anything changed, and pushes via\nGit. This command does not run `ob sync`; use `bob cronjob` for the nightly path\nthat syncs Obsidian before maintenance steps. `bob bulk-git-commit` mutates the\nvault repository and should only be run when Git remotes and SSH credentials are\nready.\n\n```bash\nbob cronjob\n```\n\nRuns the nightly maintenance sequence. It performs one shared\n`ob sync --path \u003cvault\u003e` gate first, then runs `bob move-done-tasks` and\n`bob bulk-git-commit` in order. A failed Obsidian sync aborts before the wrapped\nsteps touch the vault; a failed wrapped step is reported but does not prevent\nlater wrapped steps from running.\n\n```bash\nbob dataview --source '#project'\nbob dataview --query 'LIST FROM #waiting'\nbob dataview --format json --query-file queries/projects.dql\n```\n\nRuns Dataview source expressions and DQL queries from the shell. The default\nnative engine evaluates queries against the local Markdown vault, so scripts do\nnot need a running desktop Obsidian app. `paths` output prints one vault-relative\nMarkdown path per line, `json` output is stable for scripts, and `markdown`\noutput prints Dataview-rendered Markdown for supported DQL results. This command\ndoes not run `ob sync`; vault freshness is handled by the external background or\ncron sync path. Use `--engine obsidian` when you want exact behavior from the\nlive Dataview plugin in an open Obsidian vault.\n\nThe full command contract and live smoke-test steps live in\n[`docs/dataview.md`](docs/dataview.md).\n\n```bash\nbob move-done-tasks [--threshold N]\n```\n\nScans the Bob vault for completed (`[x]`) and canceled (`[-]`) Markdown task\nblocks containing `#task`, then moves blocks from notes that meet the threshold\ninto matching archive notes under `done/`. The default threshold is `10`; use a\nsmaller value for a targeted collection pass, such as `--threshold 1` in a\nfixture vault.\n\nArchive paths mirror the source note path and add `_done` to the file stem. For\nexample, `projects/foo.md` archives to `done/projects/foo_done.md`. Archive\nnotes are created with `parent` pointing at the original source note plus\n`type: \"[[done]]\"`, such as `parent: \"[[projects/foo]]\"` and\n`type: \"[[done]]\"`.\nExisting archive notes have `parent` and `type` frontmatter inserted or repaired\nbefore new blocks are appended. Source notes that have a matching archive note\nare linked back to it with `done_tasks`, such as\n`done_tasks: \"[[done/projects/foo_done]]\"`. Existing archive notes under `done/`\nare backfilled into source note frontmatter and archive metadata on future runs\neven when no task blocks meet the threshold.\n\nWhen task blocks with explicit Obsidian block ids are moved, links to those\nblocks are repaired across vault Markdown notes. For example,\n`[[projects/foo#^abc123]]`, `![[projects/foo#^abc123]]`, and aliases such as\n`[[projects/foo#^abc123|follow-up]]` are rewritten to\n`[[done/projects/foo_done#^abc123]]`. Moved block ids are de-duplicated within\ntheir destination archive note before link repair. If `^abc123` already exists\nin `done/projects/foo_done.md`, the moved id becomes the smallest available\nsuffix such as `^abc123-1`, and repaired links point at that final id. If\nmultiple moved blocks originally share the same id, their archived ids are still\nmade unique, but existing links to the original duplicate id are left unchanged\nbecause the intended block is ambiguous. Only explicit `^block-id` targets can\nbe rewritten; heading links and tasks without block ids do not have a stable\ntarget to repair.\n\nThe command itself does not run `ob sync`; `bob cronjob` runs the shared\nObsidian sync gate before invoking it. In a Git worktree, the command refuses to\nmodify source, archive, or link-repair candidates that already have uncommitted\nchanges, stages only the files it touches, commits with a\n`bob move-done-tasks YYYY-MM-DD` message, and pushes. Non-Git vaults are left\nuncommitted.\n\n```bash\nbob highlights-ref doctor\nbob highlights-ref marker \u003cpdf\u003e\nbob highlights-ref scan [--dry-run]\nbob highlights-ref sync \u003cpdf\u003e [--dry-run] [--write-pdf] [--prefer marker|frontmatter]\n```\n\nPrepares the Highlights app PDF annotation to Bob reference note sync workflow.\n`sync \u003cpdf\u003e` reads the first standalone `/Text` PDF note annotation on page 1\nas the marker note, parses its `key: value` list, and creates or updates\n`ref/\u003cref_type\u003e/\u003cpdf-basename\u003e.md` frontmatter and the managed Highlights body\nregion for PDFs under `lib/\u003cref_type\u003e/`. Top-level library PDFs and explicit\nout-of-library syncs keep the legacy `ref/\u003cpdf-basename\u003e.md` target. It stores a\ncanonical marker projection hash so later runs can sync marker-only edits into\nfrontmatter and, when `--write-pdf` is supplied, frontmatter-only edits back\ninto the PDF marker. Simultaneous marker/frontmatter edits fail with a conflict\nreport unless `--prefer marker` or `--prefer frontmatter` is supplied.\n`--dry-run` reports the planned note/PDF actions without writing either side.\n`marker \u003cpdf\u003e` inspects and renders the marker contract without writing. `scan`\nrecursively processes PDFs under the configured library with collision and\ndirty-target preflights, while `doctor` checks vault paths, sidecars, marker\nreadability, Git state, and optional `ob` availability without writing files.\nMarker notes must include `status` and `parent`; `parent` may be a bare note\ntarget such as `obsidian` or an existing wikilink. Generated reference notes\nalways include `type: \"[[ref]]\"` and include command-managed `ref_type` when it\ncan be derived from the first library path component.\n\nFor `lib/books/foo.pdf`, `sync` discovers `lib/books/foo.md` first and can\nparse simple `foo.textbundle/text.md` or `text.markdown` sidecars. Highlights,\nhighlight comments, and standalone non-marker notes render into the managed\n`\u003c!-- highlights:begin --\u003e` region using stable `^h-...` block IDs. Existing\nmanual body content outside that region is preserved, and disappeared generated\nblocks are kept as tombstones under `### Removed highlights`.\n\nThe full contract and MacBook setup guide live in\n[`docs/highlights-ref-sync.md`](docs/highlights-ref-sync.md).\n\n```bash\nbob pomodoro\n```\n\nPrints the current Pomodoro ledger entry from today's Bob daily note, including\ntime remaining or recent overdue status. It defaults to\n`$BOB_DIR/YYYY/YYYYMMDD_day.md`, or `~/bob/YYYY/YYYYMMDD_day.md` when `BOB_DIR`\nis unset, unless `BOB_DAY_FILE` is set.\nLedger entries may use bold Markdown ranges such as\n`(**0945-1015** [t:: 30m])`; command output remains plain, for example\n`0945-1015 Review crate skeleton`.\n\n```bash\nbob notify PRE_CHECK_SLEEP POST_NOTIFY_SLEEP\n```\n\nPolls `bob_pomodoro` until the current Pomodoro is overdue, then sends a desktop\nnotification when `notify-send` is available and rings the terminal bell.\n\n```bash\nbob tmux-pomodoro\n```\n\nPrints Pomodoro status in the tmux status-line format.\n\nThe installed compatibility shims are:\n\n```text\nbob_pomodoro\nbob_notify\nbob_sync\ntmux_bob_pomodoro\n```\n\nThey call the same native Rust command implementations as `bob \u003csubcommand\u003e`.\n\n## Runtime Dependencies\n\nNormal command execution no longer requires Bash or Perl. These tools are still\nuseful for validating or forcing the embedded script fallback with\n`BOB_CLI_USE_SCRIPT=1`.\n\nThe remaining runtime dependencies are:\n\n- `ob` from obsidian-headless for the shared `bob cronjob` Obsidian sync gate\n- `obsidian` CLI plus a running desktop Obsidian vault with the Dataview plugin\n  only when using `bob dataview --engine obsidian`\n- `git` and `ssh` for `bob bulk-git-commit` and for `bob move-done-tasks`\n  commit/push behavior when the vault is a Git worktree\n- `notify-send` for desktop notifications from `bob notify`\n- `bash` only when loading `ob` through the NVM fallback or sourcing\n  `~/.ssh-agent-thing`\n\nNo old chezmoi script files are required after installation. Cargo installs the\nRust binaries, and the binaries carry the script assets they need.\n\n## Environment\n\n`BOB_DIR` sets the Bob vault directory. It defaults to `~/bob`.\n\n`BOB_DATAVIEW_OBSIDIAN_COMMAND` overrides the executable used by\n`bob dataview --engine obsidian`.\n\n`BOB_DATAVIEW_VAULT` sets the default Obsidian vault name or ID forwarded to\n`obsidian eval` by `bob dataview --engine obsidian`.\n\n`BOB_DAY_FILE` sets the exact daily note path used by `bob pomodoro`.\n\n`BOB_NOW` sets the current timestamp for Pomodoro status and default runtime note\nselection. It also controls the default `bob move-done-tasks YYYY-MM-DD` commit\nmessage date. Supported formats include `YYYY-MM-DD`, `YYYY-MM-DD HH:MM`, and\n`YYYY-MM-DD HH:MM:SS`.\n\n`BOB_HIGHLIGHTS_LIB_DIR` sets the Highlights PDF library directory used by\n`bob highlights-ref`. It defaults to `lib` under `BOB_DIR`. Relative values are\nresolved under the Bob vault; absolute paths and `~/...` paths are used as\nconfigured.\n\n`BOB_HIGHLIGHTS_REF_DIR` sets the generated reference note directory used by\n`bob highlights-ref`. It defaults to `ref` under `BOB_DIR`.\n\n`DATE` preserves the legacy date override behavior. It can be a date command\nprefix such as `date --utc`, or a timestamp in the same formats accepted by\n`BOB_NOW`.\n\n`OB_COMMAND` overrides the `ob` executable used by the shared `bob cronjob`\nObsidian sync gate.\n\n`BOB_BULK_GIT_COMMIT_LOCK_FILE` overrides the lock path used by\n`bob bulk-git-commit` and `bob cronjob`.\n\n`BOB_BULK_GIT_COMMIT_MESSAGE` overrides the commit message used by\n`bob bulk-git-commit`.\n\n`BOB_SYNC_LOCK_FILE` is a deprecated compatibility alias for\n`BOB_BULK_GIT_COMMIT_LOCK_FILE`.\n\n`BOB_SYNC_COMMIT_MESSAGE` is a deprecated compatibility alias for\n`BOB_BULK_GIT_COMMIT_MESSAGE`.\n\n`BOB_CLI_USE_SCRIPT=1` forces the embedded shell fallback implementation.\n\n## Migration Notes\n\nUse `bob pomodoro`, `bob notify`, `bob bulk-git-commit`, and\n`bob tmux-pomodoro` for new integrations, and run `bob move-done-tasks` when\ndone and canceled task blocks should be archived from the vault.\n\nThe old top-level commands were renamed: `bob collect-done` is now\n`bob move-done-tasks`, and `bob sync` is now `bob bulk-git-commit`. The old\ntop-level names are no longer registered. Legacy installed binaries such as\n`bob_sync` remain compatibility shims for existing callers.\n\nThe original script implementations remain embedded only as a rollback path.\nNew integrations should rely on the native Rust command behavior.\n\n## Release Checklist\n\nRun the package checks from a clean worktree:\n\n```bash\ncargo fmt --check\ncargo clippy --all-targets --all-features\ncargo test\njust check-scripts\ncargo package --list\n```\n\nRun a local install smoke test:\n\n```bash\nroot=\"$(mktemp -d)\"\ncargo install --path . --locked --root \"$root\"\n\"$root/bin/bob\" --help\n\"$root/bin/bob\" bulk-git-commit --help\n\"$root/bin/bob\" cronjob --help\n\"$root/bin/bob\" dataview --help\n\"$root/bin/bob\" highlights-ref --help\n\"$root/bin/bob\" move-done-tasks --help\n\"$root/bin/bob\" notify --help\n\"$root/bin/bob\" pomodoro --help\n\"$root/bin/bob\" tmux-pomodoro --help\n\"$root/bin/bob_notify\" --help\n\"$root/bin/bob_pomodoro\" --help\n\"$root/bin/bob_sync\" --help\n\"$root/bin/tmux_bob_pomodoro\" --help\n```\n\nRun a tmux status smoke test after installing locally:\n\n```bash\ntmux display-message -p '#(bob tmux-pomodoro)'\n```\n\nBefore running `bob bulk-git-commit` in a release smoke test, verify that\n`BOB_DIR` points at the intended vault and that its Git remote can be pushed\nwithout prompts. Before running `bob move-done-tasks` against the real vault,\nverify that `~/bob` is the intended vault, inspect `git -C ~/bob status --short`,\nand expect the command to skip candidate files that are already dirty.\n\nThe default `bob dataview` smoke tests are local and headless. Before running\nlive Obsidian smoke tests, start desktop Obsidian, open the target vault, enable\nDataview, and use the explicit `--engine obsidian` examples in\n[`docs/dataview.md`](docs/dataview.md).\n\nFor an end-to-end collection smoke test, install the local binary, run\n`bob move-done-tasks` against `~/bob`, then verify that archive notes under\n`~/bob/done` include `parent: \"[[source]]\"` for the original note and\n`type: \"[[done]]\"`, source notes include matching `done_tasks` links and no\nlonger contain the collected blocks, Obsidian links to moved `^block-id` task\nblocks point at `done/..._done#^block-id`, and the vault Git commit was pushed.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbbugyi200%2Fbob-cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbbugyi200%2Fbob-cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbbugyi200%2Fbob-cli/lists"}