A CLI tool for organizing PhD research assets, auto-routing PDFs, and syncing Readwise highlights.
Install the macOS command dependencies:
brew bundle --file "$HOME/repos/research-workbench/Brewfile"Add this block to your ~/.zshrc:
# Research workflow
export WIKI_PATH="$HOME/Documents/wiki"
[ -f "$HOME/repos/research-workbench/shell/res.zsh" ] \
&& source "$HOME/repos/research-workbench/shell/res.zsh"res.sh— the main dispatcher (init,add,ln,unlink,relink,mv,repair,finalize, …). Honors$READWISE_TOKENand$WIKI_PATHfrom the environment.- For Readwise Reader URLs (
readwise.io/reader/document_raw_content/...in note front-matter, orread.readwise.io/read/...),resdoes not download that URL withAuthorization: Token(Readwise returns 401). It calls the Reader v3listAPI to obtain a time-limited S3raw_source_urlfor the underlying PDF, then downloads that. RequirescurlandjqonPATH. - Finder project pins are managed with
mysides. Useres finder syncto pin registered projects with id labels like[0] Missional AI Summit.res finder clearremoves only pins recorded in the managed state file. shell/res.zsh— a small zsh integration that provides:res init <name>— create a project, thencdinto the new project root.res cd <id|name>—cdinto a project's root (requires a shell function).res search on|off— toggleTAVILY_ENABLEDin the current shell.res <anything else>— delegates tores.sh.
tavily_wrapper.sh— Tavily search helper used by the Gemini CLI plugin.
Use unregister to remove a project from the registry and Finder pins while
leaving its directory alone:
res unregister 1
res unregister -f 1Use delete to remove the project directory and unregister it:
res delete 1
res delete -f 1Both commands default to the registered project whose directory is the current
directory or one of its parents. If you are not inside a registered project, they
print help instead. New projects use the next available project id above the
current maximum, so unregistering a project does not cause id reuse. When run
through shell/res.zsh, both commands show a tree preview before the
confirmation prompt, using the same tree command configured in your zsh
startup.
Use ledger while a project is active to create a reviewable source ledger
without marking the project done:
res ledger
res sources 1
res ledger --no-llm 1The ledger writes a compact LLM-first control file under
reports/YYYY-MM-DD_Source_Ledger.md: a short attention queue plus YAML for
source roles, weights, symlink status, review flags, and actions. Early on, scan
only the attention queue. Once the classifications are consistently right, you
can let future LLM runs consume the YAML directly and use res finish as the
final closure step.
Use finish, done, or retro to create the final retrospective note for a
project after the ledger is stable:
res finish
res done 1
res retro --model gpt-5-mini 1
res finish --no-llm 1The command defaults to the registered project whose directory is the current
directory or one of its parents. It writes a retro note and the prompt/context
used to generate it under the project's reports/ folder. By default it uses
RES_RETRO_LLM_CMD if set, otherwise the model from RES_RETRO_LLM_MODEL or
OPENAI_EVERYDAY_MODEL, then the llm CLI, then gemini; --no-llm only
writes the prompt and placeholder note.
Suggested transition:
- Run
res ledgerand review every role/weight manually. - Rerun
res ledgerafter source changes and compare the new draft. - When the ledger is trustworthy, use it as the project source-of-truth and run
res finishonly when you want a final retrospective. - Later, automate more aggressively by trusting low-risk ledger updates and only
reviewing the attention queue or files marked
needs_review: true.
Use ln to attach an existing wiki file to a project's sources folder:
res ln 1 swbts-applicationUse unlink to remove a source link from a project without deleting or moving the
original file:
res unlink 0 swbts-applicationUse relink / rl to make a project keep a source link, cleaning up matching
links from other projects when needed:
res rl 1 swbts-applicationYou can also give both source and destination projects for a precise relink:
res rl 0 1 swbts-applicationSet READWISE_TOKEN before running commands that call the Readwise API:
export READWISE_TOKEN="..."
res add <url>Use readwise-project to fetch recent Reader documents, detect whether they
have already synced into the Obsidian vault, count synced highlights, and emit
candidate area/project suggestions based on the vault's .keywords files and
project registry.
Examples:
./readwise-project --limit 10
./readwise-project --limit 10 --seen true --format tsv
./readwise-project --limit 20 --location new
./readwise-project --limit 10 --source-url-contains docs.google.com --unsynced-only
./readwise-project --limit 10 --source-url-contains docs.google.com --unsynced-only --interactive-routeThe default output is JSON with fields like:
synced_to_wikisynced_note_pathhas_highlightshighlight_countsuggestions
Interactive Google Docs routing:
- Only shows documents that are not already synced into
90_media/readwiseand are not previously routed/excluded. - Prompts for a project id/name,
skip,exclude, orquit. - Saves routed markdown notes into the selected project's
sources/. - Persists triage state under
99_meta/readwise_triage/.