Skip to content

Installation

Chapter 01 of the ResearchTools manual. Back to table of contents.

Follow these steps on any machine after cloning the repository.

Install scripts overview

Three scripts, three different jobs and lifecycles. setup.ps1 is the single entry point: it wraps the other two via -InstallJunctions / -InstallTools, and -All runs the full sequence (config, then junctions, then tools) in one pass.

setup.ps1 -InstallDaemon is the fourth job, and it belongs here rather than in the two installers: it delegates to .claude\skills\obsidian-cli\scripts\vault-daemon-autostart.ps1 -Install, which puts one shortcut in the Startup folder so the vault event daemon is running at login and raw drops in ~/.claude/obsidian-outbox/raw get filed instead of piling up. -All includes it only when a vault is configured, and says so in one line when it skips: a login daemon with no vault starts, finds nothing and exits invisibly. install.ps1 runs many times a day and install-junctions.ps1 -Sync runs at every session start, so a Startup write in either would come back after the user deliberately removed it.

Nothing installs that shortcut on its own, and no tool here should: the Startup folder is the operator's. The daemon is therefore started by the operator, either by running setup.ps1 -InstallDaemon once so it comes up at every login, or by launching vault-daemon-autostart.bat when it is wanted. Until one of those happens, raw drops simply accumulate in ~/.claude/obsidian-outbox/raw/ and are filed the first time the daemon runs; they are not lost. vault-daemon-autostart.ps1 -Status is read-only and answers the three questions that matter - whether a daemon holds the lock right now, what the log's tail says, and whether the login shortcut exists at all.

setup.ps1 install-junctions.ps1 install.ps1
Job Detect this machine's paths (Git Bash, Node, Obsidian) and fill the gaps in the GLOBAL Claude Code configuration from the two templates Link the repo into ~/.claude so Claude Code loads agents/skills/rules/commands in every workspace Generate mirrors for other coders: GitHub Copilot, OpenCode, Continue, Aider, AGENTS.md readers (-Personal adds the user-level Copilot install)
Output Nothing inside the repository. Additively: ~/.claude/CLAUDE.md (whole file only when absent), ~/.claude/settings.json (only the hook entries the template declares and the live file lacks), OBSIDIAN_VAULT at USER scope (only when unset), and .venv-skills/ in the clone with -InstallPython Links in C:\Users\<you>\.claude\ Generated files committed in the repo (.github\, .opencode\, .continue\, CONVENTIONS.md, AGENTS.md) + optional user copies
When to run Once after clone (or when machine paths change) Once after clone; re-run when an agent or skill is ADDED (or a hardlink detached after a pull) After every agent/command/rule EDIT, then commit the output
Privilege none symlinks want Developer Mode (automatic hardlink fallback) none
Interactive yes (asks vault path, confirms) - -NonInteractive refuses with exit 2 instead of assuming a default, and -Preview writes nothing at all no no
Via setup.ps1 - -InstallJunctions -InstallTools
Other switches -InstallDaemon (vault daemon at login), -InstallPython (.venv-skills for the offline suite) - -
.\setup.ps1 -All -Personal   # new machine: config + Claude links + all tool mirrors

The CLAUDE*.md family

Two files, both hand-written, both English, neither carrying a machine path or a person's name. A file a script generates is never a tracked file, so anything derived from these lands in ~/.claude/ or in the mirrors, which are regenerated wholesale and reviewed as output.

File What it is Written by Where its content lands
CLAUDE.template.md Source of the GLOBAL instructions: session rules, Obsidian vault integration, git-sync, plan-mode workflow, hooks. Carries the {{OBSIDIAN_VAULT}} / {{OBSIDIAN_EXE}} placeholders and the only copy of the RT-CONTRACT block a human ~/.claude/CLAUDE.md — the whole substituted file when that file does not exist, the RT-CONTRACT block alone when it does (install-junctions.ps1 -Sync, Update-RtClaudeMd)
.claude/CLAUDE.md The repository's own authority: mission, writing standard, references, figures/tables/equations, the routing table, pipeline integrity, where code belongs a human loaded by Claude Code when working inside this repository

Two files that used to sit beside them are gone: a root CLAUDE.md, which was a generated copy of the template carrying this machine's vault and Obsidian paths, and CLAUDE (up).md, a stale copy of the parent directory's file that nothing read. Only the root CLAUDE.md is gitignored.

.claude/settings.json is a different case and is committed. It is the shared project scope, and it has to reach GitHub: a routine running on the web clones this repository and has no ~/.claude of yours, so this committed file is the only way it learns which plugin marketplaces to trust when it reviews a pull request. It holds marketplace and plugin declarations only — no absolute path, no account name, no secret. It must never declare hooks: the global file already does, a project copy makes every hook run twice, and their commands are Windows paths that do not exist on a Linux runner. Anything machine-specific goes in settings.local.json, which is gitignored. .claude/settings.template.json remains the declaration of the GLOBAL ~/.claude/settings.json, which is a separate file with a separate job.

Prerequisites

