CLI reference, skills, experiments, and advanced configuration.
Run distillate with no arguments to enter the Nicolas REPL — an interactive research agent powered by Claude Code. Nicolas can search your paper library, launch experiments, and synthesize insights across your work.
$ distillate
─── ⚗️ Nicolas ──────────────────────────────
Your research alchemist.
🧪 4 experiments · 12 runs · 1 running
📚 42 papers read · 7 in queue
Single-turn mode: pass a query as an argument.
$ distillate "what papers discuss attention mechanisms?"
Type a skill name in the REPL to invoke it. Skills are organized into two areas:
Laboratory (experiments)
/conjure Launch a new autonomous experiment
/steer Guide a running agent — adjust goals or direction
/assay Deep analysis of experiment results
/distill Extract insights from session histories
/survey Scan all experiments for new runs and breakthroughs
/transmute Turn paper insights into experiment ideas
Library (papers)
/brew Sync papers from Zotero, extract highlights, generate summaries
/forage Browse trending research, get reading suggestions
/tincture Deep extraction from a single paper
Distillate experiments are git repos where autonomous Claude Code agents run ML training loops. Each commit is one run. Results are tracked in .distillate/runs.jsonl.
# In the Nicolas REPL:
> /conjure tiny-matmul --duration 30m
# Or via the CLI:
$ distillate "conjure an experiment to classify sigma factors"
This creates a git repo, writes PROMPT.md (what to optimize), installs CLAUDE.md (the agent protocol), and spawns a Claude Code session in tmux.
PROMPT.md — describes the research question, target metric, and constraintsCLAUDE.md — the autonomous agent protocol (run tracking, commit discipline, insight saving).distillate/runs.jsonl — structured log of every run with metrics, hyperparameters, and reasoning.distillate/llm_enrichment.json — research insights (key breakthrough, lessons learned, dead ends)RESULTS.md — human-readable summary updated after each runEach experiment repo has a .mcp.json that connects the agent to Distillate's tool server. The agent uses these tools to track runs and save insights:
start_run Announce a new run with description and hypothesis
conclude_run Record results with duration tracking
save_enrichment Save structured research insights
scan_project Sync run state with the desktop app
annotate_run Add notes or hypotheses to a specific run
Every processed paper gets an engagement score from 0 to 100, measuring how deeply you interacted with it. The score appears in your notes (YAML frontmatter), --status output, --digest, and email digests.
Three components, weighted:
Each component is normalized to 0.0–1.0, then the weighted sum is scaled to 0–100:
score = round((density * 0.3 + coverage * 0.4 + volume * 0.3) * 100)
A paper you skimmed lightly might score 15–25. A paper you highlighted thoroughly across most pages will score 70+. The score is a quick signal for which papers you actually engaged with versus those you just scanned.
Use --reprocess to re-extract highlights and regenerate notes for a paper that's already been processed. Common reasons:
# Substring match on the paper title
$ distillate --reprocess "Attention Is All"
What it does: re-downloads the bundle from Saved/ on your reMarkable, re-extracts highlights, re-renders the annotated PDF, regenerates the AI summary, and updates both the markdown note and the reading log.
Distillate uses two model tiers, configurable via environment variables in your .env:
CLAUDE_SMART_MODEL (default: claude-sonnet-4-5-20250929) — used for paper summaries and one-liner descriptionsCLAUDE_FAST_MODEL (default: claude-haiku-4-5-20251001) — used for paper suggestions and key learnings# In your .env file:
CLAUDE_SMART_MODEL=claude-opus-4-6
CLAUDE_FAST_MODEL=claude-sonnet-4-5-20250929
Without ANTHROPIC_API_KEY set, sync pipeline AI features (summaries, suggestions) use abstracts as fallback. The Nicolas agent uses Claude Code instead — no API key needed.
The KEEP_ZOTERO_PDF setting controls whether the original PDF stays in Zotero cloud after being uploaded to your reMarkable.
true (default) — PDF remains in your Zotero libraryfalse — PDF is deleted from Zotero cloud after it's confirmed saved locally and uploaded to reMarkable# In your .env file:
KEEP_ZOTERO_PDF=false
This is useful if you're on Zotero's free tier (300 MB storage). The safety order is: the PDF is first saved to your local Distillate/Inbox/ folder, then uploaded to reMarkable. Only after both succeed is the Zotero cloud copy removed. Your local copy is always preserved.
Set LOG_LEVEL=DEBUG for verbose output:
# One-off
$ LOG_LEVEL=DEBUG distillate
# Persistent (add to .env)
LOG_LEVEL=DEBUG
Behavior depends on how distillate is running:
~/.config/distillate/distillate.logDebug output includes: rmapi commands and responses, API call details, file read/write operations, and state changes. Useful for diagnosing issues like "why didn't my paper sync?" or "why are highlights missing?"
Distillate tracks all your papers and experiments in a local state.json file. The --sync-state command syncs it with Supabase cloud — keeping the same reading state across your laptop and desktop, and enabling cloud email features.
# Sync state with the cloud
$ distillate --sync-state
Requires email registration in the desktop app (Control Panel → Updates). State sync uses the same Supabase account.
If state.json becomes corrupted (malformed JSON), distillate automatically backs it up as state.json.bak and starts with a fresh state. No data is silently lost — the backup file preserves whatever was there.
state.json is plain JSON. You can read it directly, pipe it through jq, or edit it if you know what you're doing:
# Pretty-print your state
$ cat state.json | jq .
# Count processed papers
$ cat state.json | jq '.documents | length'
When you process a paper, Distillate writes your reMarkable highlights back to Zotero as native annotation items. These are visible in Zotero's built-in PDF reader on desktop and mobile.
.rm filesitemType: "annotation"All Distillate-created annotations are tagged distillate. On re-sync, existing Distillate annotations are replaced (your manual annotations are never touched).
# In your .env file (default: true)
SYNC_HIGHLIGHTS=true
Set to false to disable highlight back-propagation entirely.
If you processed papers before v0.2.0, you can back-propagate their highlights retroactively:
# Back-propagate highlights for all processed papers
$ distillate --backfill-highlights
# Or just the last 5
$ distillate --backfill-highlights 5
Papers that already have synced highlights are skipped. To force a re-sync, use --reprocess instead.
When a paper is added, Distillate queries Semantic Scholar to fill gaps in the Zotero metadata. This happens automatically during sync and can also be triggered manually.
liu_embeddings → liu_embeddings_2024)Zotero is always the source of truth: S2 only fills empty fields, never overwrites existing data.
Use --refresh-metadata to re-fetch metadata from both Zotero and Semantic Scholar for all tracked papers:
$ distillate --refresh-metadata
This is useful after editing papers in Zotero (adding dates, fixing titles) or as a one-time migration to enrich older papers with S2 data. Shows progress and only reports papers that changed.
Notes and annotated PDFs are named using citekeys — short identifiers like einstein_relativity_1905 instead of full paper titles. This makes filenames predictable and compatible with Obsidian plugins that use citekeys.
If you use Better BibTeX for Zotero, Distillate reads the citekey from the item's extra field (where Better BibTeX stores it as Citation Key: AuthorYear).
Without Better BibTeX, Distillate generates a citekey from the first author's surname, the first meaningful word of the title, and the year. Accented characters are normalized (e.g. Lála → Lala, Müller → Muller):
# "Attention Is All You Need" by Vaswani et al., 2017
→ vaswani_attention_2017
# "Biology needs to become prospective" by Avasthi, 2026
→ avasthi_biology_2026
When a paper's citekey changes — because you edited the date in Zotero, or Semantic Scholar filled a missing year — Distillate renames everything automatically:
Distillate/Saved/ and Distillate/Inbox/citekey, pdf)Distillate is designed to complement — not replace — existing Obsidian plugins for academic workflows.
The Obsidian Zotero Integration plugin creates notes from Zotero items. If a note with the same citekey already exists when Distillate processes a paper:
<!-- distillate:start --> and <!-- distillate:end --> markersThis means both tools can write to the same note without conflicts.
PDF++ provides enhanced PDF viewing in Obsidian. Distillate's annotated PDFs are stored alongside notes in Distillate/Saved/ with citekey filenames, making them easy to reference from PDF++ links.
Distillate generates a Papers.base file for Obsidian Bases (available in Obsidian 1.9+), providing a native table view of all your papers with columns for title, dates, engagement score, and highlight counts. The existing Dataview template is also still generated for users on older Obsidian versions.
Built with love and coffee by Romain Lacombe.