Tool Required for
Claude Code Running agents and slash commands
Git for Windows (includes Git Bash) Hooks that use bash shell
Node.js Caveman-mode hooks (caveman-activate.js, etc.)
Python 3.x Scopus skill scripts + security hooks (betterleaks, pip-audit, prompt-injection-defender)
pip install requests google-genai openai Scopus skill + Gemini/Copilot cross-review
pip install pymupdf4llm pymupdf (optional, AGPL-3.0) extract-statistic skill PDF parsing (mine mode), LLM-ready Markdown + table extraction; reuses SCOPUS_API_KEY via download_pdf.py, needs no key of its own
pip install docling markitdown[pdf] (optional, MIT; Docling pulls torch) Pluggable Markdown backend for extract_text.py (--stats-scan / --section-scan) and HTML conversion in the any-format retrieval path. Docling is the default (best tables/layout), MarkItDown the light fallback; absent both, the parser uses pymupdf4llm + a tag-strip
pip install "psycopg[binary]" pgvector (optional) extract-statistic's opt-in corpus_index.py (RT-7): pgvector store for ad-hoc cross-corpus retrieval. Both degrade gracefully when absent - the parse cache (parse_cache.py) and the chunker work without them, and the index reports itself unavailable
pip install matplotlib (+ optional folium) geolocalisation skill: world-map PNG figure (matplotlib) and interactive HTML map (folium). No geopandas/GDAL. The --full-text study-site scan additionally reuses pymupdf + download_pdf.py
pandoc word2latex skill (Word → LaTeX)
pip install pypdf python-pptx jinja2 defusedxml paper2talk skill: paper-size PDF reflow (pypdf), the gabarit-based PowerPoint renderer (python-pptx), the Beamer/web renderers (jinja2), OOXML reading (defusedxml). Pinned in .claude/skills/paper2talk/scripts/requirements.txt
npm install pptxgenjs (optional) paper2talk fallback for a PowerPoint deck with no gabarit at all. Set NODE_PATH when building outside the tree that holds the install
PowerPoint (Office 16+) or LibreOffice, plus Poppler pdftoppm paper2talk render loop: deck → PDF → page images. On Windows the working path is PowerPoint COM SaveAs(..., 32); the document-skills soffice.py wrapper fails here with AF_UNIX. Poppler ships with MiKTeX
draw.io Desktop (optional) paper2talk figure re-export at scale 3 (fig_export.py); locate it with --drawio or DRAWIO_EXE
pdflatex (TeX Live / MiKTeX) recommendation-letter skill: compile letters to PDF (degrades to .tex only if absent)
Obsidian Desktop (optional) Obsidian vault integration in CLAUDE.md
uv tool install graphifyy (optional) The graphify CLI behind the code-graph memory. The SKILL is vendored here (.claude/skills/graphify/, from graphify 0.9.50) so a clone is never left with instructions to consult a graph and no way to reach one; the CLI itself is not, and without it query, path, explain and update are simply unavailable
Ollama (optional) The local model behind local-writer and local-coder
Docker and Docker Compose (optional) deploy/form-service/, the containerized HTTP transport over the form-service skill. Not needed to use the skill itself

Two Ollama settings are the operator's own step, and the scope is not interchangeable. The GRAPHIFY_* pair ships in .claude/settings.template.json, because graphify runs as a child of Claude Code and sends its own keep_alive in every request body, which overrides the daemon default. The OLLAMA_* values cannot ship there at all and belong in the Windows user registry (HKCU:\Environment), because the Ollama daemon is started by its own tray application at login and never sees Claude Code's environment. Setting only one of the two leaves the model being unloaded on a timer that nothing in this repository controls:

# operator step, once, then restart the daemon and confirm with `ollama ps`
[Environment]::SetEnvironmentVariable('OLLAMA_KEEP_ALIVE',        '-1', 'User')
[Environment]::SetEnvironmentVariable('OLLAMA_MAX_LOADED_MODELS', '1',  'User')
[Environment]::SetEnvironmentVariable('OLLAMA_NUM_PARALLEL',      '1',  'User')
[Environment]::SetEnvironmentVariable('OLLAMA_FLASH_ATTENTION',   '1',  'User')

OBSIDIAN_VAULT is the third value of this kind, and setup.ps1 now offers to set it at USER scope when you give it a vault path. It is add-only: a variable that already holds a value is printed and left alone unless you pass -Force, and a path that does not exist is refused rather than stored. USER scope rather than the current shell is deliberate — the Startup shortcut passes no argument, so a login-started daemon reads the user environment block and nothing a shell exported. An already-open terminal keeps its old block, and VS Code has to be restarted before a session sees the new one.

ollama ps must then show Forever in the UNTIL column. Restart the daemon with .claude\skills\opt-local-vram-llm\scripts\restart-ollama.ps1, never by killing ollama* by name: the model runs in a child process called llama-server.exe, which that pattern does not match, so it survives and keeps its slice of VRAM.

Step 1 — Clone the repository

git clone https://github.com/LARi-UQAC/ResearchTools.git
cd ResearchTools

Step 2 — Detect this machine's paths

Run the setup script from the repository root. It auto-detects Git Bash and Node.js and asks for your Obsidian vault path (optional).

.\setup.ps1

It writes nothing into the repository. The two templates (.claude/settings.template.json, CLAUDE.template.md) are the hand-written sources, and the configuration they describe belongs in your global Claude Code folder, ~/.claude/.

This step links ~/.claude/agents/, ~/.claude/skills/, ~/.claude/rules/, and ~/.claude/commands/ into this repository, so that Claude Code loads these agents and skills in every workspace, not only when you open this folder.

Only missing links are created; existing ones are never overwritten.

# Preview what will be created without making changes
.\setup.ps1 -InstallJunctions -Preview

# Apply
.\setup.ps1 -InstallJunctions

Alternative (direct): .\install-junctions.ps1 (or .\install-junctions.ps1 -WhatIf to preview).

How linking works by directory type (skills are folder-based, agents are file-based — see the Agents chapter):

Directory Link type One link per… New file/folder after git pull
agents/ SymbolicLink per FILE (HardLink fallback when Developer Mode is off) Agent file (e.g. scopus-researcher.md) Re-run .\setup.ps1 -InstallJunctions — existing agents show [EXISTS], only the new one is created. With HardLinks, also re-run after a pull that EDITS an agent (git rewrites detach hardlinks)
skills/ Junction per sub-folder Skill (e.g. scopus/) Re-run — only the new skill is created
rules/ Junction on the whole directory Entire rules/ folder Automatic — new .md files are visible immediately through the existing junction, no re-run needed
commands/ Junction on the whole directory Entire commands/ folder Same as above

Junctions need no Administrator privileges. Agent file links prefer SymbolicLinks (enable Windows Developer Mode, or run elevated); without that privilege the script falls back to HardLinks automatically.

Fallback when rules/ or commands/ already exists as a real directory (another project previously created it): the script automatically switches to per-file symbolic links for any missing files. If Administrator privileges are required for the symlinks, the script re-launches itself elevated.

Because the links point directly into this repository, a git pull is all that is needed to propagate rule and command improvements contributed by any collaborator.

Step 4 — Install for other coding tools (optional)

install.ps1 regenerates the GitHub Copilot, OpenCode, Continue, Aider, and AGENTS.md mirrors from the canonical .claude/ sources (agents, task commands, rules). With -Personal it also installs the Copilot agents to ~/.copilot/agents/ and the prompt/instruction files to the VS Code user profile, making them available in every workspace:

.\install.ps1                     # repo-level mirrors only (commit the output)
.\install.ps1 -Personal           # + user-level Copilot install
.\install.ps1 -Profile cosmetic   # + select the active domain profile
.\setup.ps1 -InstallTools -Personal   # same, via the setup entry point

install.ps1 also records the active domain profile (see Profiles): pass -Profile <name> or answer the interactive prompt; non-interactive runs keep the current default (engineering).

Details in Using the agents outside Claude Code.

Step 5 — Python environment for the offline test suite (optional)

scripts/test/run-offline-tests.ps1 resolves .venv-skills\Scripts\python.exe first, then .venv, then whatever python is on PATH. Without that environment several suites cannot import what they need and are reported NOT RUN — which is honest, and means the suite is not actually proving what it looks like it is proving.

.\setup.ps1 -InstallPython            # creates .venv-skills, installs, then pip-audits
.\setup.ps1 -InstallPython -Preview   # say what it would install, install nothing

It installs only what the offline suite imports: pypdf, python-pptx, jinja2 and defusedxml for the thirteen paper2talk suites, and PyYAML for test_letter_identity.py. Everything else in the Prerequisites table above stays a manual step on purpose — docling alone pulls torch, and a CVE in a skill you never run should not block the environment your tests need.

By hand, if you would rather not use the switch:

python -m venv .venv-skills
.\.venv-skills\Scripts\python.exe -m pip install -r .claude\skills\paper2talk\scripts\requirements.txt
.\.venv-skills\Scripts\python.exe -m pip install -r .claude\skills\recommendation-letter\scripts\requirements.txt
.\.venv-skills\Scripts\python.exe -m pip_audit --strict -r .claude\skills\paper2talk\scripts\requirements.txt

The directory name matters: name it anything else and the runner will not look there.

Contributing improvements

Fork the repository, improve an agent or skill on a feature branch, and open a pull request against main. The repository owner reviews and merges; a git pull on their machine immediately updates the linked entries via the junctions.

To add or edit an agent, skill, or command (and propagate it to Copilot, OpenCode, Continue, Aider, and AGENTS.md readers), follow the turnkey guide docs/authoring-and-mirrors.md: canonical sources, per-type checklist, and the install.ps1 mirror regeneration. Shared project conventions and environment facts (English-only definition files, agent/skill layout, local-model routing, git/GitHub workflow) live in docs/contributor-notes.md.


← 00 Purpose & overview | Table of contents | 02 Profiles & environment →