Vibe Researching with Coding Agents
How to Use This Handbook
This handbook is the participant companion for the two-hour workshop Vibe Researching with Coding Agents. It is not a transcript of the talk. It is a hands-on tutorial you can work through at your own pace, on your own machine, beginning from “Claude is not yet installed” and ending with a complete, verified, journal-ready paper draft built on real CFPS data.
You will see five things repeated on almost every page:
- Goal — what you should be able to do by the end of the section.
- What you type — exact commands, prompts, or code, formatted as fenced code blocks. If a line begins with
$, type it in your terminal (without the$). If it begins with>, type it inside a running Claude Code session. - What you should see — abridged but real terminal output, so you know whether you are on track.
- Inspect — the artifacts you should open and read after the agent finishes.
- Stop and check — the question you should be able to answer before moving on.
The running example is a real one: a Social Forces-style paper on the Chinese digital divide, built from six waves of the China Family Panel Studies (CFPS, 2010–2020) using only Claude Code, Codex CLI, and the open-scholar-skill suite. Every command, every figure, every table, every verification finding shown in this handbook came from an actual run — including the seven critical errors that verification caught before the manuscript was sent anywhere. Those errors are the reason this workshop exists.
The handbook has four parts.
- Part I — Foundations (the first hour of the workshop): install the agents, open your first session, learn the project layout, write an agent-quality prompt, and tour the newer Claude Code capabilities — dynamic workflows, subagents, and automation (§5A).
- Part II — Open Scholar Skills, end to end (the second hour): a reference to all 44 skills — every mode, every argument, every gate, every file they write — organized in the order you would actually use them, with the CFPS digital divide as the concrete artifact at each step. §5B is the inventory table; read it first and come back to it.
- Part III — Orchestrators: when a single paper deserves the full pipeline (
scholar-full-paper,scholar-auto-research), how to find your place again (scholar-resume), how to run a queue of ideas unattended (scholar-loop), how to audit the suite itself (scholar-auto-improve), and how to get an independent second opinion from a different vendor’s model (scholar-openai). - Part IV — Responsible practice: the take-home checklist, common participant mistakes, and the five principles.
If you already use Claude or Codex, skim Part I and start at §5B (the skill inventory) or §6 (scholar-init). If you are completely new, do every step.
Using Part II as a reference. Each skill section follows the same shape: the argument-hint grammar copied verbatim from the skill’s own frontmatter, a table of every mode, the internal workflow, the exact files written, the gates that can stop you, and the documented gotchas. Where a rule exists because a real run failed, the failure is named and dated — those are the passages worth reading even if you never run that skill.
PART I — FOUNDATIONS
1. What “Vibe Researching” Is — and Is Not
“The moment an AI touches your files, we are no longer in the world of casual prompting. We are in the world of workflow design.”
Vibe Researching is the practice of using a coding agent (Claude Code or Codex CLI) to do bounded research tasks inside a real project, leaving inspectable artifacts behind, while a human keeps ownership of the question, the standards, and the accountability.
Vibe Researching is NOT:
- “Write me a paper on X.” (Asking the agent to invent the question, the data, and the framing all at once — guaranteed to produce a polished but hollow draft.)
- “Find me a significant result.” (Outsourcing both the hypothesis and the standard for evidence — this is p-hacking with extra steps.)
- “Just trust the output because it sounds smart.” (Polished prose is not validated prose.)
Vibe Researching IS:
- “Here is my data boundary, here is the research puzzle, here is what counts as evidence, here are the artifacts you must produce, here is when you must stop and ask me.” (You define scope, standard, and stop rules; the agent executes.)
The agent has three kinds of power
| Power | What it means | Why it matters |
|---|---|---|
| Files | The agent can read and write any file you point it at | Same reason it is useful and same reason it is dangerous |
| Tools | It can run R, Python, shell, git, even web search | A small typo in a prompt can run rm |
| State | It can keep logs, resume across sessions, write project memory | If you don’t build inspectable state, mistakes hide |
Treat permissions as method, not bureaucracy. The agent’s read boundary is your data boundary. Its network boundary is your privacy boundary. Its write boundary is your reproducibility boundary.
Claude vs. Codex — division of labor
In this handbook we use two agents on purpose, because we don’t want one model acting as author, analyst, and reviewer.
- Claude Code — the orchestrator. Strong at running multi-step skills, drafting prose, planning, project memory. We use it as the primary research workflow engine.
- Codex CLI — the external reviewer. Strong at code patches, statistical implementation, independent audit. We use it (later) as a second pair of eyes on the same scripts and tables Claude produced.
You do not have to use both on day one. Start with Claude.
2. Installing Claude Code and Codex
Goal: get to the point where typing claude or codex in your terminal launches a working agent.
2.1 Prerequisites
You need:
- macOS, Linux, or Windows (WSL2).
- Node.js ≥ 18 (we recommend 20 LTS) for Claude Code.
- A terminal (Terminal.app, iTerm2, or Windows Terminal).
- An Anthropic API key for Claude (or a Claude Pro/Max subscription) and an OpenAI API key for Codex.
- Optional: R 4.3+ and Python 3.11+, since most scholar-skills run analyses in those.
The lab notebooks find a key differently from Claude Code, and this trips people up. Claude Code and Codex each authenticate themselves. The four lab notebooks do not use either of those logins — they resolve a provider in this order, first one that works:
Provider How it is found 1 OpenAI (the workshop default) OPENAI_API_KEY, else a one-linelabs/openai.txt2 Local Ollama a server on 127.0.0.1:11434— free, private, no key3 Anthropic ANTHROPIC_API_KEY4 GLM / Z.ai ZAI_API_KEY5 offline canned [OFFLINE FALLBACK]answers, so every cell still runsSo the usual fix for “The api_key client option must be set” in a notebook is one line, from the repository root:
printf '%s' 'PASTE_YOUR_KEY_HERE' > labs/openai.txt chmod 600 labs/openai.txt
labs/openai.txtis gitignored and must stay that way. If you would rather spend nothing, runollama serveinstead and the notebooks will use it with no key at all. The full walkthrough is in the pre-workshop setup guide (teaching/03-pre-workshop-setup.md).
Windows users: The commands in this section assume macOS, Linux, or a Linux-like shell. If you are on Windows, do not try to run them in PowerShell or
cmd.exe. Go to Appendix K — Windows setup walkthrough first and follow it through WSL2 (Windows Subsystem for Linux). Once you have a working Ubuntu shell inside WSL2, every command in §2 and §3 works unchanged. You only need to read Appendix K once per laptop.
Check your Node version:
$ node --version
v20.11.0
If node is missing or older than 18, install nvm and run nvm install 20.
Prefer not to install anything by hand? Once Claude Code or Codex is running (even with only Node installed), you can ask the agent to install Python, R, Git, and the standard social-science packages for you. See §2.7 — “Let the agent install your research toolchain” — for the exact prompts.
2.1A Accounts, plans, and keys — the three things people confuse
There are two different ways to pay, and they are not interchangeable. This trips up almost everyone, so read the last row twice.
| A subscription | An API key | |
|---|---|---|
| What it is | A monthly plan tied to your login | A secret string tied to usage, billed per token |
| Claude | Claude Pro or Claude Max at claude.ai | console.anthropic.com → API Keys |
| OpenAI | ChatGPT Plus / Pro / Business at chatgpt.com | platform.openai.com → API keys |
| Runs Claude Code? | ✅ sign in with your account | ✅ paste the key |
| Runs Codex CLI? | ✅ sign in with your account | ✅ paste the key |
| Runs the lab notebooks? | ❌ no | ✅ yes |
The last row is the one that costs people an hour. A ChatGPT Plus subscription does not give you an API key, and a Claude Pro subscription does not give the lab notebooks anything to use. Subscriptions authenticate you to an app; the notebooks are your own Python calling an API, and that needs a key (or a local model — see §2.1).
Getting a Claude plan (for Claude Code). Go to claude.ai, sign up, then Settings → Plans. Pro is the entry tier; Max raises the usage limits, which matters on Day 3 when everyone runs agents at once. Then run claude and choose Login with Anthropic Console — no key needed.
Getting an Anthropic API key (the alternative). Go to console.anthropic.com → API Keys → Create Key, copy it immediately (it is shown once), and add credit under Billing — a new console has a zero balance and calls will fail with a billing error until you do. Current per-token rates are on the pricing page; as of August 2026 Claude Opus 5 is $5 / $25 per million input / output tokens and Claude Haiku 4.5 is $1 / $5.
Getting Codex working. Either sign in with a ChatGPT Plus/Pro account (codex login, then pick the browser sign-in), or create an OpenAI key at platform.openai.com/api-keys and paste it. OpenAI billing is separate from ChatGPT billing — the same warning about a zero balance applies.
What this workshop actually needs. Claude Code, by either route. Codex, by either route, and only on Day 4 for external review. The lab notebooks need an OpenAI API key in labs/openai.txt — or nothing at all if you run ollama serve, which is free and local and is what we recommend if you would rather not spend anything.
Cost, honestly. Four days of lab work on the default
gpt-4o-miniis well under a dollar. The expensive thing is agents on Day 3–4, which is what a Max plan or a funded console is for. If you are paying out of pocket, run the labs on Ollama and spend your budget on the agent days.
2.2 Installing Claude Code
$ npm install -g @anthropic-ai/claude-code
Confirm:
$ claude --version
2.0.x
The first time you launch it, it will walk you through authentication:
$ cd ~/Documents/projects/digital-divide-china-cfps # cd into your project FIRST
$ claude
You will see a welcome screen asking how you want to authenticate. Choose API key (paste from console.anthropic.com) or Anthropic Console (browser flow).
┌──────────────────────────────────────────────────────┐
│ Welcome to Claude Code │
│ Choose authentication method: │
│ 1) Login with Anthropic Console │
│ 2) Use ANTHROPIC_API_KEY │
└──────────────────────────────────────────────────────┘
Always start Claude Code from inside the project directory. That directory becomes the working root, and Claude will only read/write inside it (subject to permissions).
2.3 Installing Codex CLI
Codex is OpenAI’s coding agent. We use it for external code review.
$ npm install -g @openai/codex
$ codex --version
codex-cli 0.130.0 # exact version as of 2026-05; yours may be newer
Authenticate once:
$ codex login
# Paste your OpenAI API key when prompted.
2.3A Desktop apps — a friendlier alternative to the CLI
Both vendors now ship a desktop application that bundles the same coding agent behind a window-based interface, so you can try the tools without ever touching npm or a terminal. If the CLI install above stalled — missing Node, PATH headaches, a locked-down work laptop — the desktop app is the fastest way to get a working agent in front of you.
Goal: have a working Claude Code or Codex agent running, by whichever path is least painful for your machine.
Claude Code desktop (macOS / Windows). Download the installer from the official page:
The desktop app includes Claude Code — you do not need to install Node.js or the CLI separately. Install it like any normal app (drag to Applications on macOS; run the .exe on Windows), launch it, and sign in with your Anthropic account (Pro/Max subscription or Console login). macOS 11 (Big Sur) or newer is required. The first-run walkthrough lives at https://code.claude.com/docs/en/desktop-quickstart.
Codex app (macOS / Windows). Download from OpenAI’s official page:
Pick the macOS build (Apple Silicon or Intel) or the Windows build; Windows users can also install it from the Microsoft Store. Open it and sign in with your ChatGPT account (Plus / Pro / Business / Edu / Enterprise — Codex is included) or an OpenAI API key. The app runs Codex threads in parallel and has built-in worktree, automation, and Git support.
What you should see: a window-based agent that can open a folder, read and edit files, run commands, and talk to git — the same capabilities as the CLI, with buttons instead of keystrokes.
A third desktop agent — ZCode (Z.ai). If neither vendor’s billing works for you, Z.ai ships ZCode, a desktop agent built on GLM-5.2 that reads Claude Code’s skills and can therefore run the open-scholar-skill suite. It is a different company’s product with its own configuration and its own data-jurisdiction implications, so it gets its own treatment: see §2.6.7.
Let the desktop install the CLI for you. You do not have to run the npm commands from §2.2 by hand. Once the desktop app is open, ask it in plain English — “Install the Claude Code CLI on my machine and walk me through signing in” — and the agent will check your Node version, run the installer, fix your PATH, and hand you a working claude command. It is the same agent that later sets up your whole research toolchain (§2.7); here it simply sets up its own terminal home.
…but for this workshop, please also install and use the CLI. The desktop apps are excellent for first contact and for day-to-day work, and you are welcome to keep using them afterward. The reason to spend ten minutes at the terminal too is not that the desktop is weak — by now it reads your files, runs code, remembers across a session, and connects to MCP servers, exactly like the CLI. The reason is a handful of things a graphical app structurally cannot do. A desktop needs a screen and a human clicking; the CLI is just text in, text out, so it runs anywhere a shell does:
- Headless & remote. The CLI runs over SSH on a lab server or an HPC cluster with no screen attached. When restricted data cannot leave a secure machine, you bring the agent to the data — impossible from a windowed app that needs a graphical desktop session.
- Scriptable.
claude -p "…"drops into a shell script, aMakefile, or a cron job, so the agent becomes one automated step in a pipeline rather than a person clicking buttons. - Unattended at scale. Long or parallel jobs launched under
tmux/nohupoutlive your session — two hundred model calls overnight with the laptop shut. - Composes with Unix. Its input and output pipe and redirect straight into
git,grep,R, andawk— it drops into the research-computing stack you already run. - Text-reproducible. Every action is a command you can log, version, and rerun, so a colleague reproduces your exact workflow; a GUI click leaves no trace.
Two workshop-specific reasons reinforce this: everything you learn on the CLI transfers straight back to the desktop app (the reverse is not always true), and the materials assume the terminal — the plugin install (§2.4) runs a shell setup.sh, and hooks (§5A), .claude/settings.json, and MCP wiring are all demonstrated as copy-pasteable commands.
So: if the desktop app is how you get unstuck today, great — use it, or let it install the CLI for you. But do get claude (and ideally codex) working in a terminal too, because §2.4 onward assumes you can type commands at a $ prompt and > inside a session.
2.4 Installing the open-scholar-skill plugin
Skills are not built into Claude Code; you install them by cloning the repository and running its setup script. The repo at https://github.com/joshzyj/open-scholar-skill ships a .claude-plugin/ manifest plus a setup.sh that registers the skills, the agents, and the PreToolUse data-safety hook with Claude Code.
There are two ways to do this. If git, SSH keys, and shell scripts are new to you, use the beginner shortcut (§2.4.0) — ask Claude Code itself to do the install. If you’d rather see every command, follow the manual path in §2.4.1–§2.4.5.
Or install it as a plugin. The repo also publishes a marketplace manifest, so
claude plugin marketplace add joshzyj/open-scholar-skillfollowed byclaude plugin install open-scholar-skill@open-scholargets you the skills and agents in two commands, and is the route ZCode uses (§2.6.7). It is not a substitute forsetup.sh: the plugin cannot write the three things that live outside the repo — your.envwith the Zotero and CrossRef settings, the executable bits on the skills’ shell scripts, and the PreToolUse data-safety hook in~/.claude/settings.json. For the workshop, clone and runsetup.sh; treat the plugin route as the fast path for a second machine where you will runsetup.shafterwards anyway.
Two editions — which one you have determines which skills exist.
Edition Repo Skills Access Public github.com/joshzyj/open-scholar-skill35 Open — this is what §2.4 installs Extended openscholarskills44 Available on request — email the author This handbook documents the extended edition, because that is the superset. Nine skills exist only there:
scholar-full-paper·scholar-resume·scholar-loop·scholar-presentation·scholar-image·scholar-grant·scholar-teach·scholar-book·scholar-exemplar-curateSections covering those carry an [Extended] tag. Everything else in Part II works identically on the public edition — including the entire analysis-to-verification core (
scholar-init→scholar-design→scholar-analyze→scholar-write→scholar-verify→scholar-citation), which is where the workshop’s argument actually lives. On the public edition, run those skills individually in the order of Part II; the orchestrator in §21 is a convenience over that same chain, not a different method.Check what you have at any time:
$ ls ~/.claude/skills/ | grep -c scholar # 35 public · 44 extended
2.4.0 Beginner shortcut — let Claude Code install it for you
Once Claude Code is installed (§2.2) and running in any directory, paste this prompt:
> Please install the open-scholar-skill plugin from
> https://github.com/joshzyj/open-scholar-skill
> into Claude Code on this machine. Clone it under
> ~/.claude/plugins/open-scholar-skill
> run its setup.sh, install any missing dependencies (git, jq,
> python3), then verify the install by listing the scholar-*
> commands. Stop and ask me before running anything that needs
> sudo or that writes outside ~/.claude.
Claude will read the repo’s README, run git clone, execute setup.sh, install missing tools (pausing for your permission on each one), and confirm by calling /help. Anything that fails is reported with the exact error — you read the transcript instead of memorizing the steps. End state is identical to the manual path.
Safety rules for the shortcut
- Start Claude Code in
defaultpermission mode (notbypassPermissions) so each install step still asks for your approval. TypeShift+Tabuntil the status line readsdefaultif you are not sure.- If the agent proposes
sudo, read what it intends to install before typingy. The shortcut should never needsudofor the plugin itself — only, possibly, forjq/python3on Linux.- If the agent reports it cannot reach
github.comor that a dependency install failed three times, switch to the manual path below — those failures usually need a human to debug your shell, proxy, orPATH.
When Claude finishes, jump to §2.4.4 to confirm the install, then move on to §3.
2.4.1 Prerequisite — git
The install uses git. Confirm it is installed and configured:
$ git --version # any 2.x is fine
$ git config --global user.name "Your Name"
$ git config --global user.email "you@example.com"
If git is missing:
- macOS:
xcode-select --install(Apple’s git) orbrew install git - Ubuntu / Debian / WSL:
sudo apt install git
For pulling private repos later, also add an SSH key:
$ ssh-keygen -t ed25519 -C "you@example.com"
$ cat ~/.ssh/id_ed25519.pub
# Paste the public key into github.com → Settings → SSH and GPG keys.
2.4.2 Install — clone and run setup
$ git clone https://github.com/joshzyj/open-scholar-skill.git
$ cd open-scholar-skill
$ bash setup.sh
setup.sh will:
- Create the
.claude/skills/and.claude/agents/symlinks the plugin uses internally. - Auto-detect your Zotero library, or prompt you for the path if it cannot find one.
- Optionally configure BibTeX, EndNote, and a CrossRef email for the polite API pool.
- Install every skill in your edition (35 public · 44 extended) and its agents as personal skills in
~/.claude/skills/and~/.claude/agents/— so/scholar-*works in every Claude Code session, in any directory, not just the cloned repo. - Register
scripts/gates/pretooluse-data-guard.shas a PreToolUse hook in~/.claude/settings.json. The hook intercepts everyRead,NotebookRead,NotebookEdit,Grep, andGlobcall and refuses files whose.claude/safety-status.jsonentry isNEEDS_REVIEW:*orHALTED. - Write a
.envfile recording your configuration.
Requirements: bash, python3, jq. Install jq first — the data-safety hook fails closed without it, which means every data read gets blocked until you do. Presidio, used for NER-based PII detection, is optional: python3 -m pip install presidio-analyzer presidio-anonymizer.
If setup.sh reports a missing dependency, install it (brew install jq on macOS; sudo apt install jq python3 on Linux) and re-run.
Step 2 is the one people skip, and it silently degrades half the suite. The reference library detected here is what
scholar-writedrafts against, whatscholar-citationverifies against at Tier 1, whatscholar-lit-reviewsearches before it touches the web, and whatscholar-exemplar-curateharvests paragraph exemplars from. Get it wrong and nothing errors — you just get web-only citations and generic prose. §14.0 shows how to verify it took.
2.4.3 Update later
$ cd open-scholar-skill
$ git pull
$ bash setup.sh # idempotent — refreshes symlinks and hook registration
2.4.4 Verify
Start Claude Code from any project directory and type:
> /help
You should see a long list of scholar-* commands. Quick check:
> /scholar-init --help
If it prints a help summary, you are ready for §3.
2.4.5 Troubleshooting
- Skills missing from
/help— symlinks didn’t install. From the cloned repo, runbash setup.shagain and watch for the▸ Checking symlinks...block. - PreToolUse hook blocks an unexpected file — that is the data-safety guard working. Resolve it with
/scholar-init review(thereviewmode is owned byscholar-init, notscholar-safety). Do not disable the hook. Behind a corporate proxy — clone via HTTPS with an explicit token:
$ git clone https://<token>@github.com/joshzyj/open-scholar-skill.gitOr download the repo as a ZIP and extract it before running
setup.sh.
2.5 What setup.sh actually does — a walk-through
Goal: know what to expect before you run it, what each of the seven prompts is asking, and how to tell afterwards whether it worked.
setup.sh is interactive. It asks six or seven questions, and every one of them can be skipped by pressing Enter. It is also idempotent — re-running it is safe and is the documented way to repair a broken install. Budget three minutes.
One design note that explains a lot of its behaviour: the script deliberately does not use set -e. Its own header says why — the interactive read prompts return non-zero on EOF (piping /dev/null, or running it in CI), and under set -e that would abort the install halfway through. Instead each step checks its own exit status and continues best-effort. The consequence for you: a warning mid-run does not mean the install failed, and you have to read the summary at the end rather than assuming silence is success.
2.5.1 The seven steps, in order
1 — Symlinks. ▸ Checking symlinks... creates two repo-local conveniences, skills/ → .claude/skills/ and agents/ → .claude/agents/. If one exists but points somewhere unexpected it is repaired; if a real directory sits at that name, the script refuses to delete it and tells you to move it yourself. It will not destroy your files to make room.
2 — Zotero auto-detection. ▸ Looking for Zotero library... probes seven locations, in order, for a zotero.sqlite (or .sqlite.bak):
~/Zotero ~/Library/CloudStorage/*/zotero
~/Documents/Zotero ~/Library/CloudStorage/*/Zotero
~/snap/zotero-snap/common/Zotero ~/Google Drive/zotero
~/Google Drive/Zotero
Then it asks:
Auto-detected Zotero at: /Users/you/Zotero
Use this path? [Y/n] or enter a different path:
Three valid answers: Enter or Y accepts, n skips Zotero entirely, or you paste a different path. If you paste a path that does not exist, it warns and keeps the auto-detected one rather than silently accepting a broken path. If nothing was found at all, it asks you to type a path and skips on empty input.
3 — Optional reference managers. Four prompts in a row, each skippable with Enter:
| Prompt | Sets | Notes |
|---|---|---|
Path to a .bib file | SCHOLAR_BIB_PATH | Must exist, or it warns and skips |
| Path to an EndNote XML export | SCHOLAR_ENDNOTE_XML | Must exist |
| CrossRef/OpenAlex polite pool email | SCHOLAR_CROSSREF_EMAIL | Not validated — it is just an email for API etiquette |
| HuggingFace access token | HF_TOKEN | For SciThinker and gated models |
4 — Knowledge graph directory. Defaults to ~/.claude/scholar-knowledge; press Enter to accept. This is the user-scoped, cross-project graph from §8C — one graph for all your papers, deliberately not inside any project.
5 — jq check, then Presidio. ▸ Checking jq... is the step to actually read:
⚠ jq is NOT installed.
... the guard falls back to a minimal sed-based parser and fails CLOSED
on data files — every Read of a .csv/.dta/.xlsx will be blocked
with "install jq" until jq is available.
That is not a soft warning. Without jq the data guard blocks every data read. Install it and re-run.
Presidio is then offered for NER-based PII detection (names, addresses, entities) on top of the built-in regex patterns. It needs roughly 500 MB and defaults to no. If you accept, the script installs presidio-analyzer, presidio-anonymizer, and spaCy’s en_core_web_lg, then smoke-tests that presidio_anonymizer actually imports — because a successful pip install is not proof the package works on that interpreter. Declining is fine; regex detection is used instead, and you can install it later.
6 — The .env file. Before writing, an existing .env is copied to .env.bak.<timestamp> and you are told to re-apply any manual additions. The script never silently clobbers a file you may have hand-edited. The result:
SCHOLAR_SKILL_DIR="/path/to/open-scholar-skills"
SCHOLAR_ZOTERO_DIR="/Users/you/Zotero"
SCHOLAR_BIB_PATH=""
SCHOLAR_ENDNOTE_XML=""
SCHOLAR_CROSSREF_EMAIL="you@university.edu"
HF_TOKEN=""
SCHOLAR_KNOWLEDGE_DIR="/Users/you/.claude/scholar-knowledge"
7 — Installing as personal skills. This is what makes /scholar-* work in every directory. It creates one symlink per skill and per agent inside ~/.claude/skills/ and ~/.claude/agents/ — rather than replacing those directories with a single link to the repo. Three consequences, all good:
- A skill of your own already at
~/.claude/skills/my-thing/is untouched; thescholar-*entries install alongside it. - If a real (non-symlink) directory already occupies a
scholar-*name, the script skips it and says so rather than deleting your content. - Uninstalling is just deleting the
scholar-*symlinks.
Then three smaller steps run without asking anything:
chmod +xrepair. Helper scripts that lost their executable bit — which happens on cloud-sync mounts and ZIP downloads, though not on a freshgit clone— get it restored. Only files starting with a#!shebang are touched; sourced helpers are deliberately left non-executable.- The PreToolUse hook.
scripts/gates/pretooluse-data-guard.shis merged into~/.claude/settings.jsonwithjq— additively and idempotently, preserving every other key you have configured, and replacing rather than duplicating an existing scholar entry. The command is written quoted, which is what makes it survive a path containing spaces (§6.4). - Bootstrap files.
~/.claude/scholar-skills.path(a one-line absolute path,chmod 600) and a copy ofscholar-skill-bootstrap.sh, so skills can find the repo from any working directory even withSCHOLAR_SKILL_DIRunset.
Finally it offers to append export SCHOLAR_SKILL_DIR="..." to your ~/.zshrc (or ~/.bashrc / ~/.bash_profile), detecting your shell. Accept unless you manage your profile some other way.
2.5.2 Reading the summary — the one line that matters
═══════════════════════════════════════════════════
Setup Complete
═══════════════════════════════════════════════════
SCHOLAR_SKILL_DIR=/path/to/open-scholar-skills
Zotero: /Users/you/Zotero
Next steps:
1. Source your shell profile or open a new terminal
2. Try from any project: /scholar-idea "your research question"
If the safety hook could not be installed, the banner says so instead — and the script exits non-zero:
Setup Complete (WARNING: safety hook NOT installed)
The PreToolUse data-safety hook could not be installed.
Raw data files will NOT be automatically guarded.
That exit code is the machine-readable signal. If you script the install, check it:
$ bash setup.sh || echo "SAFETY HOOK MISSING — install jq and re-run"
2.5.3 Verify it took
$ ls ~/.claude/skills/ | grep -c scholar # 44
$ ls ~/.claude/agents/ | wc -l # 22
$ cat ~/.claude/scholar-skills.path # the repo path
$ jq '.hooks.PreToolUse' ~/.claude/settings.json | head # the guard
$ cat "$SCHOLAR_SKILL_DIR/.env" # your configuration
Then, in a new terminal (so the profile export is live), from a directory that is not the repo:
> /scholar-idea does hukou status shape internet use in urban China?
If the skill runs from an unrelated directory, the personal-skills install worked. If /help does not list the scholar skills, re-run bash setup.sh and watch the ▸ Checking symlinks... block for errors (§2.4.5).
Stop and check. Open ~/.claude/settings.json and find the PreToolUse entry. Is the script path wrapped in quotes? If your install lives under a path with a space in it — My Drive, Application Support — an unquoted command silently never fires, and you would have no guard at all while believing you did.
2.6 Running the workflow on GLM, DeepSeek, or a local model — including Z.ai’s ZCode
Goal: keep using the same Claude Code CLI, the same open-scholar-skill plugin, and the same project layout, but route the model calls to a different backend — Z.ai/GLM, DeepSeek, or a model you run on your own machine.
You do not need to install another CLI, swap your scripts, or hand-edit JSON before every session. Claude Code reads two environment variables — ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN — and will talk to any provider that exposes an Anthropic-compatible endpoint. GLM (Z.ai and the mainland BigModel host) and DeepSeek both do. For genuinely local models (DeepSeek-R1 distilled, Qwen2.5-Coder, Llama, GLM), Claude Code still needs an Anthropic-compatible front: Ollama, vLLM, and llama.cpp all speak OpenAI-style APIs, so you put a small translation layer — claude-code-router or litellm — in front to re-shape their responses into the Anthropic schema; the rest of the workflow is identical.
Options A–C below all keep Claude Code and swap the model underneath it. §2.6.7 covers the other direction: ZCode, Z.ai’s own agent app built around GLM-5.2, which replaces the harness and the model — and which reads Claude Code’s skills, so the open-scholar-skill suite runs inside it too.
2.6.1 Provider snapshot
| Provider | Endpoint host | Models to set |
|---|---|---|
| GLM / Z.ai (international) | api.z.ai | Opus and Sonnet → glm-5.2; Haiku → glm-4.7. Also set API_TIMEOUT_MS=3000000. |
| GLM mainland China | open.bigmodel.cn | Same idea; pick the GLM family your BigModel account has access to. |
| DeepSeek | api.deepseek.com | Opus / Sonnet → deepseek-v4-pro; Haiku and subagents → deepseek-v4-flash. |
| Local — Ollama (via CCR/proxy) | CCR → http://localhost:11434/v1/chat/completions | Any tag you pulled (e.g. qwen2.5-coder:32b); needs a translation layer. See §2.6.5. |
| Local — vLLM / llama.cpp (via proxy) | proxy address you start | Whatever you exposed; see §2.6.5. |
The full ANTHROPIC_BASE_URL for Z.ai is https://api.z.ai/api/anthropic; for BigModel it is https://open.bigmodel.cn/api/anthropic; for DeepSeek it is https://api.deepseek.com/anthropic. The trailing /anthropic segment is what makes these endpoints route to the compatibility shim — leaving it off is the most common configuration error.
Model names move fast. The model IDs in this section (glm-5.2, glm-4.7, deepseek-v4-pro, and the rest) are illustrative. Before a session, check the provider’s current model list — Z.ai/BigModel and DeepSeek each publish their own — and use the exact names your account can call; pasting a retired tag is the second most common error after dropping the /anthropic suffix. GLM in particular has moved fast: glm-5.1 was the flagship when the first edition of this handbook was written and glm-5.2 replaced it in June 2026, bringing a 1M-token context window. If you copied the old three-line block into settings.json, update it.
2.6.2 Option A — declare a backend in ~/.claude/settings.json
This is the simplest setup: you point Claude Code at one backend, save the file, and every new session uses it until you change it.
GLM example:
{
"env": {
"ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
"ANTHROPIC_AUTH_TOKEN": "your_zai_key",
"ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-5.2",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-5.2",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "glm-4.7",
"CLAUDE_CODE_AUTO_COMPACT_WINDOW": "1000000",
"API_TIMEOUT_MS": "3000000"
}
}
This is Z.ai’s own recommended mapping: GLM-5.2 for both the Opus and the Sonnet tier, the cheaper glm-4.7 for the Haiku tier that Claude Code uses for small background calls. CLAUDE_CODE_AUTO_COMPACT_WINDOW tells Claude Code it may fill GLM-5.2’s 1M-token window before auto-compacting — leave it out and you compact far earlier than you need to, which matters when the agent is holding a codebook and three scripts at once.
DeepSeek example:
{
"env": {
"ANTHROPIC_BASE_URL": "https://api.deepseek.com/anthropic",
"ANTHROPIC_AUTH_TOKEN": "your_deepseek_key",
"ANTHROPIC_DEFAULT_OPUS_MODEL": "deepseek-v4-pro",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "deepseek-v4-pro",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "deepseek-v4-flash"
}
}
Restart Claude Code; run /usage or just trigger any tool call to confirm the backend has switched.
2.6.3 Option B — keep keys outside the project and switch with shell functions
Hand-editing settings.json before every workshop is painful and tends to leak keys into git. Instead, keep all your provider keys in ~/.api-keys (chmod 600), source it from ~/.zshrc or ~/.bashrc, and define small shell functions that export the right environment and then launch claude:
# ~/.api-keys (NOT committed anywhere)
export ANTHROPIC_API_KEY="sk-ant-..."
export ZAI_API_KEY="..."
export DEEPSEEK_API_KEY="..."
# ~/.zshrc
[ -f ~/.api-keys ] && source ~/.api-keys
glm() {
export ANTHROPIC_BASE_URL="https://api.z.ai/api/anthropic"
export ANTHROPIC_AUTH_TOKEN="$ZAI_API_KEY"
export ANTHROPIC_DEFAULT_SONNET_MODEL="glm-5.2"
export ANTHROPIC_DEFAULT_OPUS_MODEL="glm-5.2"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="glm-4.7"
export CLAUDE_CODE_AUTO_COMPACT_WINDOW=1000000
export API_TIMEOUT_MS=3000000
claude "$@"
}
deepseek() {
export ANTHROPIC_BASE_URL="https://api.deepseek.com/anthropic"
export ANTHROPIC_AUTH_TOKEN="$DEEPSEEK_API_KEY"
export ANTHROPIC_DEFAULT_SONNET_MODEL="deepseek-v4-pro"
export ANTHROPIC_DEFAULT_OPUS_MODEL="deepseek-v4-pro"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="deepseek-v4-flash"
claude "$@"
}
claude-anthropic() {
unset ANTHROPIC_BASE_URL ANTHROPIC_AUTH_TOKEN
unset ANTHROPIC_DEFAULT_SONNET_MODEL
unset ANTHROPIC_DEFAULT_OPUS_MODEL
unset ANTHROPIC_DEFAULT_HAIKU_MODEL
unset CLAUDE_CODE_AUTO_COMPACT_WINDOW API_TIMEOUT_MS
claude "$@"
}
From then on, glm opens Claude Code against Z.ai, deepseek opens it against DeepSeek, and claude-anthropic falls back to vanilla Anthropic. The PATH binary claude itself is still the one CLI you trust.
2.6.4 Option C — CC Switch, a one-click GUI for provider switching
Options A and B edit configuration by hand. If you juggle several providers or accounts — an Anthropic login for one project, GLM and DeepSeek for others, a Kimi key for a collaborator’s repo — a GUI that makes those same edits for you is less error-prone. CC Switch is a cross-platform desktop app that manages provider configurations for Claude Code (and Codex, Gemini CLI, Claude Desktop, and more) from one window, with 50+ built-in provider presets and a system-tray menu for instant switching. It is an open-source, third-party tool — not an Anthropic product.
Install.
# macOS (Homebrew) — signed and notarized
brew install --cask cc-switch
# Linux (Arch)
paru -S cc-switch-bin
On Windows, download the .msi installer (Windows 10+); on other Linux distributions, the .deb, .rpm, or universal .AppImage. All builds are on the official releases page:
- Website: https://ccswitch.io
- Downloads: https://github.com/farion1231/cc-switch/releases
How it works. CC Switch keeps your provider definitions in a local SQLite database at ~/.cc-switch/cc-switch.db and, when you switch, writes the matching values into the live tool config — the same ~/.claude/settings.json env keys you set by hand in Option A — using atomic writes with rotating backups in ~/.cc-switch/backups/. Claude Code supports hot-switching without a restart; for the other CLIs you restart the terminal after switching.
Add and switch, in four steps.
- Add Provider → choose a preset (Anthropic official, GLM/Z.ai, DeepSeek, Kimi/Moonshot, …) or enter a custom base URL + key.
- Select the provider and click Enable — or pick it from the tray menu for an instant switch.
- Restart the terminal (not needed for Claude Code) and run any tool call or
/usageto confirm the backend changed. - To return to your Anthropic login, enable the “Official Login” preset, restart, and sign in normally.
Two cautions — the workshop’s data-boundary rules still apply.
- It stores your API keys unencrypted in
~/.cc-switch/cc-switch.db. Treat that file like any credential store: not on a shared lab machine, not in a synced or backed-up folder you don’t control, never in git. On a borrowed computer, prefer Option B (keys in~/.api-keys,chmod 600) or clean up afterwards. - Many presets are community relays, not the vendor’s own endpoint. A relay sees every prompt you send it — including participant text. Before routing a project with sensitive data through any non-official backend, run the trust checks in §2.6.6, and for restricted data prefer an official channel or a provider you have vetted.
CC Switch does not replace Options A/B — it automates them behind a UI. Everything else (the plugin, CLAUDE.md, the permission gates) is unchanged.
2.6.5 Running models locally
If your institution forbids sending data to a hosted API, or you want offline reproducibility, you can run a local checkpoint and route Claude Code to it. The catch: Claude Code speaks the Anthropic Messages API, while local servers (Ollama, vLLM, llama.cpp) speak OpenAI-style chat completions, so you put a thin translation layer in between. claude-code-router (CCR) is the lightest option: it speaks OpenAI-style chat completions to providers, so all three plug in as ordinary OpenAI-compatible backends — no per-server transformer required.
Path A — Ollama, fronted by CCR (simplest local route). Ollama exposes an OpenAI-style API (/v1/chat/completions) and its own native API — not the Anthropic /v1/messages format Claude Code expects — so it needs a shim in front, exactly like vLLM and llama.cpp:
# 1. Install Ollama (macOS / Linux / WSL).
$ curl -fsSL https://ollama.com/install.sh | sh
$ ollama --version
# 2. Pull a local model that fits your VRAM / RAM. Browse
# https://ollama.com/library for current tags; these exist today:
$ ollama pull qwen2.5-coder:32b # strong local coding model
$ ollama pull deepseek-r1:14b # distilled reasoning model
# GLM checkpoints also appear in the library — search "glm" there.
# 3. Front Ollama with CCR (install it in Path B). In `ccr ui`, add an
# "ollama" provider with base URL http://localhost:11434/v1/chat/completions and your
# pulled tag, then launch and select it:
$ ccr code
# Inside the session: /model ollama,qwen2.5-coder:32b
Pointing ANTHROPIC_BASE_URL straight at http://localhost:11434 does not work: Claude Code would POST /v1/messages, which Ollama does not serve. The translation layer is what bridges the two schemas.
Path B — claude-code-router (CCR), install and routing. CCR is both the shim for a single local model (Path A) and the way to mix providers — different routes per tier (Opus to Z.ai, Sonnet to DeepSeek, Haiku to a local Ollama model), with manual mid-session switching via /model provider,model (add your own fallback logic with a custom router.js):
$ npm install -g @musistudio/claude-code-router
$ ccr ui # opens a browser config editor and creates
# ~/.claude-code-router/config.json
$ ccr start # launches the router service
$ ccr code # launches Claude Code routed through CCR
There is no ccr config init; the config file is created the first time you run ccr ui (or ccr start/ccr code) and lives at ~/.claude-code-router/config.json. Edit the default and per-tier routes there or in ccr ui, then ccr restart to apply. Inside a CCR session, /model deepseek,deepseek-v4-pro or /model ollama,qwen2.5-coder:32b switches routes mid-conversation — the provider,model form is a CCR feature, not stock Claude Code.
vLLM / llama.cpp. If you already serve models with vLLM (
vllm serve <model>) or llama.cpp (llama-server), they expose OpenAI-style chat completions, not Anthropic-style. vLLM ships its own Claude Code integration guide; otherwise putlitellm, ananthropic-proxy, or CCR in front to translate the OpenAI ↔ Anthropic schemas. The Claude Code side never changes.
2.6.6 Workshop checks before you trust a backend
Open Scholar skills are not model-agnostic. They depend on long-context reading, tool use, and JSON-structured output. Before running the CFPS pipeline on a non-Anthropic backend, run this three-step smoke test:
- Tool-use round-trip. In a sandbox project, prompt: “Read
grades.csv, run a Python snippet to compute the mean, and write the result toout.txt.” A backend that silently skips theBashcall, hallucinates the file content, or returns the answer in prose without producingout.txtwill fail every scholar-skill that depends on artifacts. - Long-prompt stability. Paste a 30-page CFPS codebook excerpt and ask the agent to extract variable names and waves. Backends with smaller effective context windows will start dropping later pages without warning.
- Skill invocation. Run
/scholar-init --slug smoke-testand/scholar-safety scan. If the model refuses to invoke the skill, returns a wrong path, or “forgets” the PreToolUse hook, do not use that backend for real data.
Record the result of each check in a one-line note in logs/backend-test.md. Do not advertise any tested model as fully compatible with the open-scholar-skill suite — say only that you ran the smoke test on a specific date and the listed skills passed.
Workshop rule. During the workshop itself, default to one backend per laptop. Switching providers mid-pipeline is the fastest way to produce two halves of a paper that disagree about CFPS variable definitions because the two models read the codebook differently.
2.6.7 Option D — ZCode, Z.ai’s own agent app, running the scholar skills
Options A–C keep the Claude Code CLI and swap the model underneath it. ZCode does something different: it is Z.ai’s own agent application, built around GLM-5.2, replacing the harness as well as the model. Z.ai calls it an Agentic Development Environment — a desktop app with a Goal mode for long multi-step tasks, browser automation, remote-development and phone-control channels. It is not an Anthropic product and it is not Claude Code; it is a separate program with its own configuration directory, ~/.zcode/.
The reason it belongs in this handbook is one design decision on Z.ai’s part: ZCode reads Claude Code’s skills, plugins, commands, and hooks. The open-scholar-skill suite you installed in §2.4 runs inside it, with GLM-5.2 doing the work. If your department cannot fund an Anthropic subscription, or you need a mainland-China billing path, this is the shortest route from “no Claude budget” to “the scholar pipeline runs on my laptop.”
Which option do you want?
| You want | Use |
|---|---|
| The exact workflow in this handbook, at GLM prices | Option A or B — Claude Code CLI on a GLM backend (§2.6.2–2.6.3) |
| A graphical agent, Goal mode, GLM-native tooling | Option D — ZCode (this section) |
| To move between them per project | Option C (CC Switch) for Claude Code, ZCode alongside it |
Parts II–IV of this handbook assume a $ prompt and /scholar-* commands. Under ZCode the skill files are the same, but invocation, project memory, and hooks all differ. Read the three “difference” blocks below before you start the CFPS run in ZCode; the third one is a safety issue.
Install. ZCode is a desktop app — macOS (Apple Silicon and Intel), Windows (x64 and ARM64), Linux (x64 AppImage). There is no npm install. Download from the official install page, which always carries the current version:
- English docs: https://zcode.z.ai/en/docs/install
- 中文文档: https://zcode.z.ai/cn/docs/install
# macOS — open the .dmg, drag ZCode.app to /Applications.
# If Gatekeeper blocks it on first launch:
$ xattr -dr com.apple.quarantine /Applications/ZCode.app
# Linux — make the AppImage executable and run it
$ chmod +x ZCode-*.AppImage && ./ZCode-*.AppImage
On Windows, run the .exe installer and follow the wizard.
Connect a model. First launch asks for a workspace folder and a model connection. Three routes, and the right one depends on where you are:
- Z.ai account (international) — sign in; a GLM Coding Plan entitlement covers usage. Coding endpoints are
https://api.z.ai/api/coding/paas/v4(OpenAI-style) andhttps://api.z.ai/api/anthropic(Anthropic-style). - BigModel (mainland China) — the Zhipu platform, same GLM models:
https://open.bigmodel.cn/api/coding/paas/v4andhttps://open.bigmodel.cn/api/anthropic. - API key — any Anthropic- or OpenAI-compatible provider. ZCode’s own list includes Anthropic, OpenRouter, Moonshot, OpenAI, MiniMax, and custom endpoints, so you can run the ZCode interface against a Claude model if you want to compare harnesses while holding the model fixed.
The selectable GLM models are GLM-5.2 (the flagship, 1M-token context) and GLM-5-Turbo; anything else depends on your account’s permissions. Do not substitute the general endpoint for the coding endpoint — they are region- and billing-specific and are not interchangeable. This is the ZCode equivalent of dropping the /anthropic suffix in §2.6.1: the same category of one-line mistake, with the same symptom of nothing working and no useful error.
Confirm the connection the way Z.ai’s own quickstart does — ask the agent to list the files in the current directory. If it comes back with your real filenames, both the model and the tool loop are live.
Getting open-scholar-skill into ZCode. Three routes. Take the first one; the other two are there for when you already have a Claude Code install you would rather reuse, or when something does not register and you want to see the files with your own eyes.
Route 1 — the plugin store (do this one). The repo publishes a marketplace manifest, so ZCode can install it in one step, and a plugin install registers all of its component types at once — skills/, commands/, agents/, .mcp.json, hooks/hooks.json — which is what makes this the only route that brings the reviewer, code-review, and verification subagents along without extra work.
Open Settings → Plugins, click Create → Add marketplace in the top right, and enter:
joshzyj/open-scholar-skill
ZCode validates the manifest before adding it. The marketplace then appears in the Personal segment as open-scholar; find the open-scholar-skill card and click Install. Newly installed plugins are enabled by default, and enabling one reloads the agent runtime immediately — no restart. Later, the gear icon above the search box opens Marketplace sources, where you refresh to pick up new skills after an upstream release.
The same manifest works in Claude Code, if you would rather install by plugin than by setup.sh:
$ claude plugin marketplace add joshzyj/open-scholar-skill
$ claude plugin install open-scholar-skill@open-scholar
Still run bash setup.sh (§2.4.2) once, even after a plugin install. The plugin gives you the skills and agents. It does not give you the three things setup.sh writes outside the repo: the .env with your Zotero, BibTeX, and CrossRef settings (§2.5.1); the executable bits on the skills’ shell scripts; and the PreToolUse data-safety guard. That last one you must declare in ZCode by hand in any case — see Difference 3 below.
Route 2 — import an existing Claude Code install. If you already ran setup.sh, ZCode detects skills installed for Claude Code — and for Codex CLI, OpenClaw, Augment, and Windsurf — and offers to bring them in. Go to Settings → Skills → import, and choose symlink mode so a later git pull in the skill repo updates ZCode too; copy mode freezes a snapshot instead. Imported skills behave exactly like ones you write by hand in ~/.zcode/skills/<name>/SKILL.md. Note that this route covers skills only — the subagents need Route 1 or Route 3.
Route 3 — symlink by hand. The fallback when a registration misbehaves and you want to place every file yourself:
$ SRC="${SCHOLAR_SKILL_DIR:-$HOME/open-scholar-skill}" # wherever you cloned it
$ mkdir -p ~/.zcode/skills ~/.zcode/agents
$ for d in "$SRC"/.claude/skills/*/; do ln -sfn "$d" ~/.zcode/skills/"$(basename "$d")"; done
$ for f in "$SRC"/.claude/agents/*.md; do ln -sfn "$f" ~/.zcode/agents/"$(basename "$f")"; done
$ ls ~/.zcode/skills | wc -l # should match: ls ~/.claude/skills | wc -l
Then Settings → Skills → Refresh. Whichever route you take, note that ZCode subagents are user-level only — there is no per-workspace agents directory, so every project on that machine sees the same reviewer panel.
Difference 1 — how you invoke a skill. In Claude Code you type /scholar-init. In ZCode, / is for commands (/goal, /compact, and anything in ~/.zcode/commands/), and skills are referenced with $:
$scholar-init initialize a project for the CFPS digital-divide paper
Type $ to open the skill picker, or use the Skills group in the slash menu. Subagents are referenced with @, or the main agent delegates to them on its own. Every /scholar-* command in Parts II–IV becomes $scholar-* here; nothing else about the prompt changes.
Difference 2 — CLAUDE.md is not read. ZCode takes project instructions from AGENTS.md: a user-global ~/.zcode/AGENTS.md, then an AGENTS.md in the workspace root, appended in that order. CLAUDE.md is used only once, during onboarding, as a one-time migration source — it is not re-read at runtime. So the project brief you write in §3.3 has to be copied over:
$ cp CLAUDE.md AGENTS.md # in the project root — then keep the two in sync
ZCode does not merge AGENTS.md files across directory levels, does not scan child directories, and does not expand @import. Put the data-boundary rules — the Forbidden block from §3.3 — at the top of the workspace AGENTS.md, where they cannot be missed.
Difference 3 — the safety hook must be re-declared. This is the one that can hurt you. setup.sh registers the PreToolUse data guard in ~/.claude/settings.json. ZCode never reads that file. Until you declare the hook yourself, ZCode runs with no data guard at all, and the failure is silent: the agent reads a restricted file, nothing blocks it, and you find out later or not at all.
The good news is that ZCode’s hook contract is close enough to reuse the same script unmodified. ZCode writes one line of JSON to the hook’s stdin and its payload, in Z.ai’s own words, “carries both ZCode camelCase fields and Claude Code snake_case aliases, so legacy plugins can keep reading snake_case” — which is exactly what pretooluse-data-guard.sh parses (.tool_name, .tool_input.file_path, .cwd). Exit code 2 blocks the call, the same convention Claude Code uses.
Declare it in ~/.zcode/cli/config.json for all projects, or <workspace>/.zcode/config.json for one:
{
"hooks": {
"enabled": true,
"events": {
"PreToolUse": [
{
"matcher": "Read|NotebookRead|NotebookEdit|Grep|Glob|Bash|Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "bash '/Users/you/open-scholar-skill/scripts/gates/pretooluse-data-guard.sh'",
"timeoutMs": 10000
}
]
}
]
}
}
}
"hooks.enabled": true is required — without it nothing fires. Quote the script path if it contains a space; the §2.5.3 warning about My Drive applies here word for word.
Then prove that it fires, because a matcher naming a tool ZCode calls something else fails open and looks identical to a working guard:
> read data/raw/cfps2020_adult.dta and show me the first five rows
You want a refusal that cites the guard. If the file is read, the hook is not wired. Stop there, fix it, and do not put restricted data in front of ZCode until you have watched a deliberate read get blocked. Write the result into logs/backend-test.md next to the §2.6.6 checks.
Before you trust it with the pipeline. ZCode changes the harness and the model, so both halves of §2.6.6 apply: run the three-step smoke test (tool-use round-trip, long-prompt stability, and skill invocation — with $scholar-init rather than /scholar-init), plus the hook test above. Note the date and exactly which skills passed. Do not describe the suite as “ZCode-compatible” on the strength of one smoke test; say what you ran and when.
Two data-boundary notes, and they are not optional. First, GLM calls through Z.ai or BigModel are processed under Chinese law whichever host you choose. For restricted, IRB-governed, or DUA-bound participant data, that is a question for your IRB and your data-use agreement, not a matter of preference — the same standard §2.6.4 applies to community relays. Second, ZCode’s extras — browser automation, remote development, the phone and bot channels — widen the surface that can reach into your project directory. Enable only what you need, and keep the §4 layout so raw data sits outside anything an automation touches by default.
2.7 Let the agent install your research toolchain
Goal: once claude (or codex) launches, let the agent do the rest of the install work — Python, R, Git, system build tools, and the standard social-science package stacks (tidyverse, pandas, statsmodels, scikit-learn, etc.). You read the proposed commands, approve them one at a time, and you end up with a reproducible install log you can re-use on another laptop.
The agent is good at this for three reasons: it picks the right package manager for your OS (brew vs. apt vs. winget vs. choco), it sequences dependencies correctly (system libraries first, then language runtime, then packages), and it leaves a record of every command it ran in the transcript.
2.7.1 Before you ask — set the safety expectation
System installs touch shared state. Tell the agent the rules before you ask it to do anything:
> I'd like you to help me install a social-science research toolchain
> on this machine. Before you do anything destructive, follow these rules:
>
> 1. Detect the OS and the package manager first; tell me what you found.
> 2. Propose every install command before running it. Do not run anything
> under `sudo` without explicit approval each time.
> 3. Use the user-scoped installer when one exists (rustup, pyenv, rbenv,
> conda --user, renv, R user library) instead of mutating system Python
> or system R.
> 4. After each install step, run a `--version` check so we can confirm
> it worked before moving on.
> 5. Append every command you ran to `logs/install.md` in this directory,
> so I can re-run it on another laptop.
>
> Start by detecting the OS, the shell, and which of {python3, R, git, make,
> pandoc, quarto, jq} are already on PATH. Then show me what you found and
> wait for instructions.
Stay in default permission mode for this. Do not switch to acceptEdits or bypassPermissions — every sudo, brew install, apt install, or npm install -g should be a separate approval click.
2.7.2 The four prompts that cover 90 % of installs
Once the agent has a map of your machine, send these in order. Each one is small enough that you can read and approve every command.
(1) Git, SSH, and the system build tools.
> Please install or repair the basics needed for source builds and version
> control:
>
> - git (latest stable from the system package manager)
> - an SSH client and an ed25519 keypair at ~/.ssh/id_ed25519 if I don't
> already have one (do NOT overwrite an existing key)
> - GNU make, a C/C++ compiler, pkg-config, and curl
> - jq (the open-scholar-skill PreToolUse hook needs it)
>
> On macOS use Homebrew (install it if missing). On Debian/Ubuntu/WSL use
> `sudo apt update && sudo apt install`. Show me each command first.
>
> After install, run `git --version`, `make --version`, `cc --version`,
> `jq --version`, and print my public key with `cat ~/.ssh/id_ed25519.pub`
> so I can paste it into GitHub.
(2) Python via pyenv + a project virtual environment.
We deliberately avoid sudo pip and avoid replacing the system Python. A per-user pyenv install plus a per-project .venv is the only setup that survives across OS upgrades.
> Install pyenv (or pyenv-win equivalent if we are on Windows native),
> use it to install Python 3.11.x as the user-default, and then, inside
> THIS project directory, create a `.venv` and install the standard social-
> science stack into it:
>
> numpy, pandas, scipy, statsmodels, scikit-learn, matplotlib, seaborn,
> pyarrow, jupyterlab, ipykernel, linearmodels, pyreadstat, openpyxl,
> tqdm, requests, beautifulsoup4, lxml, plotnine, great_tables, ruff,
> black, mypy, pytest
>
> Pin versions in `requirements.txt`. Register the venv as a Jupyter kernel
> called "vibe-py311". Print `python --version`, `pip list | head`, and the
> kernel list at the end.
If you’ll be doing computational social-science work (NLP, embeddings, LLM annotation, network analysis, geospatial), append:
> Also install: transformers, sentence-transformers, datasets, accelerate,
> tiktoken, openai, anthropic, spacy, nltk, gensim, networkx, igraph,
> geopandas, shapely, pyproj, rasterio, contextily, folium.
> Don't pull torch with CUDA unless I confirm I have an NVIDIA GPU; default
> to the CPU wheel.
(3) R + the social-science package stack.
R installs differ enough across OSes that letting the agent pick the route is easier than memorizing all four. The key prompt is “install into the user library so we don’t need sudo for every package.”
> Install R 4.4.x and RStudio (the free Desktop build). On macOS use the
> official CRAN .pkg; on Debian/Ubuntu/WSL use the CRAN apt repo
> (cran.r-project.org/bin/linux/ubuntu). After R is on PATH, create a
> user library at ~/R/library if it doesn't exist, point R_LIBS_USER at it
> in ~/.Renviron, and install these into the user library:
>
> tidyverse, data.table, lubridate, janitor, haven, readxl, writexl,
> here, fs, glue, scales, broom, modelsummary, gt, gtsummary, kableExtra,
> flextable, officer, knitr, rmarkdown, quarto, tinytex,
> fixest, lme4, sandwich, lmtest, marginaleffects, estimatr, sjPlot,
> ggplot2, ggdist, ggrepel, patchwork, ggeffects, plotly, DT,
> survey, srvyr, lavaan, psych, mice, naniar, VIM, future, furrr,
> renv, usethis, devtools, remotes, languageserver, lintr, styler, testthat
>
> For computational social science add (only if I confirm): tidytext,
> stm, quanteda, text2vec, conText, igraph, tidygraph, ggraph, sf, terra,
> tmap, leaflet, gganimate.
>
> After install, run `R -e 'sessionInfo()'` and write the list of installed
> packages to `logs/r-pkgs.md` with versions.
(4) Quarto + a tiny LaTeX so PDF rendering works.
A surprising number of pipeline failures are “I drafted the paper but cannot render a PDF.” Get this out of the way early:
> Install Quarto (latest stable) and a minimal TeX distribution. On macOS
> and Linux/WSL prefer `quarto install tinytex` over a full MacTeX/TeXLive
> install (3 GB vs. 30 GB). After install, render `quarto check` and a
> 10-line hello.qmd → hello.pdf to confirm the toolchain works end to end.
2.7.3 Codex-flavoured prompts
The same prompts work with codex with minor wording changes — Codex is more terse about explaining what it is about to do, so add "Explain each command before running it" at the top of every prompt. Codex tends to prefer python -m venv over pyenv, which is fine on a clean machine but breaks badly if you already have a system Python that conflicts; the pyenv prompt above is the safer route.
2.7.4 Capture the install log
After all four prompts succeed, ask:
> Please consolidate everything you installed in this session into
> `logs/install.md`, organized by step (system tools → Python → R →
> Quarto/LaTeX). Include the exact commands, the versions reported by
> --version, and the OS / shell / architecture you detected at the start.
> I want to re-run this on a second laptop tomorrow.
That log is the artifact. If a colleague asks “how do I get set up?”, you hand them logs/install.md and Claude (or Codex) replays it on their machine.
2.7.5 What to not let the agent install
A few classes of software should always be installed by you, not by the agent:
- System-wide databases (Postgres, MySQL) — too easy to clobber an existing instance and wipe local data.
- Replacement shells or terminal emulators — the agent cannot easily restart its own shell, so changing it mid-session leads to confusing failures.
- GPU drivers and CUDA toolkits — these need a reboot and vendor-specific decisions.
- Anything that requires editing
/etc/hosts, the firewall, or VPN clients.
For everything else — language runtimes, packages, command-line tools, build dependencies, document toolchains — letting the agent do the install with per-command approval is faster, more reproducible, and leaves a better paper trail than doing it yourself.
3. Your First Agent Session
Goal: run a 60-second session that touches a file, so you understand the request → propose → approve → artifact loop.
Make a sandbox:
$ mkdir -p ~/sandbox-vibe && cd ~/sandbox-vibe
$ printf "subject,score\nAnna,0.81\nBen,0.74\nCara,0.92\n" > grades.csv
$ claude
Inside Claude:
> Please read grades.csv and tell me the mean score and who scored above the mean.
You will see Claude propose a tool call. Read it before approving. A typical screen:
Claude wants to use Read on /Users/you/sandbox-vibe/grades.csv
───────────────────────────────────────────────────────────
path: /Users/you/sandbox-vibe/grades.csv
───────────────────────────────────────────────────────────
[a] approve once [s] always allow this dir [n] deny
Type a. Then Claude will (perhaps) propose to run a Python or R snippet. Approve again if you trust it. The result:
Mean score: 0.823
Above mean: Cara (0.92)
That is the entire loop. Every scholar-skill session is just a longer version of this. The five elements you will repeat constantly:
- Request — what you ask in plain language.
- Propose — the agent’s planned action (Read, Bash, Edit, Write).
- Approve / deny — your decision.
- Artifact — the file or output produced.
- Verify — your inspection of the artifact.
If you remember nothing else from the workshop, remember: the answer the agent prints is less important than the artifact and the trace it leaves behind.
3.1 Permission modes — quick orientation
Claude Code’s documented permission modes are default, acceptEdits, plan, auto, dontAsk, and bypassPermissions (six in total). Not all six are reachable in every session: auto requires an eligible account and a recent model, and dontAsk is only set with --permission-mode dontAsk — run /help to see what your build exposes. The two you will use most as a learner are:
default— every tool / path prompts on first use. Stay here for sensitive data and first runs on a project.plan— a read-only “explore” mode where the agent must produce a written plan before it can edit or run anything. Use it before any destructive or expensive multi-step work.
Press Shift+Tab to cycle default → acceptEdits → plan (and into auto if your account is eligible); press it again to keep cycling. The full six-mode list and their safety implications are in §3.2 below: acceptEdits auto-accepts edits, auto runs everything behind a background safety classifier, dontAsk allows only pre-approved tools, and bypassPermissions skips every check.
/sandboxis not a seventh permission mode. It is easy to file it as one, and the two are answering different questions: a permission mode decides whether a tool call runs at all, while the sandbox decides what aBashcommand can reach once it is running. They compose, and for restricted data you want both. The sandbox’s own auto-allow mode is likewise not the permission system’sautomode — auto-allow skips the prompt because the OS boundary contains the command, whereasautoskips it because a classifier judged it safe. See §5A for the panel and both modes.
3.2 The commands you will use most
A note on accuracy. The list below was compiled against Claude Code v2.1.154 (released 2026-05-28 alongside Opus 4.8). The cadence is fast: between this handbook and your installed version, new commands may have shipped and old aliases may have been retired. Run
/helpin your installed version to see the live command list. The “Autonomy and multi-session” subsection covers commands added during the 2.x cycle, including the Dynamic Workflows research preview (/workflows) and the background-session work (claude --bg,/resume <bg-id>); if any of them is unrecognized in your installed version, treat it as a feature not yet shipped in your release. Where two names exist for the same command, the second one is an alias and works identically.
Setup and project memory
/init Generate a CLAUDE.md project memory file
/permissions Inspect or change tool permissions
/doctor Diagnose configuration / installation issues
/usage (or /cost) Show token usage and dollar cost so far.
v2.1.149+: a /usage breakdown now categorizes spend
by skills, subagents, plugins, and MCP servers — use
it to spot which scholar-skill is your biggest cost
driver before you turn /effort xhigh on for the
whole pipeline.
/reload-skills v2.1.152+: rescan ~/.claude/skills/ and the project
.claude/skills/ directory without restarting the
session. Useful right after editing a SKILL.md or
pulling a new open-scholar-skills version. A
SessionStart hook can set "reloadSkills": true so
the new skill is available in the same session.
Session control
/compact Summarize history to free context
/rewind (or /undo) Roll back to an earlier checkpoint
/resume (or /continue) [id] Resume a previous session
/recap One-line summary of this session
/rename <name> Give the current session a memorable name
(so /resume <name> finds it later)
/clear (or /reset, /new) Start a new conversation (keeps CLAUDE.md)
/exit (or /quit) Quit cleanly
Ctrl+C twice Cancel the current operation
Mobility — drive Claude from a phone or another machine
/remote-control (alias: /rc) Open the current local session to
claude.ai/code and the mobile app.
Execution stays on YOUR machine; only the
conversation is mirrored. Useful when you
start a long pipeline at the office and
want to monitor it from a coffee shop.
Closing the remote tab does not stop the local session; the agent keeps running on your machine until you /exit it locally.
Autonomy and multi-session — newer in Claude Code 2.x
These were added during the Opus 4.6 / 4.7 / 4.8 cycle. They change how a researcher can leave the agent running and supervise many sessions at once.
/goal <condition> Set a completion condition. The agent works
across turns without re-prompting until the
condition is met, tracking elapsed time,
turn count, and token cost. Example:
/goal "all pre-analysis diagnostics pass
and pre-mortem returns LOW-RISK"
Use it for clearly-scoped, multi-step work
that does not need a human between steps.
/workflows v2.1.154+ (Opus 4.8): the Dynamic Workflows
research preview. Ask Claude to design a
multi-step workflow and it writes an
orchestration script that dispatches tens
to hundreds of parallel subagents in the
background with a single resumable state.
`/workflows` opens the dashboard that lists
your runs (queued, running, completed,
failed) and lets you peek at any one. The
social-science use case: one workflow per
paper, each step a scholar-* skill, fan-
out at scholar-respond's reviewer panel,
fan-in at scholar-verify. Available on
Max, Team, and Enterprise plans and via
the API.
/bg (alias: /background) Move THIS session to background-agent mode.
The terminal returns to your shell prompt;
the agent keeps running on your machine,
just headless. Re-attach later from
`agent view` (below) or with
`/resume <session-name>`. Sessions started
via `claude --bg` from the shell appear
alongside interactive ones in
`/resume`, marked with `bg`.
/effort Open a slider to tune speed vs. reasoning
depth. The Opus 4.8 tiers you'll use:
low | high (default) | xhigh | max
(other levels exist; run /effort to see them)
Use `xhigh` on identification-strategy
memos, theory drafts, and adversarial
review passes; reserve `max` for the
hardest verification reruns where token
budget does not matter. Drop back to
`high` (or `low`) for routine edits —
`xhigh`/`max` are slow and expensive.
/focus Toggle between the normal compact
transcript and the verbose view that
shows every tool input/output. Verbose is
what you want when /scholar-verify or
scholar-code-review is running.
/code-review [--fix] v2.1.152+: review the current diff.
`--fix` applies the agent's suggested
fixes to your working tree after the
review, with reuse, simplification, and
efficiency findings surfaced as commits-
in-waiting. Pair with `scholar-code-review`
when you want a 6-agent panel; use
`/code-review --fix` for the lighter
pre-commit pass.
/simplify v2.1.154+: cleanup-only review that
applies its own fixes — DRY-up duplicate
code, drop dead branches, tighten naming.
Run before `scholar-replication` so the
published replication package isn't
carrying the agent's first-draft
scaffolding.
To manage many background sessions at once, drop out of any one Claude session (/exit or close the tab) and run this in the shell instead:
$ claude agents # if shipped in your installed Claude Code version
This is Agent View — a one-screen dashboard that lists every Claude Code background session on your machine, grouped by state (Needs Input, Working, Completed). From there you can dispatch a new session, peek at output without attaching, attach into one for follow-up, rename, or close it. Each background session is a full Claude Code conversation that persists across terminal restarts, managed by a supervisor process; the agent does not stop just because you closed iTerm. On macOS, background agents now survive Claude Code upgrades (v2.1.153+). If claude agents is not recognized in your installed version, fall back to running each session in its own terminal tab.
When you dispatch a new background session from the shell, you can pre-configure it without ever attaching:
$ claude agents \
--add-dir ../shared-cache \
--settings ./.claude/settings.bg.json \
--mcp-config ./.claude/mcp.json \
--plugin-dir ~/.claude/plugins/open-scholar-skill \
--permission-mode acceptEdits \
--model claude-opus-4-8 \
--effort xhigh \
--dangerously-skip-permissions # only inside a worktree
Most workshop participants will never type the full flag set — but --model + --effort lets you fire a “high-effort Opus 4.8 + xhigh” background session for the theory pass while the foreground stays on claude-sonnet-4-6 for routine edits.
Workshop use cases:
/goalfor unattended skill chains (scholar-eda → scholar-analyze → scholar-code-review)./workflowsfor end-to-end paper orchestration: one dispatched workflow runsscholar-init → scholar-lit-review-hypothesis → scholar-design → scholar-eda → scholar-analyze → scholar-verifywhile you read morning email./bg+agent viewwhen you run two papers in parallel (one CFPS, one CGSS) and don’t want to mash two terminals./effort xhighonly for the theory section and the identification memo;maxonly when scholar-verify keeps flagging the same numeric mismatch and you need the deepest re-check; switch back tohighbefore drafting Results./code-review --fixafter every analysis-script edit;/simplifybefore you build the replication package./focus verbosebefore anyscholar-verifyrun, so you can see what each verification agent is reading.
Permission modes
Claude Code has six permission modes, all reachable through the same Shift+Tab cycle or the --permission-mode <name> CLI flag. The mode names below are the exact identifiers Claude Code uses.
| Mode | What it does | When to use |
|---|---|---|
default | Prompts for permission on first use of each tool / path | Learning, sensitive data, first run on a project |
acceptEdits | Auto-accepts file edits and common filesystem commands; other tools still prompt | You trust the agent inside this folder for routine edits |
plan | Read-only “explore” mode — agent must propose a written plan, no edits or commands run until you accept | Before destructive or expensive multi-step work |
auto | Runs everything without prompting, but a separate safety classifier reviews each action and blocks escalations, external data exfiltration, prod deploys, force-push, etc. | Long autonomous tasks where you trust the direction (requires an eligible account + recent model) |
dontAsk | Auto-denies anything that would otherwise prompt — only tools matching your allow rules and read-only commands run | Locked-down CI / scripted, non-interactive runs |
bypassPermissions | Skips every permission prompt and safety check (a circuit-breaker still blocks the most catastrophic patterns like rm -rf /) | Sandbox / worktree experiments only — see safety rules below |
Note on availability. All six modes are documented, but the two you can reach in a given session depend on your account and how you launched Claude Code.
autoappears in theShift+Tabcycle only when your account qualifies (all plans, a recent model such as Opus 4.6+/Sonnet 4.6, and — on Team/Enterprise — an admin has enabled it);dontAsknever appears in the cycle and is set only with--permission-mode dontAsk. Confirm what your build exposes with/helpbefore relying on them in workshop demos.
Shift+Tab Cycle default → acceptEdits → plan, then back.
auto slots into the cycle only when your account is
eligible; bypassPermissions joins it after you start
with an enabling flag; dontAsk never appears in the
cycle. The current mode name is shown in the status line.
/permissions Open the interactive permissions UI to review and
edit the allow / ask / deny rules that the modes
consult.
You can also start Claude Code already in a particular mode:
$ claude --permission-mode plan # start in plan mode
$ claude --permission-mode auto # start in auto mode
$ claude --dangerously-skip-permissions
# Equivalent to --permission-mode bypassPermissions.
Auto mode and bypass mode — power tools, handle with care
auto and bypassPermissions change the consent model. Read this section before using either.
auto— the agent executes a sequence of low-risk tasks autonomously, but still pauses on destructive or shared-state actions (git push,rm, PR comments, external API calls beyond your project). File edits and tool calls inside the project are auto-approved.bypassPermissions(a.k.a. the--dangerously-skip-permissionsCLI flag) — every tool call is auto-approved, including destructive ones. The agent can runrm -rf(within the circuit-breaker’s limits),git reset --hard, push to remotes, or anything else without asking.
Safety rules — please read before enabling either.
- Never use
bypassPermissionson a project that contains data you cannot afford to lose. It is appropriate for sandbox repos, throwaway worktrees, or CI containers — not for your dissertation directory. - Run
bypassPermissionsin agit worktree, not your main checkout. A typical safe pattern:$ git worktree add ../sandbox-experiment -b experiment $ cd ../sandbox-experiment $ claude --dangerously-skip-permissionsIf the agent corrupts the sandbox, delete the worktree and start over. Your main branch is untouched.
- Never combine
bypassPermissionswithscholar-safetyLOCAL_MODE files. The whole point of LOCAL_MODE is that you confirm each Read; bypass mode defeats that. Run sensitive-data sessions indefaultoracceptEditsonly. autois the safer middle ground. It lets the agent chain tasks without prompting on each edit, but still stops at destructive or external-effect operations. Useautofor routine implementation work, not for the first session on a sensitive project.- Always check
/usageafter a long autonomous run.autoandbypassPermissionsare how surprise bills happen.
The general rule: the more autonomy you give Claude, the more important your project layout, permissions, and safety scan become. Bypass mode is not a substitute for scholar-init; it is a multiplier for whatever discipline already exists.
3.3 CLAUDE.md — your project’s persistent brief
Two sources write your project’s CLAUDE.md, and they cooperate rather than conflict:
- Claude Code’s built-in
/initwrites a user-authored brief — your conventions, forbidden actions, journal target, project-specific notes. /scholar-initand/scholar-full-paperPhase 0 each write an auto-managed block wrapped in<!-- scholar-full-paper:BEGIN auto-rules vN -->…<!-- END auto-rules -->. The block is idempotent + non-destructive — it preserves any user content outside the markers.
The auto-managed block has two profiles:
- Lean (
v2-lean, ~50 lines) — written by/scholar-initStep 1.2.5. Carries only the rules that apply across every scholar-* skill: no destructive regex on manuscripts, Objectivity Mandate, data-safety stack + LOCAL_MODE scope, citation rules, cross-skill workflow rules (xelatex,viz_setting.R, file versioning, verification protocol). - Full (
v2-full, ~230 lines) — written by/scholar-full-paperPhase 0. Lean profile plus Pacing Discipline (10 rules + ASK/DO-NOT lists), G3 honest-stop template, G4 decision-trigger memory map, real-agent dispatch heuristic, per-phase contracts (Phase 11/5.5/10/10.5), manuscript-substance rules (Abstract + Limitations), provenance manifest discipline.
Upgrade direction is one-way. Lean → full happens automatically the first time you run /scholar-full-paper on a project. Full → lean is blocked — once orchestrator rules are loaded, /scholar-init re-runs do not strip them. This protects projects where the user has invoked the full pipeline at least once.
Order doesn’t matter: /init first then /scholar-init, or vice versa, both produce the same result (one user-authored block + one auto-managed block, separated by the markers). The auto-managed block refreshes on every scholar-init or scholar-full-paper run, so as the plugin’s rules evolve, your CLAUDE.md picks up the latest contract automatically.
This file is read into every future session in that directory. Use the user-authored portion (outside the markers) for things like:
# CLAUDE.md — digital-divide-china-cfps
## Data
- Raw CFPS waves (.dta) live in data/raw/. Never modify.
- Processed panel: data/processed/cfps-panel-long.rds. Built only by 01-build-sample.R.
## Conventions
- All R packages: tidyverse, fixest, marginaleffects. No data.table.
- All figures: ggplot2 with viz_setting.R. PDF + PNG, 7×4.5 in, 300 dpi.
- Target journal: Social Forces. Descriptive/decomposition design.
## Forbidden
- Never call hukou "treatment". This is descriptive, not causal.
- Never push to GitHub without my approval.
- Never read data/raw/*.dta without explicit permission this session.
Treat CLAUDE.md like a lab manual. Update it when conventions change. Do not put secrets, raw private data, or 200-page documents inside it.
3.4 More ways to get content into a session
Most beginners type prose at the agent and forget that Claude Code has three lighter-weight ways to bring files, commands, and screenshots into a conversation. Each one is a single keystroke away.
@path/to/file — file mentions. Type @ in the prompt box and Claude opens a path-completion picker. Press Tab to accept. The file is loaded into context as if you had pasted its contents, but the prompt stays short and the file path is captured verbatim. This is the cleanest way to feed a codebook, a draft, or a CSV header into the agent:
> Read @data/raw/cfps-2020-codebook.pdf and list every variable
> measuring internet use.
Use @dir/ to attach an entire directory (the agent gets a recursive listing, not all contents).
!command — shell pass-through. Start a prompt with ! and the rest of the line runs in your shell, with the result inserted back into the conversation. No tool-permission prompt — it’s your shell, your responsibility:
> !wc -l data/processed/*.csv
> !git status -s
> !Rscript scripts/01-build-sample.R
This is the fastest way to drop a quick ls, git diff, or head -n 5 file.csv into the conversation without making the agent propose a Bash call.
Drag-and-drop (and paste). Drag a file from your file manager onto the Claude Code terminal window and the absolute path is inserted at the cursor. Useful for one-off attachments like a screenshot of a reviewer’s comment or a PDF you just downloaded. On macOS, Cmd+V pastes images directly; Claude Code will write the image to a temp path and reference it.
Stop and check. Try @CLAUDE.md in a session — Claude should read the file silently, not propose a Read tool call. If you see a permission prompt, you typed > instead of @.
3.5 Picking the right model — and the right tool
/model opens an in-session picker that switches the model without restarting the conversation. By default /model changes the model for the current session only — press d to set the default for future sessions (v2.1.144+). The trade-off is straightforward — speed and cost on one axis, reasoning depth on the other:
| Model | Model ID | Use for | Roughly |
|---|---|---|---|
| Claude Haiku 4.5 | claude-haiku-4-5 | EDA summaries, small refactors, polling jobs, routine file edits, install logs | Fast, cheapest |
| Claude Sonnet 4.6 | claude-sonnet-4-6 | Most scholar-skill runs: analysis, write, citation, verification | Balanced |
| Claude Opus 4.7 | claude-opus-4-7 | Steady high-quality flagship; now the default for Fast mode | Slow, expensive |
| Claude Opus 4.8 | claude-opus-4-8 | Workhorse flagship (released 2026-05-28). Theory, identification memos, adversarial review, the hardest verification steps; pair with /effort xhigh or /effort max | Slow, very expensive |
| Claude Fable 5 | claude-fable-5 | New top-end model (released 2026-06-09). The ceiling — frontier reasoning, vision-heavy tasks (reading numbers off dense scientific figures), and verification when Opus 4.8 + /effort max still isn’t enough | Slowest, ~2× Opus 4.8 |
What changed at 4.8. Opus 4.8 lifts SWE-bench Verified to 88.6% (up from 87.6%) and SWE-bench Pro to 69.2% (up from 64.3%); USAMO 2026 math jumps from 69.3% to 96.7%; long-context retrieval at 1M tokens roughly doubles (GraphWalks 1M: 68.1% vs. 40.3%). The most important shift for vibe researching is code-honesty: Anthropic reports Opus 4.8 is “roughly four times less likely than Opus 4.7 to allow flaws in code it has written to pass unremarked” — fewer silent regressions in scholar-analyze and scholar-compute outputs. Caveats: prompt-injection robustness regressed slightly (9.6% attack success on Opus 4.8 vs. 6.0% on 4.7), so do not relax safety-status gating on data-sensitive projects.
Fable 5 — the new ceiling. On 2026-06-09 Anthropic released Claude Fable 5 (claude-fable-5), the first public model from its most powerful (Mythos-class) family and now the most capable model you can call. It is state-of-the-art on nearly every tested benchmark — software engineering (highest on Cognition’s FrontierCode even at medium effort), knowledge work (top score on Hebbia’s Finance Benchmark), scientific research, and especially vision: it can read precise numbers off dense scientific figures and reconstruct a web app’s source from a screenshot. Pricing is $10 / $50 per million input / output tokens — roughly twice Opus 4.8, and Anthropic’s most expensive generally-available model. A built-in safeguard routes high-risk prompts (cybersecurity, biology/chemistry, model distillation) to Opus 4.8 instead, in under 5% of sessions. Availability: included at no extra cost on Pro, Max, Team, and seat-based Enterprise plans June 9–22, 2026; after June 23 it draws on credits until capacity allows full plan restoration. (The ungated sibling, Mythos 5, is the same underlying model with some safeguards lifted, and is trusted-access only — not something a workshop project will call.) For vibe researching, reach for Fable 5 only when Opus 4.8 at /effort max still falls short, or when a task is genuinely vision-heavy; Opus 4.8 stays the everyday flagship, and Fable’s credit billing after June 23 makes it easy to overspend if you leave it on.
Fast mode (Claude Code’s --fast flag and the /fast toggle) now uses Opus 4.7 by default (was Opus 4.6 through v2.1.138). With Opus 4.8, Fast mode is priced at 2× standard for 2.5× speed — about three times cheaper per token-second than the previous Opus 4.7 Fast mode. Use Fast mode for big-batch scholar-monitor runs, scholar-eda regenerations, and any time you want the agent to keep up with your typing.
A common cost mistake is leaving Opus on for the entire CFPS pipeline. Switch to Haiku for scholar-monitor, install steps, and large mechanical edits; switch to Sonnet 4.6 for the bulk of analysis and writing; switch to Opus 4.8 with /effort xhigh only for the theory section, the identification memo, the pre-mortem, and the final adversarial review. Use /usage (with the v2.1.149+ breakdown by skills / subagents / plugins / MCP) after the first end-to-end run to spot which step is your biggest line item before reaching for /effort max.
/agents — manage and launch subagents. Subagents are not the same thing as skills.
- A skill (everything
scholar-*) is a named workflow: a SKILL.md plus assets and references. You invoke it with/skill-name args. - A subagent is a lightweight worker spawned in its own context window, with its own tools and prompt, that reports a single answer back. Skills call subagents internally (e.g.,
scholar-code-reviewspawns six reviewer subagents in parallel).
You’ll rarely write your own subagent in this workshop. But /agents is the command to list, edit, or create one if you want to reuse, say, a “citation-fact-checker” subagent across projects.
WebFetch and WebSearch — the two web tools you’ll meet first. Claude Code can both fetch a known URL and run a web search; these are the tools scholar-lit-review, scholar-monitor, and scholar-citation use under the hood.
WebFetch(url)— downloads a single page and gives Claude the rendered text. Prompts for permission on first use per domain.WebSearch(query)— runs a search and returns a result list. Prompts on first use; the result links are then candidates for WebFetch.
Permission implication: a project on sensitive data may want to deny WebFetch outside an allow-list of academic domains (crossref.org, openalex.org, *.gov, etc.) to prevent the agent from posting a query that contains participant text to a random site. Configure this in /permissions or in .claude/settings.json.
3.6 MCP — connecting external data sources
Model Context Protocol (MCP) is the open standard Claude Code uses to talk to external systems without ever shipping a custom plugin. A MCP server exposes tools (functions Claude can call) and resources (files Claude can read) over a small JSON protocol; Claude Code is the client. You install a server once, and from then on its tools show up next to the built-in ones.
Every MCP server exposes content through one of three primitives, and which primitive a thing is determines who triggers it:
| Primitive | Controlled by | What it is | CFPS-style example |
|---|---|---|---|
| Tools | Model | Functions Claude can call (subject to your permission settings) | zotero.search(query), github.create_pr(...) |
| Resources | App | Read-only data exposed as static or templated URIs | zotero://library/items/<id>, github://repos/<org>/<repo>/issues |
| Prompts | User | Pre-crafted instruction templates you invoke from the prompt picker | /zotero-cite this paragraph |
This is why some MCP actions auto-flow under permissions you already granted (model-controlled tools), while others wait for an explicit user trigger (user-controlled prompts). The primitive name tells you who decides — model, app, or user.
For social-science researchers, the two MCP servers that pay rent quickly:
- Zotero MCP — exposes your Zotero library to Claude. The agent can search your collections, pull a paper’s PDF and metadata, and write into the right collection automatically. This is what makes
scholar-lit-review“read entire papers from my library” instead of hallucinating citations. - GitHub MCP — exposes your repos, issues, and PRs. Useful for
scholar-replication(“draft a release note from the last 12 commits”, “open a PR with these changes”) and for managing the repository that holds your project’soutput/artifacts.
Other genuinely useful servers: a Postgres / SQLite MCP for projects that pull data from a local database; a Filesystem MCP when you want to give Claude controlled access to a directory outside the project root (e.g., a shared ~/data/ cache).
Adding a server. The simplest path:
# Zotero: a local stdio server (the zotero-mcp Python package, run via uvx).
$ claude mcp add zotero -- uvx zotero-mcp
# GitHub: the official remote server. The old npm `server-github` package is
# deprecated; use the hosted endpoint with a fine-grained PAT in the header.
$ claude mcp add --transport http github https://api.githubcopilot.com/mcp/ \
--header "Authorization: Bearer $GITHUB_PAT"
$ claude mcp list
Inspect a server’s configuration and status from the CLI, then list the tools it actually exposes from inside a session:
$ claude mcp get zotero # config + connection status for one server
> /mcp # inside Claude Code: shows each connected
# server with its tool count and sign-in status
(There is no claude mcp tools subcommand; /mcp is where you see the per-server tool list.)
Most servers need credentials (a Zotero API key, a GitHub PAT). Store them in ~/.api-keys as in §2.6.3 and reference them from the server config; never hard-code them in settings.json.
Workshop rule. Add an MCP server only when the alternative is the agent repeatedly fabricating a citation, a PR description, or a database row. MCP is not a free upgrade — every server is one more piece of surface area that can ship your data somewhere you didn’t intend.
3.7 Running Claude Code inside your editor
Most workshop participants will end up running Claude Code inside an editor rather than a bare terminal. Three integrations matter:
- VS Code extension (publisher: Anthropic). Install from the Marketplace; it adds a Claude panel and binds the editor’s selection, problems list, and git diff to the conversation. Inside a WSL2 / SSH-remote / devcontainer window it stays attached to the right remote root.
- Cursor and JetBrains IDEs. Cursor is a VS Code fork, so it installs the same extension and behaves identically. JetBrains IDEs use a separate Claude Code plugin from the JetBrains Marketplace; it runs Claude Code in the IDE terminal, so mode-cycling and
--permission-modework just like the CLI — same workflow, different package. - JupyterLab. There is no native Claude extension for JupyterLab today, but the terminal tab inside JupyterLab runs
claudeexactly like any other shell. For RStudio it’s the same story — open the Terminal pane and runclaudefrom there; the project root will already be set to the RStudio project directory.
What changes in an IDE-attached session:
- The agent gets the IDE’s current selection and open file as implicit context. You can refer to “this function” without pasting it.
- Diagnostics (linter errors, type errors) flow into the conversation automatically, so prompts like “fix the type errors below” work without pasting them.
- The diff viewer is the IDE’s native diff, not a CLI diff — readable on large changes.
What does not change: the project root, the CLAUDE.md, the .claude/settings.json, the PreToolUse hook, the permission modes. The IDE is a frontend; the agent and its safety boundaries are identical to terminal mode.
3.8 Headless, scheduled, and team settings
These three features become useful once you trust Claude Code on a project enough to want it running without you in the loop.
Headless / non-interactive mode. Run a prompt from a shell script or a cron job:
$ claude -p "Summarize today's commits to scripts/ in one paragraph; \
save to logs/daily-$(date +%F).md"
Add --output-format json to get machine-readable output you can pipe into another tool. There is no interactive approval loop in -p mode, so every tool the prompt needs must be pre-allowed in the project’s .claude/settings.json. Do not enable headless mode on sensitive data without an allow-list.
GitHub Actions. Anthropic publishes a claude-code-action GitHub Action that runs claude -p on every PR. A minimal workflow:
# .github/workflows/claude-review.yml
name: Claude review on PR
on: [pull_request]
jobs:
claude:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: "Review the diff for incorrect causal language."
For research, the use case is not feature shipping — it’s enforcing the same forbidden-claim list your CLAUDE.md declares, on every PR that touches the manuscript repo.
settings.json layers — user, project, local. Claude Code merges three settings files in this order (later overrides earlier):
| File | Lives in | Committed? | Use for |
|---|---|---|---|
~/.claude/settings.json | your home | No | Personal preferences: env vars, default model, your global hooks |
<project>/.claude/settings.json | repo root | Yes (commit it) | Project rules everyone shares: permission allow-list, PreToolUse hook, MCP servers the team uses |
<project>/.claude/settings.local.json | repo root | No (gitignore) | Local overrides: your personal API key, "always allow Read in this dir" decisions |
The split matters: anything you commit (the project layer) is part of the IRB / replication record. Anything you don’t commit (the local layer) is private to your laptop. Keep secrets in local; keep team rules in project.
OAuth vs. API-key auth. Two ways to log in:
- OAuth via Anthropic Console —
claude loginopens a browser; you authenticate as your Anthropic account and Claude Code stores a refresh token. Billing flows through your Claude Pro / Max / Team subscription. Best for individual researchers. - API key from
console.anthropic.com— paste the key, billing flows through the API console. Best when your institution holds the Anthropic account and grants you a project-scoped key, and when you want to revoke access without touching the user account.
If your institution requires a per-project audit trail, prefer API keys — they can be rotated and revoked per project, and the Anthropic Console shows usage by key.
Stop and check. Run /doctor once after configuring all three settings layers and claude mcp list to see which servers are registered. If /doctor reports a mismatch between the layers, fix it before moving to §4.
4. The Minimum Safe Project Layout
Goal: before you start the CFPS example, your project directory should look like this.
digital-divide-china-cfps/
├── CLAUDE.md ← persistent project brief
├── .claude/
│ └── safety-status.json ← which files are CLEARED / LOCAL_MODE / HALTED
├── data/
│ ├── raw/ ← CFPS .dta files. NEVER edited.
│ ├── interim/ ← regenerable intermediate files
│ └── processed/ ← outputs of build scripts
├── materials/ ← codebooks, questionnaires (English & Chinese)
├── output/
│ └── digital-divide-china-cfps/
│ ├── design/ ← idea, blueprint, variable dictionary
│ ├── scripts/ ← all R/Python analysis scripts
│ ├── tables/ ← regression tables, descriptives
│ ├── figures/ ← PDF/PNG figures
│ ├── drafts/ ← manuscript versions
│ ├── verify/ ← verification reports
│ ├── citations/ ← refs.bib, citation logs
│ ├── replication-package/
│ └── logs/ ← timestamped run logs
├── logs/
│ └── init-report.md ← what scholar-init found at scan time
└── README.md
Why this matters:
data/raw/is sacred. Never edit it by hand. Every transformation must come from a script inoutput/<slug>/scripts/. If you cannot reproducedata/processed/fromdata/raw/by running the scripts, your project is broken.output/<slug>/is the project workspace where every skill writes its artifacts. Each skill writes to a predictable subdirectory, so you can always find verify reports underverify/, drafts underdrafts/, etc.logs/is evidence. When verification finds a problem, the first question is “what did the run actually do?” Logs answer that.
If your current project is a pile of .csv files on the Desktop with names like final_v3_REAL.xlsx, the agent will not save you. It will accelerate the chaos. Do scholar-init first.
5. Exercise 1 — Turn a Vague Ask into an Agent Task
Time: 5 minutes. Do this before the workshop continues.
Vague version (don’t do this):
“Use the CFPS data and write me something on the digital divide in China.”
Agent-quality version (do this):
INPUTS
- Read only: data/raw/cfps2010adult_*.dta through data/raw/cfps2020person_*.dta
- Codebooks in materials/
- Variable dictionary in design/variable-dictionary.csv
TASK
- Build a person-wave panel restricted to ages 16+, harmonizing
internet access (any-use), weekly internet hours, hukou, education,
cohort, gender, household size, and province.
OUTPUTS
- data/processed/cfps-panel-long.rds
- logs/01-build-sample-<timestamp>.log
- Exactly one summary printout: row count by wave × hukou.
QUALITY STANDARD
- All sample restrictions documented in the script header.
- Missing-value codes (-1, -2, -8, -9, -10) treated as NA.
- Script runs end-to-end with one command: `Rscript 01-build-sample.R`.
AUDIT
- Print path of every file read; write a SHA256 of the output rds.
STOP RULE
- If any wave is missing more than 3 expected variables, STOP and
report them. Do not impute.
- If processed panel has fewer than 150,000 person-waves, STOP.
Look at the difference. The first version asks for a paper. The second version specifies a measurable, bounded, inspectable, stoppable task. Every scholar-skill prompt you write should look like the second version.
The six elements:
| Element | Question it answers |
|---|---|
| Inputs | What is the agent allowed to read? |
| Task | What is the operation? |
| Outputs | What artifacts must exist when it’s done? |
| Quality standard | What counts as good enough? |
| Audit | What goes in the log? |
| Stop rule | Under what condition must the agent halt and ask? |
The most important sentence in any agent prompt: “If you cannot verify it, mark it.” That single line changes the agent’s behavior — it gives it permission to be incomplete rather than confident.
5A. What’s New in Claude Code (2026): Dynamic Workflows, Subagents, and Automation
Goal: know which of Claude Code’s newer capabilities actually change how you do research — and which are just convenience — so you can reach for the right one instead of brute-forcing everything through a single chat.
Everything in Part I treated Claude Code as one assistant in one conversation. That mental model still works, but it leaves most of the 2026 feature set on the table. The releases over the last year added ways for the agent to fan work out, run it in the background, repeat it on a schedule, and enforce your rules automatically. Used well, these turn a one-paper workflow into a small research operation. Used carelessly, they multiply the number of places an unverified claim can hide. The recurring discipline of this handbook — bounded task, inspectable artifact, human owns the standard — matters more as autonomy goes up, not less.
The features below evolve quickly. Treat the exact flag names and defaults as a snapshot of mid-2026; type
/helpinside a session and read the changelog (claude changelogor the docs) when something behaves differently. The concepts are stable; the spellings drift.
A quick map of what to reach for:
| Capability | One-line use | When it earns its keep in research |
|---|---|---|
| Plan mode | See the plan before any file is touched | Risky refactors, anything that edits many files |
| Subagents | Hand a bounded job to a fresh context | Multi-reviewer checks, literature triage, isolating noise |
| Dynamic workflows | Fan out many subagents, coordinated, in the background | Repo-wide audits, bulk recoding, cross-checked synthesis |
| Self-paced loops / goals | Iterate until a condition holds | “Run until all tests pass / the table reproduces” |
| Background tasks | Long jobs without blocking the terminal | Full pipeline runs, big model calls |
Scheduled routines (/schedule) | Recurring chores on a clock | Daily new-paper digest, weekly data-quality check |
| Hooks | Shell commands fired on agent events | Enforce the data boundary; block destructive commands |
| Skills & plugins | Package a procedure once, reuse it | The scholar-* suite is a skill pack |
| MCP servers | Wire external tools/data into the agent | Zotero, a SQL database, the web, your reference manager |
| Worktrees | Isolated parallel checkouts | Try two analyses at once without collisions |
Plan mode — see the plan before any file changes
Press Shift+Tab to cycle permission modes; one of them is Plan mode. In it the agent may read, search, and reason, but it cannot edit files or run shell commands until you approve. It produces a written plan and waits.
> Shift+Tab (until the prompt shows "plan mode")
> Read the build-sample script and the variable dictionary, then propose a
plan to add a province-level fixed-effects robustness check. Do not write
anything yet.
For a researcher this is the cheapest insurance there is: you read the intended approach — which files, which estimator, which outputs — before a single line of your analysis changes. Approve it and the agent switches to execution; reject it and nothing was touched.
Subagents — hand a bounded job to a fresh context
A subagent is a separate Claude instance the main session delegates to. It runs in its own context window, with its own system prompt, an optional restricted tool list, and even its own model. The main conversation gets back only the subagent’s summary — not the 30 files it read to produce it.
You already rely on this without thinking about it: scholar-code-review (“six reviewers, one report”, §13) and the scholar-verify family (§15, Appendices F–J) work by dispatching specialist subagents in parallel. You can also define your own. Drop a file in .claude/agents/:
---
name: lit-triage
description: Screens papers for relevance to a stated research question and
returns a one-paragraph verdict with a citation. Use for bulk literature triage.
model: haiku
tools: Read, WebSearch, WebFetch
---
You screen one paper at a time against the research question.
Return: RELEVANT / MAYBE / NOT, one paragraph why, and the citation.
Never fabricate findings; if you cannot access the paper, say so.
Then just ask in plain language (“triage these 20 abstracts for the digital-divide question”) and Claude routes each to the lit-triage worker. Routing fast, repetitive jobs to haiku also keeps cost down. The rule from §1 still holds: a subagent’s summary describes what it intended to do — spot-check the artifacts, don’t trust the summary blindly.
Dynamic workflows — fan out, coordinated, in the background
This is the headline addition, and the one the workshop gets asked about most. A dynamic workflow is the agent planning and running a fleet of subagents for you: Claude writes a short orchestration script from your task description, then a runtime executes it — spawning many workers (independent units of the task), running a bounded number at once, and keeping the intermediate results in the script’s variables instead of dumping them all into your conversation. Your session stays responsive while it runs.
Where a single subagent is “do this one bounded job,” a dynamic workflow is “do this across hundreds of units and bring me the consolidated result”:
> Use a workflow: for every .R script under analysis/, check whether missing-value
codes (-1,-2,-8,-9,-10) are converted to NA before any model is fit. Return one
table: script, line, status. Run them in parallel and consolidate.
Good research fits for the pattern:
- Repo- or corpus-wide audits — every script, every variable, every figure caption checked the same way.
- Bulk transformations — recode or re-harmonize 500 files split into independent units.
- Cross-checked synthesis — have several workers investigate the same claim from independent angles, then reconcile, instead of trusting one pass.
Cost and caution. A workflow multiplies token spend by the number of workers it spawns. Always test on a narrow slice first — one directory, one wave, one question — confirm the output shape, then widen. And because there is no human in the loop mid-run, the stop-rule discipline from §5 is not optional: build the “if you cannot verify it, mark it” instruction into the task itself.
Self-paced loops and goal-driven runs
Two ways to say “keep going until you’re done” without babysitting:
/looprepeats a prompt. Give it an interval (/loop 5m check whether the job finished) for polling, or let it self-pace (/loop keep fixing the failing tests, iterating as needed) so the agent decides when to take the next pass.- A completion goal lets the agent take multiple steps across turns until a measurable condition is met — “until
Rscript 11-analyze.Rruns clean and the headline table matches Appendix G.”
These shine for the mechanical tail of analysis: reproduce a table, get a script to run end-to-end, drive a linter to zero. They are poor at fuzzy goals (“make the paper better”) — those never terminate cleanly, so keep the condition binary and checkable.
Background tasks and monitoring
Long jobs — a full pipeline, a big batch of model calls, a slow build — can run in the background while you keep working in the same session. The agent hands the job off, you get notified when it finishes, and you can check interim output instead of staring at a blocked terminal. For research this means the 40-minute data build and the manuscript edit you are doing now no longer block each other.
Scheduled routines — /schedule
/schedule creates recurring tasks that run on a clock (and, on the cloud/remote setup, persist after you close the terminal). You describe the cadence and the job in plain language:
> /schedule every weekday at 8am, search for new arXiv papers on "digital
inequality" and append a one-line summary of each to lit/inbox.md
Natural research uses: a morning new-paper digest, a Friday-night data-quality sweep, a monthly archive of logs. It bills against your usage and runs with whatever file access you grant, so scope it like any other agent task.
Hooks — make your data boundary an enforced rule, not a hope
§1 said the agent’s read boundary is your data boundary. Hooks let you enforce that mechanically. A hook is a shell command Claude runs automatically on an event — before a tool call (PreToolUse), after one (PostToolUse), at session start, and so on — and a PreToolUse hook can block an action. Configure them in .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{ "matcher": "Bash",
"hooks": [{ "type": "command", "command": ".claude/hooks/guard.sh" }] }
]
}
}
The script inspects the proposed command and exits non-zero (or returns a deny decision) to refuse it — for example, refuse any rm -rf, or any write outside data/processed/. This is how you turn “please don’t touch the raw data” from a polite request in CLAUDE.md into an enforced rule.
Enforced, but still cooperative: the harness runs your script and obeys its verdict, and a determined command can encode its way around a denylist (§6.4). The thing that is not cooperative is the sandbox.
The Bash sandbox — /sandbox, and its two modes
Claude Code ships an OS-level sandbox for the Bash tool. Where a hook asks, the sandbox enforces: the operating system refuses the open(), for the command and every child process it spawns, no matter how the path is spelled. macOS uses Seatbelt; Linux and WSL2 use bubblewrap. Native Windows is not supported — Windows participants run Claude Code inside WSL2 (Appendix K); WSL1 will not work either.
You do not have to hand-write JSON to turn it on. /sandbox opens a panel with three tabs:
| Tab | What it is for |
|---|---|
| Mode | How sandboxed commands get approved — the two modes below |
| Overrides | Whether a command that fails under the sandbox may be retried outside it. This is the allowUnsandboxedCommands setting; turn it off and the tab reads Strict sandbox mode |
| Config | The resolved settings after every scope has merged — read this rather than your own file, which is only one input |
A fourth tab, Dependencies, appears only when something is missing, and names which of ripgrep, bubblewrap, socat, or the optional seccomp filter your platform lacks. On Linux/WSL2, sudo apt-get install bubblewrap socat then restart — the dependency check runs at startup, so the panel will not notice an install until you do.
The two modes, specifically. Both enforce identical filesystem and network isolation. The only difference is whether you are asked.
| Mode | Behaviour |
|---|---|
| Auto-allow | A command that can be sandboxed runs with no prompt — the boundary replaces the prompt. Anything that cannot be sandboxed (a host you have not allowed, an incompatible tool) falls back to the normal permission flow. |
| Regular permissions | Every Bash command goes through the normal permission flow, sandboxed or not. Same wall, more approvals. |
Auto-allow is not “no questions asked”. Four things still stop you: explicit deny rules, always; rm/rmdir aimed at /, your home directory, or critical system paths; content-scoped ask rules such as Bash(git push *); and plan mode, where commands outside the built-in read-only set prompt regardless. Only a bare Bash (or Bash(*)) ask rule is skipped for sandboxed commands — and even that is not skipped in plan mode.
Choosing a mode in the panel writes to .claude/settings.local.json, so it applies to that project only. To sandbox everything you do, set "sandbox": {"enabled": true} in ~/.claude/settings.json.
The default that will surprise you — and it matters for restricted data. The sandbox’s default write scope is the working directory plus the session temp directory. Its default read scope is the entire computer, minus a few denied directories — which still includes
~/.sshand~/.aws/credentials. Turning the sandbox on does not protect your microdata. You get that wall only by addingsandbox.filesystem.denyRead, or asandbox.credentialsblock ("mode": "deny"for files;"deny"or"mask"for environment variables). Network access is the opposite default: no domains are pre-allowed, and the first time a command needs one you are prompted; approving it lasts the rest of the session.
Two more behaviours worth knowing before you rely on this as a safety control:
- The escape hatch. When a command fails because of sandbox restrictions, Claude may retry it with
dangerouslyDisableSandbox, which runs it outside the box through the normal permission flow. Setting"allowUnsandboxedCommands": falsemakes that parameter ignored entirely — this is what the Overrides tab calls Strict sandbox mode. - It fails open by default. If the sandbox cannot start — a missing dependency, an unsupported platform — Claude Code prints a warning and runs your commands unsandboxed. Set
"failIfUnavailable": trueto make that a hard failure instead. For a DUA-bound project, that is the setting you want.
Finally, a distinction the docs are emphatic about and which is easy to get backwards: /sandbox is not a permission mode (§3.1). A permission mode decides whether a call runs; the sandbox decides what it can touch once it does. They compose — and the sandbox’s auto-allow is a different mechanism from the permission system’s auto mode, which uses a classifier.
This is the same machinery /scholar-safety level lockdown configures for you (§6.6) — lockdown generates the OS sandbox config with denyRead over data/, which is why it is the only genuine containment boundary in the suite, and why it blocks your own Rscript too.
Skills and plugins — package a procedure once
A skill is a folder under .claude/skills/<name>/ with a SKILL.md that carries a procedure; its full text loads only when the skill is invoked (/<name>), so it costs no context until used. This is exactly what open-scholar-skill is — a pack of skills (scholar-init, scholar-design, scholar-verify, …). Plugins bundle skills, subagents, hooks, and MCP servers so a lab can share a whole toolkit with one install. The lesson for participants: when you find yourself re-typing the same multi-step instructions across projects, that is a skill waiting to be written.
MCP servers — connect Zotero, databases, and the web
The Model Context Protocol (MCP) lets the agent call external tools and data sources as first-class tools. Add one with claude mcp add … (or declare it in .mcp.json), then /mcp shows status and handles any sign-in.
$ claude mcp add --transport stdio zotero -- uvx zotero-mcp
For research this is the bridge to your reference manager, a results database, a notebook service, or a vetted web-search tool — so the agent pulls structured data directly instead of you copy-pasting it (and introducing transcription errors of exactly the kind §15 exists to catch).
Git worktrees — parallel experiments without collisions
A worktree is a separate working directory on its own branch. Claude Code can run a session — or isolate a subagent — in one, so two lines of work never overwrite each other’s files. Start one with claude --worktree try-province-fe; the agent develops there, and you merge the branch only if the experiment pays off. Ideal for “run the analysis two ways and compare” without polluting your main checkout.
Models, effort, and fast mode
Three dials worth knowing: /model switches between Opus (deepest reasoning), Sonnet (balanced), and Haiku (fast and cheap — good for subagents and triage); an effort setting trades thinking depth for speed and cost; and /fast (on recent Opus 4.x) returns answers noticeably quicker for routine work. A sensible default: Opus for design, analysis, and verification; Haiku for bulk mechanical subagent jobs. There is also /ultrareview, a user-triggered, billed multi-agent review of your current branch or a pull request — a heavier, independent second opinion than scholar-code-review.
A note on autonomy and verification
Every feature in this section moves work away from the single, watched conversation and toward fleets, schedules, and background runs. That is a real productivity gain and a real risk concentration: the more the agent does unattended, the more a wrong number can travel before a human sees it. So the workshop’s central lesson (§15) scales with these tools — the more autonomy you grant, the more non-negotiable verification and inspectable artifacts become. New capability, same contract: you own the question and the standard; the agent owns the execution.
One artifact makes this inspectable. Every /scholar-* run now leaves a Reasoning–Action–Observation (RAO) trace — an append-only logs/trace-<skill>-<date>.ndjson with one {reasoning, action, observation, refs, status} record per step. The process-log-*.md you read is a rendered view of that trace, and a coverage check red-fails any phase that left no trace behind. Dispatched subagents (reviewers, verifiers) emit a .trace.ndjson sidecar that the orchestrator folds in. Privacy rule: a trace records verdicts, counts, and file references only — never raw rows, quotes, or PII, and under LOCAL_MODE only derived aggregates.
PART II — OPEN SCHOLAR SKILLS, END TO END
This is the heart of the workshop. We build a Social Forces-style paper on the Chinese digital divide using only the open-scholar-skills suite. Every code block in this part is from a real run on May 4–5, 2026. Project slug: digital-divide-china-cfps.
The skills appear in the order you actually use them. But before the walkthrough, three things you need in front of you at all times: the complete inventory (§5B.1), the argument grammar every skill shares (§5B.2), and the artifact contract that makes the chain work (§5B.3).
5B. The suite at a glance — inventory, grammar, contract
5B.1 All 44 skills, by stage
The § column points at the section of this handbook documenting that skill in full — every mode, every argument, every gate, every file it writes.
◆ marks the nine skills that ship only in the extended edition (§2.4). On the public edition those commands do not exist; everything unmarked works identically on both.
The suite installs into ~/.claude/skills/<skill-name>/SKILL.md. Anything in that directory is invocable as /<skill-name>. Verify your install with:
$ ls ~/.claude/skills/ | grep -c scholar # 35 public · 44 extended
$ ls ~/.claude/skills/scholar-full-paper/ # SKILL.md, references/, scripts/
Stage 0 — set up and protect the project
| § | Skill | Use it for | First argument |
|---|---|---|---|
| §6 | scholar-init | Create the project tree, ingest files, run the local safety scan | init <slug> <files…> / review / add / status |
| §6 | scholar-safety | Scan a file, gate an operation, write the project safety protocol | scan / gate / protocol / status / level |
Stage 1 — find and sharpen the question
| § | Skill | Use it for | First argument |
|---|---|---|---|
| §7 | scholar-brainstorm | Ranked menu of 15–20 candidate RQs from codebooks, data, or a paper | a file path, DOI, or pasted abstract |
| §8 | scholar-idea | Turn one broad area into a specific puzzle with hypotheses | the rough idea, in prose |
| §8E | scholar-lit-review | Map the literature landscape (three depths) | topic + landscape / targeted / rapid |
| §8E | scholar-hypothesis | Formalize hypotheses and write the theory section | phenomenon or RQ |
| §8A | scholar-lit-review-hypothesis | Both of the above in one integrated chain | RQ or topic |
| §8B | scholar-conceptual | Build the theory object — typologies, mechanism diagrams | theorize / diagram |
| §8C | scholar-knowledge | The cross-project knowledge graph and wiki | ingest / search / relate / status / export / compile / ask / re-extract |
| §8F | scholar-rag | Local vector DB + GraphRAG over your whole reference library; MCP server | setup / ingest / query / mcp / graph / status |
| §20F | scholar-monitor | Delta-based current-awareness digests from journals and preprints | init / all / preview / digest |
Stage 2 — design before data
| § | Skill | Use it for | First argument |
|---|---|---|---|
| §8D | scholar-causal | Choose and justify an identification strategy; build the DAG | the causal question + variables |
| §9 | scholar-design | Lock estimand, model ladder, power, PAP, section blueprint | quant / qual / mixed / experiment / power / pap / computational / premortem / blueprint |
| §9A | scholar-data | Find or fetch data; design instruments; IRB; data-management plan | dataset / survey / interview / irb / manage / vignette / scrape / web / api |
Stage 3 — analyze
| § | Skill | Use it for | First argument |
|---|---|---|---|
| §10 | scholar-eda | Analytic sample, missingness, distributions, Table 1 | dataset path |
| §11 | scholar-analyze | The model ladder, publication tables, figures, results lock | data source + model spec |
| §11A | scholar-compute | Text-as-data, ML, networks, spatial, Bayesian, audio, sequences | text / network / ml / reproduce / spatial / bayesian / dsl / audio / life2vec |
| §11B | scholar-simulate | LLM-powered silicon sampling, generative ABM, synthetic experiments | design / personas / silicon-survey / generative-abm / experiment / validate |
| §11C | scholar-qual | Coding, thematic analysis, LLM-assisted coding, reliability | codebook / open-coding / axial / selective / thematic / content / llm-coding / mixed / reliability |
| §11D | scholar-ling | Sociolinguistics, phonetics, discourse, corpus, computational | variation / acoustic / corpus / CA / CDA / attitudes / contact / computational / experimental / MDA / TTS-guise |
| §11E | scholar-annotate | LLM-as-measurement over a text corpus, with a κ ≥ 0.70 gate before scale-out | plan / profile / codebook / devset / annotate-gold / optimize / validate / scale / distill / report / full |
| §13 | scholar-code-review | Six-agent audit of every analysis script | full or one lens |
Stage 4 — write and verify
| § | Skill | Use it for | First argument |
|---|---|---|---|
| §14 | scholar-write | Draft, revise, or polish any manuscript section | draft / revise / polish + section |
| §15 | scholar-verify | Two-stage, four-agent output↔manuscript↔prose verification | full / stage1 / stage2 / one agent |
| §16 | scholar-citation | Verify, insert, convert, materialize, retraction-check citations | insert / audit / convert-style / full-rebuild / verify / export / materialize / retraction-check / reporting-summary |
| §17 | scholar-polish | Style personalization without touching claims | scan / rewrite / full |
| §20G | scholar-exemplar-curate ◆ | Build the annotated paragraph-exemplar library scholar-write reads | zotero / top50 / user-work / review |
| §23A | scholar-openai | Independent Codex CLI review panel (read-only) | code / stats / logic / full / prose / custom |
Stage 5 — submit, share, and reuse
| § | Skill | Use it for | First argument |
|---|---|---|---|
| §18 | scholar-respond | Reviewer simulation, response letters, R&R packages | simulate / respond / revise / resubmit / cover-letter |
| §18 | scholar-journal | Journal fit ranking, format check, submission package | journal name + FULL-PACKAGE / FORMAT-CHECK / COVER-LETTER / SELECT-JOURNAL / RESUBMIT-PACKAGE |
| §18A | scholar-ethics | AI-use audit, plagiarism, integrity audit, disclosures | ai-audit / plagiarism / integrity / general / full |
| §19 | scholar-replication | Build, document, test, verify, archive the replication package | BUILD / DOCUMENT / TEST / VERIFY / ARCHIVE / FULL |
| §19 | scholar-open | Preregistration, data/code sharing, open-science package | PREREGISTER / DATA-SHARE / CODE-SHARE / FULL-PACKAGE / REPLICATION-PACKAGE |
Stage 6 — downstream products
| § | Skill | Use it for | First argument |
|---|---|---|---|
| §20 | scholar-presentation ◆ | Talks and print-ready conference posters (8 modes) | talk type |
| §20A | scholar-image ◆ | Decorative/conceptual figures via gpt-image-2 (never evidence) | generate / prompt / preview / list-venues |
| §20B | scholar-grant ◆ | NSF / NIH / RSF / Spencer proposals and mock review | nsf / nih / rsf / spencer / aims / budget / data-plan / review / compare / resubmit |
| §20C | scholar-teach ◆ | Syllabus-first course materials from your research | syllabus / lecture / discussion / assignment / exam / reading-list / slides / rubric / adapt |
| §20D | scholar-book ◆ | Monographs, edited volumes, textbooks, diss-to-book | proposal / outline / chapter / revise / assemble / diss2book / full |
| §20E | scholar-collaborate | CRediT roles, task delegation, team coordination | credit / tasks / communication / contributions / mentor / team-setup / conflict / meeting |
Orchestrators (Part III)
| § | Skill | Use it for |
|---|---|---|
| §21 | scholar-full-paper ◆ | The canonical gated chain, Phase −1 → Phase 12 |
| §22 | scholar-auto-research | The deterministic 21-phase teaching scaffold |
| §21A | scholar-resume ◆ | Read project state and emit the single next route |
| §22A | scholar-loop ◆ | Drive a queue of ideas unattended across /loop wakeups |
| §22B | scholar-auto-improve | Audit and evolve the skill suite itself |
5B.2 The argument grammar every skill shares
Each skill declares an argument-hint in its frontmatter. Read it before your first run:
$ head -8 ~/.claude/skills/scholar-design/SKILL.md
---
name: scholar-design
description: Plan a rigorous research design, run power analysis, ...
argument-hint: "[quant|qual|mixed|experiment|power|methods-section|pap|
computational|NLP|ML|network|ABM|premortem|blueprint]
[research question] [optional: data source, design type,
journal target]"
---
Three rules follow from that grammar:
- The first token is almost always a mode.
[a|b|c]means “pick exactly one.” If you omit it, the skill guesses from your prose — usually correctly, but guessing costs a turn and sometimes picks the wrong branch. Say the mode. - Bracketed
optional:items are keyword-ish, not positional.journal=Social Forcesandtarget Social Forcesboth work; the skills parse loosely. Preferkey=value— it survives copy-paste into scripts. - File paths are literal. Relative paths resolve against the directory Claude Code was launched in, not against
output/<slug>/. When in doubt, paste absolute paths.
A well-formed invocation names five things: mode, subject, data, journal, constraint.
> /scholar-analyze data=data/processed/cfps-panel-long.rds
outcome=y2_hours
predictors=hukou_rural,cohort,female,eduy
fe=province_x_wave
journal=Social Forces
An ill-formed one names one: > /scholar-analyze run the models.
5B.3 The artifact contract — why the chain holds together
The skills do not pass information to each other in the chat. They pass it through files on disk in output/<slug>/. That is the whole trick, and it is why you can stop, close your laptop, and resume three days later.
| Producer | Artifact | Consumers |
|---|---|---|
scholar-init | .claude/safety-status.json | every data-touching skill |
scholar-brainstorm / scholar-idea | selected-RQ memo | scholar-lit-review-hypothesis, scholar-design |
scholar-lit-review* | refs.bib, coverage matrix | scholar-write, scholar-citation |
scholar-rag | ~/.claude/scholar-rag/ (LanceDB index + graph), the rag_search MCP tool | scholar-lit-review, scholar-write, scholar-citation |
scholar-annotate | tables/…labeled.csv, codebook.md, validation_report.json | scholar-analyze, scholar-compute, scholar-write, scholar-replication |
scholar-causal | identification-memo.md (causal_status:) | scholar-design, scholar-write, scholar-verify, scholar-polish |
scholar-design | model-specs.json, variable-dictionary.csv, results-lock | scholar-eda, scholar-analyze, scholar-write |
scholar-analyze | tables/, figures/, results-registry.csv | scholar-verify, scholar-write, scholar-replication |
scholar-write | drafts/*.md with <!--anchor:--> comments | scholar-verify, scholar-citation, scholar-polish |
scholar-verify | verify/verification-report-<date>.md | you, and the Phase 7b gate |
| every skill | logs/process-log-<skill>-<date>.md | scholar-resume, scholar-auto-improve |
Two consequences you should internalize now:
- Deleting a file breaks the chain silently. If you
rmdesign/results-lock-*.md,scholar-writewill not error — it will draft from imagination. Verification is what catches this, which is why §15 is not optional. - You can run any skill standalone. Every skill in this part works on its own, against whatever files happen to be on disk. The orchestrators in Part III add gates and ordering; they add no capability the individual skills lack.
5B.4 The trace contract — every step, written down
Part I introduced the agent loop: Thought → Action → Observation. Every skill in the suite now writes that loop down, one append-only record per meaningful step, in logs/trace-<skill>-<date>.ndjson: the reasoning (why), the action (what it did), the observation (what came back), plus refs, status, and the dispatching agent’s id. The readable process-log-*.md you will see referenced throughout Part II is a rendered view of that file, never hand-written. A phase that produces no valid trace RED-fails its gate.
The honest bit — read this one carefully. The harness cannot log the model’s hidden chain of thought. What is recorded is the stated rationale — a short, articulable “why.”
So the trace is not evidence of what the model was thinking. It is evidence of what it said it was doing, next to what it actually did and what came back. That is the part you can audit, and it is the only part that was ever checkable. Treat any stronger reading of it as a claim you cannot support.
Two rules keep the trace shareable:
- Aggregates only.
reasoningandobservationcarry metrics, verdicts, counts and file paths — never data rows, quotes, or PII. Record that you saw something and what shape it had, not the value. - So where do the quotes live? Under
evidence/— the ledger in §8A.6. A trace step that captures an anchor cites it byanchor_id; it never inlines the passage. Two artifacts, one run, one deliberate split.
Sub-agents have no shell of their own, so they emit a .trace.ndjson sidecar that the orchestrator folds in — cross-checked against the dispatch manifest, so an agent cannot be quietly dropped from the record.
The same contract also archives code: every executed R/Python/Stata/Julia script — including LOCAL_MODE Rscript -e and python3 -c heredocs — is written verbatim into the project scripts/ directory with the skill’s numbering prefix and a run header. This is what makes §13.7’s “the reviewed bytes must be the executed bytes” auditable after the fact rather than at the moment of the run.
Projects pick this up automatically: scholar-init writes it into the project CLAUDE.md auto-rules block (§F in the lean profile, §14 in the full one), and existing projects refresh on the next run. Before this existed, a lean project running standalone skills loaded a CLAUDE.md with zero traceability rules and relied entirely on each skill remembering its own protocol.
6. scholar-init + scholar-safety — start with safety
Goal: create the standard project structure, classify every file, install the guard that enforces those classifications, and write the safety contract all later skills consult.
These two skills share the same machinery — the same scanner, the same anonymizer, the same sidecar file, the same PreToolUse hook. The division of labour is simple: scholar-init owns the project and the file classifications; scholar-safety owns operations, protocols, and enforcement strength.
6.0 The four modes of scholar-init
argument-hint: "[init <slug> <file1> <file2> ...] | [review] | [add <file1> ...]
| [status] — defaults to init if a slug-looking argument is
provided, review otherwise"
| Mode | Trigger | What it does |
|---|---|---|
| init | init as first token, or a slug-shaped string followed by file paths | Builds the directory tree, ingests raw files and materials, scans everything, writes the sidecar, README, .gitignore, and the project CLAUDE.md |
| review | review, or no arguments when the sidecar has unresolved entries | Walks every NEEDS_REVIEW file interactively and records a decision plus rationale |
| add | add as first token | Ingests new files into an existing project — scan + sidecar entry only, no rebuild |
| status | status | Read-only: prints the safety level and a status→count breakdown |
A slug must match ^[a-z][a-z0-9]*(-[a-z0-9]+)*$, 2–64 characters. If you hand the skill a topic description instead (“digital divide in China”), it will slugify it — downcase, drop stopwords, hyphenate, truncate to 48 characters — and ask you to confirm before building anything.
6.1 Run scholar-init
> /scholar-init init digital-divide-china-cfps \
~/data/cfps/raw \
--materials ~/data/cfps/materials
Flags accepted by the underlying scripts/init-project.sh:
| Flag | Effect |
|---|---|
--dest <dir> | Where to create the project directory (default: current directory) |
--link | Symlink raw inputs instead of copying them — use for multi-GB panel files |
--materials <path> | Route this path to materials/ instead of data/raw/ (repeatable) |
--corpus <path> | Route this path to corpus/ instead of data/raw/ — for text corpora (repeatable) |
--force | Rebuild over an existing project directory |
--forcedestroys prior review decisions. A rebuild rewrites the sidecar from a fresh scan, so everyOVERRIDErationale andLOCAL_MODEchoice you made is lost. Fix a broken init incrementally instead, unless you genuinely want to start over.
What it does, in order:
- Creates
<dest>/<slug>/withdata/{raw,interim,processed}/,materials/,output/,logs/,.claude/— pluscorpus/, but only if you passed--corpus, so non-corpus projects do not get an empty directory. - Copies (or, with
--link, symlinks) raw files intodata/raw/, materials intomaterials/, and text corpora intocorpus/. Name collisions get a numeric suffix. - Runs a local-only safety scan on every ingested file via
scripts/gates/safety-scan.sh—file,wc,grep,awkonly. Claude sees counts and pattern categories, never the matching values. - Writes
.claude/safety-status.json,logs/init-report.md,README.md,.gitignore. - Writes the auto-managed project-memory block into
CLAUDE.md(Claude Code host),AGENTS.md(Codex host), or both (host undetected). - If any file came back YELLOW or RED, transitions immediately into
reviewmode without asking.
Abridged terminal output from the real run:
[scholar-init] Creating project: digital-divide-china-cfps
[scholar-init] Ingesting 38 raw files from data/raw ... ok
[scholar-init] Ingesting 19 materials files ... ok
[scholar-init] Running safety scan ...
cfps2010adult_201906.dta : CLEARED (de-identified PIDs)
cfps2018crossyearid_202104.dta : CLEARED (cross-year ID file)
cfps2020person_202306.dta : NEEDS_REVIEW (location items, COVID)
CFPS_2020_QnrAdult_EN.pdf : CLEARED (codebook)
...
[scholar-init] Wrote .claude/safety-status.json
[scholar-init] Wrote logs/init-report.md
[scholar-init] DONE — 35 CLEARED, 3 NEEDS_REVIEW, 0 HALTED
Exit codes from init-project.sh, worth knowing when you script it: 0 success, 1 usage error (bad slug or missing file), 2 project directory exists without --force, 3 safety-scan.sh not found (your install is broken — run bash setup.sh in the skill repo).
6.1.1 The project CLAUDE.md that init writes
Step 5 above is easy to miss and matters a lot. scholar-init writes a lean project-memory profile — five sections, roughly 50 lines: the objectivity mandate, the data-safety stack and LOCAL_MODE scope, citation rules, and workflow rules. Every later Claude Code session in that directory reads it automatically.
If you later run /scholar-full-paper, the orchestrator upgrades that file to the full 13-section, ~230-line profile. The upgrade is one-way: re-running /scholar-init on an upgraded project prints already at v2-full ... lean request ignored and changes nothing. This is deliberate — a lean re-init must never silently strip the gate conventions the orchestrator depends on.
Idempotency messages you may see: created <path> (v2-lean), appended auto-rules block to <path>, migrated <path> from v1 to v2-lean, already at v2-lean, no-op.
6.1.2 Text corpora — --corpus and why the directory name is load-bearing
Linguistics and text-as-data projects usually keep a corpus outside data/, and until recently that meant it fell outside the guard too. It no longer does: corpus/ and corpora/ are gated path segments, so everything beneath them is treated as data regardless of extension — including extensionless files, and including the linguistics formats (.eaf, .TextGrid, .trs, .cha) that no extension rule would otherwise catch.
Ingest a corpus through the skill rather than dropping it in by hand. Ingesting is what earns those files a reviewed entry in safety-status.json; a corpus you merely copied in gets re-scanned live on every read instead.
> /scholar-init init hanyu-metalinguistic-corpus \
--corpus ~/data/hanyu/videos \
--corpus ~/data/hanyu/comments
A corpus is not one kind of thing, and the policy differs by what is in it:
| Corpus content | Put it in | OVERRIDE |
|---|---|---|
| Public text (news, parliamentary records, Wikipedia, published works) | corpus/<name>/ | allowed, with a rationale |
| Participant speech (sociolinguistic interviews, classroom recordings, elicitation) | corpus/transcripts/ or corpus/interviews/ | refused |
| Audio or video of any kind | anywhere under corpus/ | refused — by extension |
This works because the classifier matches on path segments, so the qualitative segments (transcripts/, interviews/, field-notes/, participants/, subjects/, respondents/) keep their strict treatment when nested inside corpus/:
corpus/news/article.txt gated, OVERRIDE allowed
corpus/transcripts/i01.txt gated, OVERRIDE refused
corpus/recordings/s1.wav gated, OVERRIDE refused (extension rule)
The name is an exact segment match.
mycorpus/,corpus-2024/,texts/,speeches/, andtweets/are not gated. Name the directory exactlycorpus/orcorpora/, or keep the material underdata/raw/. This is the kind of rule that looks pedantic until the day a directory calledtranscripts-2024/sits one rename away from protection.
6.2 Resolve NEEDS_REVIEW with scholar-init review
You cannot advance to brainstorming or analysis until every file is resolved. The guard will block the reads.
> /scholar-init review
Claude walks each NEEDS_REVIEW item interactively — re-running the scanner for live detail, and never reading the file itself to “help decide.”
File: cfps2020person_202306.dta
Reasons flagged:
- Contains community-level codes (ck01, ck02) below-county granularity
- Contains COVID-related items that may be sensitive
Options:
[c] CLEARED - Claude may read directly
[l] LOCAL_MODE - Claude may invoke R/Python loaders that compute
summaries, but raw rows never enter context
[a] ANONYMIZED - Replace with derived/aggregated file before reading
[o] OVERRIDE - Claude may read directly; you log a written rationale
[h] HALTED - File is off-limits for this project
Choice [c/l/a/o/h]:
The option set is not the same for every file. The skill classifies each file as structured or qualitative — by extension (.wav .mp3 .flac .m4a .mp4 .mov .eaf .textgrid .cha …) or by path (a .txt/.docx/.md living under transcripts/, interviews/, field-notes/, participants/, respondents/, materials/):
| File type and level | Options offered |
|---|---|
| Structured/tabular, RED | LOCAL_MODE · ANONYMIZE · OVERRIDE · HALT |
| Qualitative, RED | LOCAL_MODE · ANONYMIZE · HALT — OVERRIDE is never offered |
| Anything, YELLOW | The above plus a one-click CLEARED |
| Anything, RED | CLEARED is never offered |
The qualitative-OVERRIDE refusal is enforced twice — once in this menu, and again inside the PreToolUse guard itself, so hand-editing the sidecar does not get you past it.
Choosing OVERRIDE requires a typed rationale of at least 20 characters. “n/a”, “ok”, and “false positive” alone are rejected; the prompt blocks until you write something real or cancel. The rationale lands in logs/init-report.md under Decision history, with the prior status, new status, and who decided.
Choosing ANONYMIZE runs python3 scripts/gates/anonymize-presidio.py anonymize <file>. Three things to know:
- Output goes to
output/qual/anonymized/ANON_<basename>— never next to the original — alongsidepseudonym-key-DO-NOT-SHARE.csv. - If Presidio finds no PII it exits 0 without writing a file. The original stays
NEEDS_REVIEW; nothing is auto-cleared. - The
ANON_file is re-scanned. Only if it comes back GREEN does the original becomeHALTEDand the anonymized copy becomeANONYMIZED. Still YELLOW or RED and you are back in the loop. - Presidio is optional for scanning (there is a regex fallback) but mandatory for anonymizing. Without
presidio-analyzer,presidio-anonymizer, andspacy+en_core_web_lg, this option dies with anImportErrorand your only valid choices are LOCAL_MODE or HALT.
For CFPS we typically choose LOCAL_MODE for any wave-level person file: scripts can load the data and produce summary counts, regression tables, and figures, but the raw row values never reach Claude’s context window. This is a real privacy boundary, not a slogan — §6.5 spells out exactly what LOCAL_MODE permits.
Changes need a restart. Claude Code snapshots hook configuration at session start. After a
reviewpass that changes statuses, restart Claude Code before expecting the guard to honour the new values. Under Codex, the project must be trusted before the hook activates at all; until thenAGENTS.mdinstructs the agent to self-enforce against the sidecar.
6.3 Inspect safety-status.json
$ jq . .claude/safety-status.json | head -30
{
"_safety_level": "standard",
"/Users/you/digital-divide-china-cfps/data/raw/cfps2010adult_201906.dta": "LOCAL_MODE",
"/Users/you/digital-divide-china-cfps/data/raw/cfps2018crossyearid_202104.dta": "CLEARED"
}
The sidecar is a flat map — an absolute file path → a status string — plus the single meta key _safety_level. The full status vocabulary, validated by scripts/gates/sidecar-schema.sh:
| Status | Meaning for the agent |
|---|---|
CLEARED | May Read directly |
ANONYMIZED | May Read directly (this is the de-identified derivative) |
OVERRIDE | May Read directly; a written rationale exists in the init report |
LOCAL_MODE | May not Read; may run summary-only loaders via Bash |
HALTED | Off-limits entirely |
NEEDS_REVIEW / NEEDS_REVIEW:<LEVEL> | Blocked until /scholar-init review resolves it (LEVEL ∈ GREEN/YELLOW/RED/UNKNOWN) |
Two schema violations that fail the guard closed, so they are worth avoiding: an object-valued entry (the value must be a bare string), and a relative-path key. The lookup has no relative-path or basename fallback. A hand-written {"foo.csv": "OVERRIDE"} is silently ignored, and moving the project directory invalidates every entry in the file.
Every later skill reads this file before touching data. If the status is LOCAL_MODE, the analysis script must enforce summary-only loading — and scholar-analyze will refuse to print raw rows.
6.4 The guard — what actually enforces this
The classification is only as good as the thing that enforces it. That is scripts/gates/pretooluse-data-guard.sh, registered as a Claude Code PreToolUse hook in ~/.claude/settings.json (and mirrored into <proj>/.codex/config.toml for Codex hosts). It intercepts Read, NotebookRead, NotebookEdit, Grep, Glob, Bash, Edit, Write, and MultiEdit. Exit 0 allows; exit 2 blocks and hands the refusal reason back to Claude.
What it does, channel by channel:
- Read channel. Canonicalizes the path (resolving symlinks), refuses anything resolving into a system directory (
/etc,/dev,/proc,/sys,/System,/var/db,/var/log), then consults the sidecar:CLEARED/ANONYMIZED/OVERRIDE→ allow;LOCAL_MODE/HALTED→ block with a hint to use a Bash loader;NEEDS_REVIEW*→ block and tell you to run/scholar-init review. - Bash channel. A cooperative speed-bump, not a wall. It blocks the obvious dump verbs —
cat,head,tail,less,od,xxd,strings,base64,sqlite3,jq,sed,awk,perl, andgrepwithout-c/-l/-q— when they target a sensitive path. On ambiguity it fails open, because bricking the shell is worse than the marginal leak it would prevent. - How the Bash channel decides what “the target” is. Two rules, both added in July 2026 after the original shape-matching classifier proved wrong in both directions. (a) A token is classified only if it resolves to something that exists — file or directory. This kills a whole family of false positives: a regex handed to grep (
grep -nE "data/raw|materials/" script.sh) is no longer read as a sensitive target, and one such block had been stopping the very command used to check whether that directory existed. Declining to classify a nonexistent path cannot open a leak, because this is a read gate and a dump verb aimed at nothing reveals nothing. Globs are rewritten to their literal directory prefix, since a glob can only reach files underneath it. (b) Variables are expanded before classification. Tokens containing$used to be skipped as unresolvable, soSP=/abs/proj; grep x "$SP/corpus/transcripts/i01.txt"evaded the gate outright. A tokenizer pass now resolves$VARand${VAR}from assignments made in the same command, plus a small ambient-environment allowlist. That scope is exactly right: Claude Code starts a fresh shell per Bash call, so a variable neither assigned in-command nor exported expands to empty and cannot address a file at all. - Grep/Glob channels. Blocks searching or enumerating raw-data paths, and any direct target with a data extension.
- Which paths count as data. Segment matching, not extension matching:
data/raw/,data/interim/,data/processed/, and — since July 2026 —corpus/andcorpora/(§6.1.2), plus the qualitative segmentstranscripts/,interviews/,field-notes/,participants/,subjects/,respondents/, which additionally refuseOVERRIDE. - Edit/Write/MultiEdit. Guards exactly one thing: writes to
.claude/safety-status.json. It refuses to promote a RED or HALTED path to CLEARED/OVERRIDE unless/scholar-init reviewprovenance exists inlogs/init-report.md. Everything else fails open. - Images. Pixels cannot be grep-scanned, so images are classified by path: inside
data/raw/→ blocked; insideoutput/figures/→ allowed.
Failure behaviour is deliberately asymmetric: if jq is missing, the read channels fail closed (blocked, with an install-jq message) while the Bash/Edit/Write channels fail open. An abnormal script termination is converted into a block by an EXIT trap whenever the target had already been classified as data-risk.
The footgun that silently disables everything. If the hook’s
commandpath contains a space — and it will, if you installed under~/Library/CloudStorage/GoogleDrive-…/My Drive/…— both Claude Code and Codex fail to execute it, with no visible error. The guard becomes globally inert. Register it wrapped in quotes:{ "command": "bash '/Users/you/My Drive/open-scholar-skills/scripts/gates/pretooluse-data-guard.sh'" }Verify with a deliberate probe: ask Claude to
Reada file you know isHALTED. If it succeeds, your hook is not wired up.
6.5 The LOCAL_MODE contract
LOCAL_MODE is the workhorse status for real survey data, so learn its rules. The analysis runs as one Rscript -e or python3 -c heredoc per analysis, and only aggregate output may come back:
| Allowed back into context | Forbidden |
|---|---|
Dimensions (dim, nrow) | head(), print(), tail(), View(), slice(), sample_n() |
| Variable names and classes | Any row-level value |
| Missingness percentages | Any free-text field content |
summary() output | Any cell with n < 10 (small-cell suppression) |
| Coefficients, SEs, p-values, AIC/BIC | Figures embedded inline when the data is sensitive |
Counts, but only where n ≥ 10 | — |
Intermediate files written by a LOCAL_MODE script must be saved to data/interim/ or data/processed/ and are auto-registered as LOCAL_MODE in the sidecar — derived data inherits the constraint rather than escaping it.
6.6 scholar-safety — the six modes
argument-hint: "[scan|gate|protocol|status|level] [file path / operation
description / level name] [optional: data type, project name,
journal target]"
| Mode | Trigger | What it does |
|---|---|---|
| scan | scan, check, audit + a path | Local pattern scan of one file; classifies 🟢 LOW / 🟡 MEDIUM / 🔴 HIGH |
| gate | gate, before, about to, going to read/load | Extracts the file(s) from a described operation, scans each, then HALTs, pauses, or proceeds |
| protocol | protocol, plan, data handling plan | Writes a full project data-safety protocol document |
| status | status, log, what was shared, history | Formats the running safety log |
| level | level + standard/strict/lockdown | Sets _safety_level; for lockdown, generates an OS sandbox config |
| full-paper-gate | auto-invoked by scholar-full-paper Phase −1 | Scans every data path in the pipeline arguments, fail-closed, writes a consolidated gate report |
> /scholar-safety scan data/raw/cfps2020person_202306.dta
> /scholar-safety gate "about to read data/interviews.txt for coding"
> /scholar-safety protocol digital-divide-china-cfps journal="Social Forces"
> /scholar-safety status
> /scholar-safety level strict
The critical operating rule, stated in the skill itself: never Read a flagged file until the user explicitly selects PROCEED or OVERRIDE — and note that LOCAL MODE is the opposite of Read permission and must never trigger a Read.
6.6.1 What the scanner actually looks for
The scan counts pattern hits across: SSNs; names; emails; phones; street addresses; ZIP codes; IP addresses; health and HIPAA markers; mental-health items; legal and immigration items; financial fields; restricted-dataset markers (NHANES, PSID, NLSY, IPUMS, Census RDC, DUA, “confidential”); international restricted-dataset markers (UK Biobank, ALSPAC, NHS Digital, SOEP, EU-SILC, CFPS, CHARLS, CGSS, CLHLS, IHDS, JGSS, Understanding Society, KLoSA, plus SHARE / HILDA / Add Health matched case-sensitively); IRB and participant markers; and fine geographic granularity.
The classification matrix, abridged to the rows you will actually hit:
| Condition | Level |
|---|---|
| Any SSN hit, or >5 emails / phones / addresses | 🔴 HIGH |
| Any health, mental-health, or legal marker | 🔴 HIGH |
| Any restricted-dataset marker (this is why CFPS files flag) | 🔴 HIGH |
| Names present and IRB markers present | 🔴 HIGH |
| IRB markers alone; or 1–5 emails/phones; or ZIP only | 🟡 MEDIUM |
| Non-plaintext file, regardless of hit count | 🟡 MEDIUM (floor) |
| No pattern hits and a plaintext scan actually ran | 🟢 LOW |
Two fail-closed rules make this trustworthy. A missing, unreadable, or directory target returns SCAN-ERROR at 🔴 HIGH — never LOW. And a binary file floors at 🟡: a clean regex pass over a .dta, .sav, .rds, .xlsx, .parquet, or .sqlite file is not evidence of safety, because the scanner cannot read the container. This is exactly why CFPS .dta files land in review rather than sailing through.
6.6.2 The three safety levels — and what each actually guarantees
> /scholar-safety level lockdown
| Level | What is enforced | Honest guarantee |
|---|---|---|
| standard (default) | Bash speed-bump + sidecar tamper guard | Stops accidental leakage. Does not stop a determined agent. |
| strict | The above + a PostToolUse output redactor | Active only if posttooluse-output-guard.sh is registered in ~/.claude/settings.json and the sidecar has at least one restricted entry. |
| lockdown | The above + a real OS sandbox with deny-read on data/ | The only genuine containment boundary in the system. |
The skill verifies the redactor is really registered before claiming strict protection, rather than reporting a level it cannot deliver.
Lockdown has a sharp edge worth planning around: denyRead on data/ blocks all reads of that directory — including the sanctioned LOCAL_MODE Rscript/python3 loader. Either run your analysis first and lock down afterwards, or generate the config with --allow-escalation so human-approved unsandboxed commands can still run.
What lockdown is, underneath. It writes the configuration for Claude Code’s own Bash sandbox (§5A) — the same Seatbelt/
bubblewrapmachinery you can drive by hand with/sandbox. Two consequences follow. First,--allow-escalationis the suite’s name for leavingallowUnsandboxedCommandson; omitting it is what the/sandboxOverrides tab calls Strict sandbox mode. Second, everything the sandbox does not do by default still applies here: read access defaults to the whole machine, so thedenyReadoverdata/is doing all the work, and if the sandbox cannot start at all, Claude Code warns and runs unsandboxed unlessfailIfUnavailableis set. If your DUA requires containment, verify the level rather than assuming it —/scholar-safety status, then a deliberate probe on a file you know isHALTED.
Everything below lockdown is evadable in principle — by another interpreter (ruby, node), by an encoding (base64, gzip, hex), by assembling the path from shell variables, or by copying the file to a benign path and reading that. The suite documents this openly rather than pretending otherwise. Design your workflow so that the honest path is also the easy path, and reserve lockdown for data where the DUA genuinely requires containment.
6.7 The scripts you can run yourself
Every gate is a plain shell or Python script. You do not need Claude in the loop to use them, and running them by hand is the fastest way to build trust in the system:
| Script | Purpose |
|---|---|
scripts/init-project.sh [opts] <slug> [inputs…] | The whole project bootstrap, standalone |
scripts/gates/safety-scan.sh <file> | GREEN/YELLOW/RED scan; exit 0 / 2 / 1 |
scripts/gates/anonymize-presidio.py {scan\|keygen\|anonymize\|verify} <file> | Presidio PII detection and anonymization |
scripts/gates/generate-lockdown-config.sh <proj> [--host auto] [--allow-escalation] | Emit the OS sandbox config for lockdown |
scripts/gates/sidecar-schema.sh | Validate the sidecar against the status vocabulary |
scripts/gates/pretooluse-data-guard.sh | The guard itself — feed it a crafted JSON payload on stdin to test |
6.8 Inspect
logs/init-report.md— the ingested-files table, the scan-level counts, and the append-only Decision history..claude/safety-status.json— every key an absolute path, every value one of the seven status strings.README.md— auto-generated, and genuinely worth reading once: it contains the decision-flow diagram and the effects table for each status.CLAUDE.md— confirm the auto-managed block is present and saysv2-lean(orv2-fullafter an orchestrator run).
Stop and check. Point at one file marked LOCAL_MODE and say, out loud, (a) why it was flagged, (b) what a script may still compute from it, and (c) what would happen if you asked Claude to head it. If you cannot answer all three, do not brainstorm yet.
7. scholar-brainstorm — widen the question menu
Goal: produce a ranked list of candidate research questions, each with variables, method sketch, and risks. Do not ask brainstorming to pick your dissertation; ask it to widen the menu.
7.0 Three modes — auto-detected from your inputs
scholar-brainstorm operates in three modes and chooses one automatically based on what you point it at:
| Mode | Triggered by | What you get |
|---|---|---|
| MATERIALS | Codebooks, questionnaires, data dictionaries (.pdf / .md / .txt / .docx) — no raw data file | Theory-driven ranking: 15–20 candidate RQs, scored on 5 criteria (novelty, data readiness, theory, identification, publication potential). No empirical signal tests. |
| DATA | Raw data files (.csv / .dta / .rds / .sav / .xlsx / .parquet) | Theory-driven ranking plus empirical signal tests: actual bivariate effects (Cohen’s d, η², Cramér’s V, r) computed on your data, scored on 6 criteria (the 5 above + a 20% empirical-signal weight). |
| PAPER | A published paper PDF, a DOI, or a pasted abstract | A “follow-up paper” generator: extracts the seed paper’s findings + limitations + future directions, optionally calls SciThinker-30B for AI-generated ideation, then expands into 15–20 follow-up RQs scored on the 5-criterion grid. |
The auto-detection looks at file extensions and (for PDFs) at content — a PDF with “Abstract / Introduction / Methods / References” is classified as PAPER; a PDF with “Variable / Codebook / Questionnaire” as MATERIALS.
All three modes share the same downstream pipeline: literature scan → Top-10 shortlist → 5-role evaluation panel (five Task-dispatched evaluator prompts — theorist, methodologist, domain expert, editor, devil’s advocate — internal to scholar-brainstorm; these are skill-internal roles, not entries in .claude/agents/) → refined Top-10 → research program overview → executive summary. Only Steps 0–4 differ.
The CFPS digital-divide example uses MATERIALS mode. We walk through that first, then show how the same project would look in DATA and PAPER modes.
7.1 MATERIALS mode — start from a codebook
Use this when you have codebooks or questionnaires but the raw data is not yet ingested — either because access is pending, or because you deliberately want a theory-driven menu before touching the data.
7.1.1 Run
> /scholar-brainstorm materials top 5 RQs on digital divide in China,
target Social Forces, descriptive/decomposition
The skill detects MATERIALS mode (codebooks present, no data/raw/ opened directly), reasons over the questionnaires and the variable dictionary, and queries verified sources. About 4–7 minutes on a typical run. Cost in this run: ≈ $1.20.
7.1.2 Real output (truncated)
From output/digital-divide-china-cfps/ scholar-brainstorm- digital-divide-china-cfps-top5-summary-2026-05-05.md:
# Research Question Brainstorm — Executive Summary
## Digital Divide in China Using CFPS Materials
*Generated by /scholar-brainstorm on 2026-05-05*
*Operating mode: MATERIALS*
## Top 5 RQs
### #1: Access Convergence, Use Divergence
**RQ:** In China from 2010 to 2020, did the hukou, education, and cohort gaps
in internet access narrow while gaps in productive use, use intensity, and
use breadth persisted or widened?
**Variables:** U201, U202, U250M, U701-U705, hukou, education, cohort,
gender, income, household composition.
**Why strongest:** Best flagship paper. Uses CFPS panel structure to separate
first-level access from second-level productive use.
**Method sketch:** Panel models, wave/province controls, individual fixed
effects where feasible, Oaxaca decomposition of rural-hukou gaps.
### #2: Remote-Work Divide During COVID-19 […]
### #3: Online-Learning Outcome Divide […]
### #4: Older-Adult Digital Health and Social-Connection Divide […]
### #5: Information Trust, Privacy Concern, and Platform Dependence […]
## Recommendation
Pursue RQ1 as the main paper. […]
7.1.3 Files written (MATERIALS mode)
output/<slug>/
├── scholar-brainstorm-<slug>-<date>.md ← full report (15–20 candidates)
├── scholar-brainstorm-<slug>-summary-<date>.md ← exec summary (Top 5 + recommendation)
└── logs/process-log-scholar-brainstorm-<date>.md
Plus a .docx, .tex, and .pdf of each (rendered via pandoc).
7.1.4 Inspect
Open the full file. Check four things:
- Variable claims — does CFPS actually have
U201,U250M? (Use the codebook.) - Verified sources — every external citation should resolve. Click them.
- Risks surfaced — for RQ5 the brainstorm correctly notes “some 2020 items are restricted data”. Good.
- Over-broad RQs — RQ4 (“does internet use improve health among older adults”) is too broad. The output flags this honestly.
Stop and check. Choose one RQ to carry forward. The rest of the handbook follows RQ1, because it is feasible, theoretically connected, and measurable.
7.2 DATA mode — start from the data itself
Use this when the raw data is already on disk and resolved by scholar-init. DATA mode adds two things that MATERIALS mode cannot:
- A safety gate — before reading anything, the skill checks
.claude/safety-status.json(the sidecarscholar-initwrote). If any input file isNEEDS_REVIEW:*orHALTED, the skill refuses to run and tells you to fix it via/scholar-init review. If the sidecar is missing, the skill falls back to agrep-only local scan that emits only counts of PII / HIPAA / restricted markers — never the matching values. - Empirical signal tests — for each of the 15–20 candidate RQs, the skill writes one R script (
scripts/brainstorm-signal-tests.R), submits it to a 3-agent pre-execution code review, then runs it. Each candidate gets a real bivariate effect size (Cohen’s d for continuous outcomes, η² for ANOVA, Cramér’s V for cross-tabs, Pearson’s r for correlations) and a signal rating: STRONG, MODERATE, WEAK, NULL, MECHANISM PLAUSIBLE, MODERATION DETECTED, or UNTESTABLE.
The Top-10 score then weights these six criteria — novelty 20%, data readiness 15%, theory 20%, identification 15%, publication potential 10%, empirical signal 20% — instead of the 5 criteria used in MATERIALS / PAPER mode.
7.2.1 Run (the version we would have used on the CFPS example)
> /scholar-brainstorm data/raw/cfps_panel_long.rds
top 5 RQs on digital divide in China,
target Social Forces
If scholar-init had already classified the file as LOCAL_MODE, the skill inherits that decision (the “scholar-init handshake”) and runs all empirical tests via Rscript brainstorm-signal-tests.R heredocs — Claude itself never Reads the data.
7.2.2 What you would see — the signal table
A typical DATA-mode signal table looks like this:
EMPIRICAL SIGNAL TABLE (sample sizes from cfps_panel_long.rds)
| RQ | x_var | y_var | test | n | effect_size | p | signal |
|----|-------------|-------------|--------|-------|------------------|---------|----------|
| 1 | hukou_rural | y2_hours | t-test | 119k | d = -0.42 (med.) | 1.4e-5 | STRONG |
| 1 | cohort | y1_access | χ² | 148k | V = 0.31 (med.) | <1e-60 | STRONG |
| 2 | mobile_only | covid5 | t-test | 34k | d = +0.18 | 4.2e-3 | MODERATE |
| 4 | u703_social | sf12_mh | r | 41k | r = +0.11 | 7.8e-4 | WEAK |
| 5 | u11_wechat | u13_trust | r | 26k | r = +0.08 | 0.04 | WEAK |
Caveats the skill prints alongside the table (verbatim):
- Signals are bivariate-only — confounding is not addressed here.
- Multiple-testing corrections are NOT applied at this stage; do not treat any single p as a confirmatory test.
- NULL is not the same as “uninteresting” — it can mean the gap is mediated by other variables.
7.2.3 The pre-execution code review
Before any Rscript actually executes, the skill spawns three review agents in parallel against the signal-test script:
review-code-correctness— variable references, NA handling, off-by-onereview-code-statistics— correct test for the variable types, effect-size package usagereview-code-data-handling— sample restrictions, missing-value codes, codebook alignment
Their output is aggregated into scripts/brainstorm-signal-tests-review.md with severity tags. The execution gate has four resolutions:
- PROCEED — no CRIT/MAJOR findings; run the script.
- FIX-AND-RERUN — fix the flagged issues, re-review, then run.
- OVERRIDE — user types a rationale ≥ 20 chars; logged to the process log.
- HALT — stop the skill; no candidate is worth running as-is.
This means DATA mode produces a real audit trail before any data is touched — exactly the discipline the workshop teaches.
7.2.4 Files written (DATA mode)
In addition to the two MATERIALS-mode files, DATA mode also writes:
output/<slug>/scripts/
├── brainstorm-signal-tests.R ← the actual R script (auditable)
├── brainstorm-signal-tests.log ← stdout from running it
├── brainstorm-signal-tests-review.md ← aggregated 3-agent review
├── brainstorm-signal-tests-review-correctness.md
├── brainstorm-signal-tests-review-statistics.md
└── brainstorm-signal-tests-review-data-handling.md
Replication-ready by design — scholar-replication will pick these up automatically later.
7.2.5 Inspect (DATA mode adds two checks)
In addition to the four MATERIALS-mode checks, also verify:
- The signal-test script is real R, not pseudocode. Open
scripts/brainstorm-signal-tests.R, runhead -40on it. Every test should be wrapped intryCatch()so one failing candidate does not crash the run. - Effect sizes use proper packages. The script must use
effectsize::cohens_d(),effectsize::eta_squared(),effectsize::cramers_v()— not hand-rolled formulas.
Stop and check. Look at the signal table above. Would you treat the WEAK signal on RQ5 as “this hypothesis is dead”? No — it might just mean the test is bivariate and needs covariates. The signal is one input to the Top-10 score, not a verdict.
7.3 PAPER mode — start from a published paper
Use this when you’ve read a paper and want a structured menu of follow-up projects: methodological extensions, population transfers, mechanism deepening, limitation address-als, or computational upgrades.
PAPER mode is triggered three ways:
# (a) PDF on disk
> /scholar-brainstorm ~/papers/li-ouyang-hu-2025-digital-divide-aging.pdf
# (b) DOI string
> /scholar-brainstorm 10.1038/s41746-025-02076-1
# (c) Pasted abstract (just paste a "Title: ... Abstract: ..." block in the chat)
> /scholar-brainstorm
> Title: A ten-year analysis of digital divides among older Chinese adults
> Abstract: Using six waves of CFPS we document persistent age-related gaps in [...]
7.3.1 What the skill does
- Extract the seed paper’s elements — title, abstract, core findings, methods used, limitations the authors acknowledge, future directions they suggest, theoretical framework, population/context, data source. (For DOIs the skill calls the CrossRef API; for PDFs it uses
pdftotext; for pasted abstracts it parses inline.) - (Optional) SciThinker ideation — if
HF_TOKENis set in the environment, the skill callsOpenMOSS-Team/SciThinker-30Bon HuggingFace with a structured prompt asking for one follow-up paper title + abstract. IfHF_TOKENis missing or the call fails, the step is logged asSKIPPEDand the run continues with Claude-only ideation. - Claude expansion — generate 15–20 candidate follow-up RQs across eight dimensions:
| Dimension | Strategy |
|------------------------|-------------------------------------------------------|
| Methodological extension | Apply a stronger / different method to the same Q |
| Population transfer | Same Q, different population or context |
| Mechanism deepening | Test the proposed mechanism directly |
| Limitation address-al | Tackle a limitation the original authors named |
| Scope expansion | Broaden to a related phenomenon |
| Contradictory test | Design a study that could falsify the finding |
| Computational upgrade | Apply NLP/ML to reveal patterns the original missed |
| SciThinker proposals | Refine and ground the AI-generated ideas in theory |
- Standard pipeline — every candidate goes through literature scan → Top-10 shortlist → 5-agent evaluation panel → refined Top-10 → research program overview, identical to MATERIALS / DATA mode.
7.3.2 What you would see for the CFPS digital-divide seed
If you ran PAPER mode on Li, Ouyang, & Hu (2025), the kinds of follow-up RQs you would expect to see:
#1 (Mechanism deepening) — Does household digital transmission (co-resident
young-adult presence) attenuate the age-related digital divide identified
by Li et al.? CFPS family-conf links + intra-household FE.
#2 (Population transfer) — Does the same age × digital exclusion pattern hold
in the rural migrant population, where hukou + age compound? CFPS migrant
sub-sample.
#3 (Limitation address-al) — The seed paper notes it cannot separate cohort
from age. Apply HAPC + Deaton-Paxson bounds to the same panel.
#4 (Methodological extension) — The seed paper uses descriptive trends.
Apply Oaxaca-Blinder decomposition to the rural-urban Y2 gap to separate
endowment from coefficient components.
#5 (Computational upgrade) — Use STM topic models on CFPS open-text items
about internet use to identify use-type heterogeneity that the closed
items cannot.
(If you had scoped the digital-divide focal paper from a seed paper instead of from the CFPS codebook, this is the shape PAPER mode would have produced — treating Li et al. as the seed and identifying the second-level / institutional gap as the unfilled lane. The actual workshop run used MATERIALS mode, per §7.1.)
7.3.3 Files written (PAPER mode)
output/<slug>/
├── scholar-brainstorm-<slug>-<date>.md ← full report
├── scholar-brainstorm-<slug>-summary-<date>.md ← exec summary
└── logs/
├── process-log-scholar-brainstorm-<date>.md
└── scithinker-response-<date>.txt ← raw SciThinker output if called
7.3.4 Inspect (PAPER mode)
Use the four MATERIALS-mode checks, plus:
- Connection to the seed. Each candidate should explicitly say which seed-paper element it extends (a finding? a limitation? a stated future direction?). If a candidate cannot cite a specific anchor in the seed, it is hallucination, not extension.
- SciThinker grounding. If SciThinker was called, its proposals appear flagged. They are seed ideas, not finished RQs. Treat them as Claude treats them — refine, theorize, and ground them before scoring.
Stop and check. PAPER mode is the easiest mode to misuse: it is tempting to take its top-ranked follow-up and start writing. Don’t. Run the chosen candidate back through scholar-idea (§8) and scholar-design (§9) before committing — PAPER mode is a menu generator, not a design.
8. scholar-idea — sharpen the puzzle
Goal: turn an area into a specific puzzle, with mechanisms, scope conditions, hypotheses, and a fatal-flaw screen.
8.1 Run
> /scholar-idea broad puzzle: "China's digital divide — access converging
while use intensity persists by hukou, cohort, and gender"
data: CFPS 2010-2020 long panel
target: Social Forces
8.2 Real output (excerpt from idea/scholar-idea-...md)
## Step 1 — The Puzzle
China entered 2024 with the world's largest internet user base (1.07 billion
CNNIC), yet remains a textbook case of *layered* digital inequality. The
first-order access gap has narrowed sharply since 2015, but second-order
(skill, autonomy of use) and third-order (returns to use) gaps appear to
have widened — particularly along hukou, generational, gender, and
educational lines.
## Step 2 — Candidate Angles
| # | Framing | Mechanism | Rival explanation |
|---|------------------------|---------------------------------|-----------------------|
| A | Hukou as durable axis | Institutional sorting | Pure SES absorbs hukou|
| B | Cohort-as-cause | Birth-cohort socialization | Period effects |
| C | Household as skill unit| Intra-household spillovers | Selection |
| D | Gender × age × hukou | Triple penalty | Additive only |
| E | Returns to engagement | Capital-conversion (Bourdieu) | Equal returns |
Angles A, B, D tractable in CFPS. E demoted to discussion.
## Step 5 — Hypotheses
H1 (hukou persistence). Net of X3, X4, regional infrastructure, agricultural-
hukou status reduces the probability of access (Y1) and weekly use hours
(Y2). The hukou effect on Y1 narrows across waves (access convergence) but
the hukou effect on Y2 does not (skill-use divergence).
H2 (cohort layering). Birth cohorts post-1985 show systematically higher Y1
and Y2 net of period and age. Within cohort, the age trajectory of Y2 is
flat — i.e., the divide tracks cohort replacement, not within-person
learning.
H3 (intersectional triple penalty). A three-way interaction (rural-hukou ×
female × born ≤ 1965) yields a use-intensity penalty larger than the sum
of the three additive marginal effects.
H4 (household spillover, secondary). Co-residence with at least one digital-
native (born ≥ 1990) is associated with higher Y1 and Y2 for older members.
8.3 What to look for
- Hypotheses are pre-specified. H1 has a directional prediction and a “narrows on Y1 but not on Y2” subtlety. That is good — it means the analysis can falsify the institutional account, not just confirm it.
- Forbidden language is named. The memo records the forbidden causal language and the descriptive-only design (“no causal interpretation of hukou; descriptive design only”).
- One hypothesis is high-risk. H3 is an intersectional claim. Decide now whether you are willing to publish a null if the data show the triple penalty is just additive. (Spoiler: in our run, H3 turned out null, and we kept the null in the paper.)
Stop and check. Can you state the directional prediction of each hypothesis in one sentence, without consulting the document? If not, the puzzle isn’t sharp enough yet.
8A. scholar-lit-review-hypothesis — integrated lit review + theory + hypotheses
Goal: in one workflow, map the existing literature, identify the unresolved gap, choose the theoretical framework that addresses that gap, specify the mechanism, and derive testable hypotheses — producing a publication-ready Literature Review and Theory section.
This skill replaces running /scholar-lit-review and /scholar-hypothesis separately. Use it after /scholar-idea (§8). For the CFPS digital-divide paper, this is the skill that wrote the entire 1,400-word “Theoretical Framework” + “Hypotheses” block in drafts/manuscript-final-...md.
8A.1 The five-step internal logic
The skill enforces a single five-step argument — every step feeds the next, and the prose cannot drift away from this chain.
| Step | What | Output anchor |
|---|---|---|
| 1 | What the literature has established | “Prior work has shown X, Y, Z (Author Year)” |
| 2 | What the literature has left unresolved | “Yet none of these studies has examined …” |
| 3 | Which theoretical framework addresses that gap | Named theory + 1–3 anchor citations |
| 4 | What mechanism the framework predicts | Causal chain with named steps |
| 5 | What hypotheses follow | H1–Hn with directional predictions |
8A.2 Run
> /scholar-lit-review-hypothesis
RQ: In CFPS 2010-2020, did hukou/cohort gaps in internet access narrow
while gaps in weekly use hours persisted?
target: Social Forces
anchor theories: layered digital divide; hukou as institutional sorting;
cumulative advantage; cohort-as-cause
The skill executes a tiered literature search:
- Tier 0 — knowledge graph — the cross-project
scholar-knowledgegraph, queried first when configured - Tier 1 — local library (Zotero / Mendeley / BibTeX / EndNote) — verified citations
- Tier 2 — external APIs — CrossRef, Semantic Scholar, OpenAlex, Google Scholar
- Tier 3 — WebSearch — only for residual gaps
Then it runs an anti-plagiarism + claim-verification panel: three Task-dispatched evaluator prompts in parallel (originality-auditor, claim-verifier, attribution-analyst — skill-internal roles, not entries in .claude/agents/) cross-check every paraphrased sentence against the source, every effect-direction claim against the cited paper, and every citation against the local library. The agreement matrix is appended to the output.
8A.3 Real output (excerpt from the CFPS run)
The skill produced the following Hypotheses block — verbatim, this is what ended up in the final manuscript:
## Hypotheses
H1 (Hukou persistence and access-intensity divergence). Net of education,
household income, occupation, and province-level infrastructure, agricultural-
hukou status reduces both the probability of internet access and the weekly
hours of internet use among users. The hukou coefficient on internet access
narrows monotonically across the 2010-2020 panel waves, consistent with
access convergence. The hukou coefficient on weekly internet hours does not
narrow, and may widen, consistent with the institutional-sorting mechanism
producing a durable second-level divide.
H2 (Cohort layering, not within-person learning). Birth cohorts born after
1985 exhibit systematically higher internet access, weekly internet hours,
and use breadth than earlier cohorts, net of period and chronological age.
Within cohort, the within-person age trajectory of weekly internet hours is
approximately flat. Aggregate population-level growth in weekly internet
hours across waves is therefore primarily driven by cohort replacement.
H3 (Intersectional triple penalty). The use-intensity penalty associated
with the joint condition rural-hukou × female × born ≤ 1965 exceeds the
sum of the three additive marginal effects.
H4 (Household spillover, secondary). Co-residence with at least one
digital-native household member (born 1990 or later) is associated with
higher internet access and weekly internet hours for older co-residents,
with the spillover larger for women and rural residents.
Notice the causal-language calibration — H1 says “is associated with” / “reduces the probability of,” not “causes.” That is enforced by the skill’s explicit rule: hypotheses for observational designs without IV / RD identification must use associational language.
8A.4 Files written
output/<slug>/
├── drafts/scholar-lrh-<slug>-<date>.md ← lit review + theory + hypotheses (+ .docx/.tex/.pdf)
├── drafts/scholar-lrh-<slug>-<date>.bib ← materialized by /scholar-citation MODE 6b (not hand-authored)
├── logs/
│ ├── process-log-scholar-lit-review-hypothesis-<date>.md
│ └── scholar-search-log-<slug>-<date>.md ← every query + hit count
└── reports/
├── source-integrity-panel-<date>.md ← 3-agent verification
├── source-integrity-originality-<date>.md
├── source-integrity-claim-<date>.md
└── source-integrity-attribution-<date>.md
8A.5 Inspect
- Every paraphrased sentence in the lit review must trace to a verified citation in
refs.bib. Open the source-integrity panel report to see which sentences flagged. - Every hypothesis must derive from a named mechanism. If the hypothesis appears without a mechanism step in the prose above it, the chain is broken.
- Causal-language audit. Search the draft for “causes,” “leads to,” “effect of.” For observational designs without identification, every hit is a candidate for revision.
8A.6 The evidence ledger — what you actually read, next to what you wrote (v5.28)
The tier hierarchy in §8A.1 says where a citation may come from. It does not say what you read before you wrote the sentence. Since v5.28 that is a separate file, and it is the artifact behind this section’s promise that every paraphrased sentence traces to a source.
Whenever a source passage becomes the basis of a finalized claim, one record is appended to evidence/claim-anchors.ndjson: the verbatim quote (≤ 60 words), a locator, the tool that retrieved it, and an honest label for how good the evidence actually was.
Two rules do all the work:
- Discovery is not capture. A 25-hit search produces no anchors. Capture happens when a claim is finalized — a landscape-map cell, an effect magnitude, a hypothesis premise, a drafted sentence. Searching is not reading.
- Capture is tier-honest. Anchor with the best evidence already in context. An abstract snippet is a legal anchor (
T3_abstract). When nothing is quotable the record carriesevidence_quote: null— which makes “cited on metadata alone” visible instead of silent.
Read the ledger’s tier label carefully — it is not the Tier 0–2 hierarchy above. The ledger’s
access_tieranswers how good is the evidence I read:T1_fulltext(a PDF, or arag_searchhit) >T2_oa_fulltext>T3_abstract>T4_none. The citation tiers answer where may this citation come from. Same word, different axis. A paper can be Tier-1 verified and still anchored atT3_abstract— you confirmed it exists; you only ever read the abstract.
Downstream this produces an Evidence Dossier pairing “what the source said” against “what we wrote,” and a required log row Evidence anchors: N created / M reused. scholar-write and scholar-citation consume the ledger rather than re-deriving it (§14, §16), and Phase 7 carries a tag gate that checks it.
Quotes live only under evidence/, and are excluded from replication packages by default — verbatim third-party text is exactly what you do not want to redistribute by accident.
Stop and check. Can you point at one citation in the draft, open the BibTeX file, and find the matching key? If not, run /scholar-citation verify (§16) before going further. Then open evidence/claim-anchors.ndjson and count how many of your finalized claims are anchored at T3_abstract or T4_none. That number is the honest size of what you are citing without having read.
8B. scholar-conceptual — build the theory object, not the prose
Goal: produce the theoretical objects a paper rests on — typologies, mechanism chains, multi-level frameworks, scope conditions, process models — and render them as publication-quality figures (TikZ → PDF, with Mermaid as a fallback).
This is not hypothesis derivation (/scholar-hypothesis does that), and not identification (/scholar-causal does that — see §8D for the fourteen identification strategies and the DAG / Potential-Outcomes scaffolding it ships with). scholar-conceptual works at the level of theory construction: what is the theory made of, and how do its parts connect?
8B.1 Two modes
argument-hint: "[theorize|diagram] [topic], e.g., 'theorize a framework for
digital labor precarity' or 'diagram mechanism model for
segregation and health'"
| Mode | Trigger | Output |
|---|---|---|
| THEORIZE | “theorize,” “build theory,” “construct framework,” “synthesize,” “typology” | A 3–5-page memo with named definitions, scope conditions, mechanisms, rivals, and limitations |
| DIAGRAM | “diagram,” “figure,” “mechanism diagram,” “concept map,” “tikz” | A standalone .tex (TikZ) compiled to .pdf, plus optional .mmd/.svg/.png Mermaid version |
| Both | Both keywords present, or full / “framework with figure” | THEORIZE then DIAGRAM, in sequence |
> /scholar-conceptual theorize a typology of immigrant civic incorporation
> /scholar-conceptual diagram multi-level model for algorithmic management
> /scholar-conceptual full framework with figure for cumulative disadvantage
THEORIZE further classifies the task into eight types — typology construction (Lazarsfeld property-space), process theorizing, mechanism specification (Coleman’s boat / Hedström DBO), scope-condition mapping, multi-level model, abductive theory-from-anomaly, synthetic framework, concept clarification.
Two things this skill deliberately does not do. It will not make identification claims — those route to /scholar-causal. And it is the only skill in this part of the suite that dispatches no subagents at all: it has a narrow tool list and no verification panel, so its output is checked by you, or by /scholar-auto-improve observe afterwards.
The HARKing disclosure gate.
scholar-conceptualcarries the suite’s theoretical-pivot protocol, which fires when all three conditions hold: (a) the project has pre-registered hypotheses, (b) at least one focal hypothesis came back null or opposite-signed, and (c) the Discussion now introduces a theoretical concept that was not in the original account list — or uses reframe-signal phrases like “reinterpret as,” “post-hoc explanation,” or “in retrospect.”When it fires, you must produce
design/theoretical-pivot.mdrecording the pre-registered account and its status per hypothesis, the pivot account and its inferential status, what changed and what did not, and guidance for the reader — and tag the affected manuscript sections[REGISTERED]or[EXPLORATORY].Note carefully what this is not: it is not a prohibition on post-hoc reframing, which is a normal and often valuable part of research. It is a requirement to disclose and bound it. Reframing after a null result is legitimate; presenting the reframe as though you had predicted it is not.
8B.2 Run (the digital-divide example)
> /scholar-conceptual build mechanism model: access convergence,
persistent intensive-use stratification,
hukou and cohort sorting
target: Social Forces
diagram type: Coleman's boat
What the skill writes:
output/<slug>/theory/mechanism-memo-<date>.md— a 1,500-word memo naming each mechanism step (institutional sorting → infrastructural exposure → skill formation → use-intensity stratification), with rival explanations explicitly listed and each arrow’s falsifying evidence stated.output/<slug>/figures/fig-mechanism-coleman.tex— TikZ source for a Coleman’s-boat diagram (macro condition → individual situation → individual action → macro outcome).output/<slug>/figures/fig-mechanism-coleman.pdf— compiled vector PDF, ready to drop into LaTeX.output/<slug>/figures/fig-mechanism-coleman.mmd/.svg— Mermaid fallback (renders quickly during iteration).
8B.3 The compiled figure — Coleman’s boat for the CFPS case
The skill emits ready-to-compile TikZ, and latexmk / xelatex compiles it to a standalone PDF you can drop straight into the manuscript. Here is the real compiled output from running this skill on the digital-divide project — not a redrawn mock-up:

Underneath, the TikZ source the skill wrote (excerpt — full file at output/<slug>/figures/fig-mechanism-coleman.tex in a fresh run; in this handbook artifact it was emitted to output/theory/fig-mechanism-coleman.tex because the run pre-dated the standardized figures/ layout):
\begin{tikzpicture}[
box/.style={draw=primary, rounded corners=3pt,
minimum width=3.6cm, minimum height=1.1cm,
align=center, font=\small, fill=white},
macrobox/.style={box, fill=lightbg, font=\small\bfseries},
arrow/.style={-{Stealth[length=7pt]}, primary},
microarrow/.style={-{Stealth[length=7pt]}, accent},
label/.style={font=\scriptsize\itshape, muted}]
% MACRO LEVEL
\node[macrobox] (M1) at (0, 3) {Hukou system\\(institutional sorting)};
\node[macrobox] (M2) at (10, 3) {Population-level\\use-intensity gap (Y2)};
% MICRO LEVEL
\node[box] (m1) at (2.6, 0) {Differential digital\\infrastructure exposure};
\node[box] (m2) at (7.4, 0) {Differential\\skill conversion};
% Coleman arrows: 4 numbered legs of the boat
\draw[arrow] (M1) -- (M2) node[midway, above, label] {Observed gap (descriptive)};
\draw[microarrow] (M1.south) -- (m1.north) node[midway, left, label] {(1) Situational};
\draw[microarrow] (m1) -- (m2) node[midway, below, label] {(2) Action-formation};
\draw[microarrow] (m2.north) -- (M2.south) node[midway, right, label] {(3) Transformational};
\end{tikzpicture}
The skill also writes a figure caption block ready to paste under the figure in your manuscript, and a Rival explanations to test: checklist (visible at the bottom of the compiled diagram) — these are the empirical falsifiers the paper must address in its robustness section.
8B.4 Eight diagram types the skill can render
| Type | Best for | Engine |
|---|---|---|
| Mechanism diagram | Coleman’s boat, causal chains, mediation | TikZ |
| Multi-level model | Macro–meso–micro, cross-level effects | TikZ |
| Typology matrix | 2×2 / 2×3 property-space classifications | TikZ or ggplot2 + geom_tile |
| Process model | Temporal stages, phase transitions | TikZ or Mermaid |
| Concept map | Relationships between theoretical concepts | Mermaid or Graphviz |
| Feedback loop | Cumulative-advantage, reinforcing/balancing | TikZ |
| Scope boundary | Where the theory applies vs. doesn’t | TikZ (Venn / nested rectangles) |
| Theoretical synthesis | How multiple theories connect | TikZ or Mermaid |
8B.5 Inspect
- Every arrow needs a labeled mechanism. Open the diagram. If an arrow has no label, it is a graphic element pretending to be theory.
- Every box should have a falsifier. The memo should state, for each box and each arrow, what observation would weaken the claim. If a participant cannot answer “what evidence would falsify this arrow,” the diagram is decorative.
Stop and check. Hand the figure to a labmate without the memo. Can they reconstruct the mechanism story from the diagram alone? If not, the diagram is over-stylized and under-informative — re-run with more labels.
8C. scholar-knowledge — the cross-project memory layer
Goal: maintain a single, user-scoped knowledge graph across all your projects so that every paper you ingest, every finding you extract, every method note, and every relationship between papers is reusable next time. This is what stops the agent from re-discovering the same literature on every project.
This is the most under-used skill in the suite and arguably the most valuable. The CFPS digital-divide paper, the CFPS hukou-marriage paper, and a dozen others in the audited corpus all share the same intellectual neighborhood — Wu & Treiman 2004, Xie & Jin 2015, van Deursen & Helsper 2015, DiMaggio et al. 2004, etc. Without scholar-knowledge, each project starts from zero. With it, ingestion is an investment that pays back forever.
8C.0 Three ways to SELECT — and why a wiki, not just RAG
Getting the right text into the model’s window (the “SELECT” move) has three distinct strategies, and scholar-knowledge is the third:
- RAG — chunk your corpus, embed it, and at query time pull the top-K nearest chunks by vector similarity. Fast and scalable, but it returns opaque fragments ranked by surface similarity, the index goes stale when sources change, and you cannot easily read why a chunk was chosen.
- Agentic search — no index; the agent
greps and reads the live files in a loop (this is how Claude Code reads your repo). Always current and fully auditable, but bounded by what a handful of searches can reach, and it re-reads from scratch every session. - Knowledge wiki (the “LLM-wiki” approach) — the model reads each source once, extracts the findings, mechanisms, and relationships, and writes them as a human-readable, interlinked markdown wiki. To answer, it reads the index page and follows
[[links]]to the few pages that matter. This is exactly what/scholar-knowledge compileandaskdo.
Why a wiki can beat RAG for a corpus you return to: the synthesis is precomputed (topic overviews, contradictions.md, gaps.md) instead of re-derived on every query; relationships are explicit links you can traverse (extends, contradicts, same-dataset), not implicit vector neighbours; it is just markdown — auditable, editable, and needs no embedding model or vector database; and it compounds — you file your own outputs back in, so paper #5 stands on the shoulders of #1–4. The cost is that extraction is upfront and lossy (the wiki is the model’s reading of a source, not the source — which is why raw/ keeps the originals), and the wiki must be kept current (the LLM maintains it; you rarely edit by hand). This is Andrej Karpathy’s “LLM wiki” idea: the model writes and maintains the knowledge base, and you file outputs back to enrich it for future queries.
The three are complementary, not rivals. Keep the wiki as durable memory, wrap a live retriever (OpenAlex, Zotero) as an MCP tool for reach (Lab 3 §4b), and let the agent choose which to reach for. As of v5.27 the suite ships the first strategy too — scholar-rag (§8F) builds a real local vector database over the same library and exposes it as MCP tools, so you no longer have to choose: the wiki holds the synthesis, the vector index holds the verbatim passages, and both key on the same paper identity. To see the whole mechanism in ~250 lines of dependency-free Python — ingest → graph → compile → navigate — run the Day-3 demo:
cd demo/day3-claude-code/llm-wiki
python3 build_wiki.py # 7 papers -> graph -> 34 interlinked wiki pages
python3 ask.py "why doesn't closing the access gap close the divide?"
ask.py prints the exact navigation path (index.md → topics/… → concepts/… → papers/…), making the contrast with RAG’s opaque top-K concrete.
This graph is also the seed for
scholar-rag’s GraphRAG (§8F).rag_py graphrag.py seedimports these concepts and citation edges before any LLM extraction runs — it is the fast, no-LLM head start. On a 5.5k-paper library the seed edges alone reached about 12% of the corpus, which is why §8F.6’s citation and semantic stages exist. The two skills are complementary:scholar-knowledgeanswers what does the field claim,scholar-raganswers show me the passage, cited.
8C.1 What lives where
~/.claude/scholar-knowledge/ (override with $SCHOLAR_KNOWLEDGE_DIR)
├── papers.ndjson ← one JSON object per paper (rich extracted content)
├── concepts.ndjson ← named concepts, theories, mechanisms
├── edges.ndjson ← inter-paper relationships (cites, contradicts, extends, …)
├── meta.json
└── raw/ ← APPEND-ONLY archive of original sources
├── pdfs/ ← symlinks to Zotero PDFs (no copies of large files)
├── abstracts/ ← extracted text
├── api-responses/ ← raw CrossRef / Semantic Scholar JSON
├── web/ ← fetched preprints, NBER WPs, blog posts
└── images/ ← figures extracted from PDFs (per-paper subdirs)
A single paper node looks like this (real schema, abbreviated):
{
"id": "fiel-zhang-2018",
"doi": "10.1007/s13524-017-0632-9",
"title": "Three Dimensions of Change in School Segregation: A Grade-Period-Cohort Analysis",
"authors": ["Fiel, Jeremy E.", "Zhang, Yongjun"],
"year": 2018,
"journal": "Demography",
"findings": ["Age-period-cohort decomposition of U.S. public-school segregation, 1999–2000 to 2013–2014, separates grade, period, and cohort effects on between-school segregation."],
"mechanisms": ["compositional change (demographic shifts)", "cohort succession"],
"theories": [{"name": "spatial assimilation", "role": "tests"}],
"methods": ["age-period-cohort decomposition", "multilevel models"],
"populations": ["K-12 students in US public schools"],
"data_sources": ["Common Core of Data (CCD)"],
"limitations": ["Data limited to public schools"],
"future_directions": ["Within-district heterogeneity at the classroom level"],
"projects": ["segregation-paper-2026", "digital-divide-china-cfps"],
"raw_path": "abstracts/fiel-zhang-2017.txt"
}
The point is the findings, mechanisms, methods, limitations, future_directions fields — stuff your reference manager does not store, but stuff you reach for constantly.
Edges look like:
| Predicate | Direction | Example |
|---|---|---|
cites | A → B | Xie & Jin 2015 → Wu & Treiman 2004 |
contradicts | A ↔ B | Cui 2024 ↔ Cheng & Selden 1994 |
extends | A → B | This paper → Li, Ouyang, & Hu 2025 |
replicates | A → B | A replication study → original |
uses-method | A → B | This paper → Oaxaca & Ransom 1994 |
uses-theory | A → B | This paper → DiMaggio et al. 2004 |
same-dataset | A ↔ B | Two CFPS papers using the same panel |
8C.2 The eight modes — concrete commands
| Mode | Trigger words | What it does |
|---|---|---|
| INGEST | ingest, add, import, extract | Pull papers from Zotero / PDF / DOI / URL / lit-review file / skill output; extract findings/mechanisms/etc.; archive raw source |
| SEARCH | search, find, query, what do we know about | Boolean / keyword / regex search over papers + concepts + edges |
| RELATE | relate, link, connect, contradicts, extends | Add or view inter-paper edges |
| STATUS | status, stats, coverage, dashboard | Graph statistics: paper count, top theories, coverage by topic |
| EXPORT | export, subset, for project | Project-scoped subset (e.g., only papers tagged digital-divide-china-cfps) |
| COMPILE | compile, build wiki, wiki | Generate an Obsidian-compatible markdown wiki from the graph |
| ASK | ask, why, how do, compare, summarize | Answer complex research questions across the wiki |
| RE-EXTRACT | re-extract, refresh, enrich | Re-run extraction on raw sources (e.g., upgrade abstract-only papers to full-PDF, or add new schema fields) |
Mode 1 — INGEST: bulk-load from Zotero
> /scholar-knowledge ingest from zotero collection "digital divide"
> /scholar-knowledge ingest from zotero tag "hukou"
> /scholar-knowledge ingest from zotero keyword "second-level digital divide" 30
For each paper found:
- Read Zotero SQLite → bibliographic metadata
- Symlink the PDF (no copy) into
raw/pdfs/<slug>.pdf - Run
pdftotexton the first 400 lines for extraction - Optionally extract figures via
pdfimages(ifpoppleris installed) - Extract findings, mechanisms, theories, methods, populations, data sources, limitations, future directions, key quotes (with page numbers when available)
- Append a
papernode topapers.ndjson - Append
conceptnodes for any new theories/mechanisms - Re-deduplicate by DOI / title hash so re-ingesting is idempotent
Mode 1 — INGEST: from PDF, DOI, URL, or your own work
> /scholar-knowledge ingest from pdf ~/papers/li-ouyang-hu-2025.pdf
> /scholar-knowledge ingest from doi 10.1038/s41746-025-02076-1
> /scholar-knowledge ingest from url https://www.nber.org/papers/w29234
> /scholar-knowledge ingest from output \
output/digital-divide-china-cfps/drafts/manuscript-final-2026-05-04.md
The last one — from output — is the feedback loop. After every paper you finish, ingest your own work back into the graph. The paper type becomes "own_work" and the findings become searchable for your next project.
Mode 2 — SEARCH
> /scholar-knowledge search "second-level digital divide China"
> /scholar-knowledge search papers using-method "Oaxaca-Blinder"
> /scholar-knowledge search papers contradicts spatial-assimilation
Returns paper IDs, titles, ranked relevance, and a short rationale per hit. Feeds directly into scholar-lit-review-hypothesis (§8A) — instead of asking external APIs first, the lit-review skill reads papers.ndjson first.
Mode 3 — RELATE: the edges you assert yourself
Ingestion extracts findings; it does not claim two papers disagree. That edge is a scholarly judgement, so you make it — and then it is queryable.
> /scholar-knowledge relate [Paper A] contradicts [Paper B]
> /scholar-knowledge relate [Paper A] extends [Paper B]
> /scholar-knowledge relate show relationships for [Paper A]
> /scholar-knowledge relate show all contradicts
> /scholar-knowledge relate map residential segregation
Both papers must already be in the graph; if one is missing the skill offers to ingest it first rather than inventing a node. contradicts is the one worth the effort — a literature review that can enumerate its own disagreements is doing something a summary cannot.
Mode 4 — STATUS (the dashboard)
> /scholar-knowledge status
Real output:
Knowledge graph at ~/.claude/scholar-knowledge
Papers: 1,142
Concepts: 287
Edges: 3,901
Raw archive: 4.2 GB across 1,142 PDFs and 318 web fetches
Top theories (by paper count):
1. cumulative advantage / Matthew effect (87 papers)
2. spatial assimilation (54 papers)
3. layered (three-level) digital divide (41 papers)
4. hukou as institutional sorting (33 papers)
5. second-demographic transition (29 papers)
Coverage gaps (theories with <3 papers):
- distributed cognition + digital practice (1 paper — extend)
- intersectional algorithmic harm (2 papers — extend)
- capability approach × digital inclusion (0 papers — gap)
Project tags:
digital-divide-china-cfps (76 papers)
hukou-marriage-cfps (94 papers)
segregation-paper-2026 (108 papers)
…
Mode 5 — EXPORT: a subset, for one project or one bibliography
> /scholar-knowledge export for project digital divide
> /scholar-knowledge export for collection [zotero collection]
> /scholar-knowledge export by author [name]
> /scholar-knowledge export all as bibtex
Markdown is the default; as bibtex writes a .bib. Use this to hand a collaborator the slice of your graph that touches one paper, without handing them your whole library.
Mode 6 — COMPILE: turn the graph into an Obsidian wiki
> /scholar-knowledge compile
Produces a fully linked markdown wiki at ~/.claude/scholar-knowledge/wiki/ with one page per paper, one page per theory/mechanism, and [[wiki-link]] cross-references throughout. Open in Obsidian (or any markdown viewer) and the graph view becomes browsable. Re-run after every ingest pass.
Mode 7 — ASK: research questions across the graph
> /scholar-knowledge ask what are the main theories of the second-level digital divide?
> /scholar-knowledge ask compare the mechanisms in van Deursen & Helsper 2015 \
vs Hargittai 2002
> /scholar-knowledge ask which CFPS papers in my graph use Oaxaca-Blinder decomposition?
The skill reads the compiled wiki and answers with paper-level citations. Every claim it makes is grounded in the wiki, so hallucinated references are bounded by what you’ve actually ingested.
Mode 8 — RE-EXTRACT: upgrade the schema
When you add a new field to the paper node (e.g., “data-availability statement” or “preregistration link”), run:
> /scholar-knowledge re-extract all abstract_only
> /scholar-knowledge re-extract field=data_availability
The skill walks raw/ and re-runs extraction with the updated schema — without re-fetching anything from the internet. This is why the raw archive is append-only: the schema can change, the source cannot.
8C.3 Why this matters for the CFPS workshop
In the workshop pipeline, scholar-lit-review-hypothesis (§8A) checks papers.ndjson first, before WebSearch. If you have already ingested Wu & Treiman 2004, Xie & Jin 2015, van Deursen & Helsper 2015, etc., the lit-review skill cites them with full verified bibliographic data instead of generating “[CITATION NEEDED]” placeholders. Same for scholar-citation verify (§16) — local hits are Tier 1, free, and instantaneous.
The right cadence is:
After every paper you finish:
/scholar-knowledge ingest from output drafts/manuscript-final-...md
/scholar-knowledge compile
Before every new project:
/scholar-knowledge ask what do I already know about <topic>?
/scholar-knowledge export for project <new-slug>
8C.4 Inspect
raw/is append-only. Neverrmfrom it. The audit trail depends on it.- Edges should outnumber concepts by ~10×. If your graph has 400 papers and 12 edges, you’ve ingested papers but not connected them — run
relatemode. - Re-extraction is cheap. New schema field?
re-extractis your friend; do not re-ingest from sources.
Stop and check. Run /scholar-knowledge status once a month. If the “Coverage gaps” section names a theory you cite, ingest 5–10 anchor papers for it before your next lit review.
8C.5 The Obsidian wiki — set up, configure, browse
/scholar-knowledge compile produces an Obsidian-compatible vault at ~/.claude/scholar-knowledge/wiki/. Obsidian is free, local-first, and the most ergonomic way to actually read and navigate the graph. This subsection walks through the setup the skill expects.
8C.5.1 What compile writes
~/.claude/scholar-knowledge/wiki/
├── index.md ← dashboard: stats, recent ingests, quick links
├── knowledge-map.png ← rendered network graph (if generated)
├── contradictions.md ← contested findings (papers where edges = contradicts)
├── gaps.md ← research gaps and unfilled future-direction lanes
├── papers/ ← one page per paper
│ ├── fiel-zhang-2017.md
│ ├── li-ouyang-hu-2025.md
│ ├── van-deursen-helsper-2015.md
│ └── … (often hundreds of files)
├── concepts/ ← one page per theory / method / mechanism
│ ├── spatial-assimilation.md
│ ├── layered-digital-divide.md
│ ├── oaxaca-blinder-decomposition.md
│ └── hukou-as-institutional-sorting.md
├── topics/ ← auto-clustered topic pages
│ ├── digital-inequality-china.md
│ └── residential-segregation.md
└── answers/ ← Q&A archive (grows with each /scholar-knowledge ask)
└── second-level-digital-divide-mechanisms-2026-05-08.md
A typical paper page (papers/li-ouyang-hu-2025.md) renders as:
# Li, Ouyang & Hu (2025) — Ten-Year Analysis of Digital Divides Among Older Chinese Adults
**Journal:** npj Digital Medicine
**DOI:** 10.1038/s41746-025-02076-1
**Data:** [[CFPS]] 2010–2020
## Findings
- Persistent age-related gap in healthy-aging outcomes attributable to digital exclusion.
- Gap does not narrow across the decade despite access growth.
## Mechanisms
- [[skill-conversion]] — older cohorts' lower marginal returns to use.
## Theories used
- [[layered-digital-divide]] (role: applies)
- [[cumulative-advantage]] (role: extends)
## Methods
- [[OLS-with-fixed-effects]]
- [[descriptive-decomposition]]
## Limitations (per authors)
- Cannot separate cohort from age in single panel —
[[APC-identification]] is non-identified without restriction.
## Future directions (per authors)
- Within-household digital transmission — see [[household-spillover]].
## Edges
- This paper **uses-theory** [[van-deursen-helsper-2015]]
- This paper **extends** [[ren-zhu-2024]]
- This paper is **cited-by** [[zhang-2026-digital-divide-china-cfps]] (own-work)
---
*Ingested: 2026-04-12 from Zotero. Raw: `raw/pdfs/li-ouyang-hu-2025.pdf`.*
A concept page (concepts/layered-digital-divide.md) renders as:
# Layered (Three-Level) Digital Divide
A theoretical framework distinguishing access (Level 1), skill / use intensity
(Level 2), and conversion of online activity into offline returns (Level 3).
## Anchor papers
- [[dimaggio-hargittai-celeste-shafer-2004]] — original five-dimension formulation
- [[hargittai-2002]] — coined "second-level digital divide"
- [[van-deursen-helsper-2015]] — named the third level
- [[robinson-et-al-2015]] — life-course / gender / race consolidation
## Papers using this framework (41 in graph)
- [[li-ouyang-hu-2025]]
- [[ren-zhu-2024]]
- [[zhang-2026-digital-divide-china-cfps]] (own-work)
- …
## Mechanisms
- [[skill-formation]]
- [[content-sorting]]
- [[opportunity-matching]]
## Empirical predictions in this graph
- Access gaps narrow as penetration saturates.
- Use-intensity gaps **persist or widen** under cumulative advantage.
- Returns gaps depend on cultural and economic capital.
## Contradictory evidence (in graph)
- [[zhao-et-al-2022]] — finds narrowing intensity gap among rural Chinese
students under online learning.
The [[double-bracket]] references are wiki-links — Obsidian renders them as clickable, follows them with Cmd+Click, and exposes them in the backlinks sidebar so each paper page knows which other pages link to it without you maintaining a back-pointer manually.
8C.5.2 Install Obsidian and open the vault
# macOS
$ brew install --cask obsidian
# Linux (AppImage from obsidian.md)
$ # download Obsidian-1.x.AppImage, chmod +x, run
# Windows (WSL participants: install Obsidian on Windows side, point at WSL path)
Open the vault:
- Launch Obsidian.
- Click Open folder as vault.
Press
Cmd+Shift+G(macOS) orCtrl+L(Linux) and paste:~/.claude/scholar-knowledge/wiki- Confirm. Obsidian indexes the vault — first time can take 30–60 seconds for a 1,000-paper graph.
A useful convenience symlink:
$ ln -s ~/.claude/scholar-knowledge/wiki ~/Desktop/scholar-wiki
After this you can just open ~/Desktop/scholar-wiki from Finder.
8C.5.3 Recommended Obsidian settings
Files & Links:
- Detect all file extensions → ON
- Default location for new notes → “In the folder specified below” →
answers/ - Use [[Wikilinks]] → ON (default)
Editor:
- Readable line length → ON
Core plugins to enable (Settings → Core plugins):
- Graph view (
Cmd+G) — visual network of papers ↔ concepts ↔ topics - Backlinks — for each page, sidebar shows incoming
[[…]]references - Outgoing links — for each page, sidebar shows what it links out to
- Quick switcher (
Cmd+O) — jump to any page by typing - Search (
Cmd+Shift+F) — full-text across the vault - Tags — if you add
#topic/segregationstyle tags
Recommended community plugins (Settings → Community plugins → Browse):
- Dataview — query the wiki as a database. Example:
TABLE journal, year FROM "papers" WHERE contains(theories, "layered-digital-divide") AND year >= 2020 SORT year DESCRenders a live table of every post-2020 paper in your graph that uses the layered framework.
- Graph Analysis — centrality, clustering, betweenness over the wiki graph
- Breadcrumbs — navigate paper → concept → topic hierarchies
- Calendar — view papers by ingest date
8C.5.4 Configure Graph View
Open Graph View with Cmd+G. The default view is undifferentiated; configure it like this:
Filters panel:
- Tags — show / hide by tag
- Orphans toggle — flips to show isolated papers (candidates for
relatemode)
Groups (color-coded by node type) — click “+ Add group” five times:
| Color | Filter expression | What it highlights |
|---|---|---|
| Blue | path:papers/ | Individual paper pages |
| Red | path:concepts/ | Theories, methods, mechanisms |
| Green | path:topics/ | Auto-clustered topic pages |
| Yellow | path:answers/ | /scholar-knowledge ask outputs |
| Purple | file:contradictions OR file:gaps OR file:index | Aggregate / dashboard pages |
Display panel:
- Node size → “By number of links” — highlights well-connected papers (these are usually the anchor citations of a sub-field)
- Arrow → ON — shows direction of
[[…]]references - Line thickness → “By number of connections”
The result: dense red clusters are theories with many supporting papers; dense blue clusters are sub-fields; bridge nodes connecting two clusters are integrative papers worth reading carefully.
8C.5.5 Four browsing patterns
(a) Browse the research landscape.
Open index.md. Click a topic (e.g., [[digital-inequality-china]]). You see the topic page with a list of papers and concepts. Click any paper to see findings, theories, methods. Use the Backlinks sidebar to see what cites or extends it.
(b) Find connections.
Open Graph View (Cmd+G). Type a concept name in the search box (e.g., “hukou-as-institutional-sorting”). It highlights in the graph. Adjacent nodes are the papers using that concept. Identify bridge papers — nodes connecting two otherwise-separate clusters. These are the papers most likely to give you a novel framing.
(c) Ask research questions.
Run /scholar-knowledge ask <question> from Claude Code. The answer is saved to wiki/answers/<question-slug>-<date>.md with full citations to the wiki pages it consulted. Open the answer file in Obsidian — its Backlinks sidebar shows every paper that fed the answer. Over a year your answers/ folder becomes its own searchable Q&A archive.
(d) Track research progress.
wiki/gaps.md— what your graph says is unstudied (low coverage inSTATUSmode)wiki/contradictions.md— debated findings (where the graph hascontradictsedges)wiki/answers/— the questions you’ve already explored- Graph View — dense clusters are well-studied, sparse regions are gaps
8C.5.6 Keeping the wiki current
The wiki updates automatically:
- After each ingest — paper pages, concept pages, and
index.mdare regenerated for just the new entries (incremental). - Full rebuild — run
/scholar-knowledge compile fullto regenerate topic clusters,contradictions.md,gaps.md, and the visualization. Use this monthly or after major ingest passes. - Manual edits — you can edit a wiki page by hand (e.g., add a personal note in the Findings section), and incremental rebuilds preserve the change. A full rebuild may overwrite it, so if you want a permanent personal annotation, put it in a separate
notes/folder you create yourself, not inside the auto-generated pages.
Stop and check. Open Obsidian → Graph View. Filter to your current project’s papers (path:papers/ + tag your current project tag). The cluster you see is the literature you actually have. Anything labeled “Coverage gap” in STATUS mode but visually missing from this cluster — that’s where your next ingest pass should aim.
8D. scholar-causal — pick an identification strategy on purpose
Goal: before you write the design blueprint, decide whether the question is causal and — if so — which of fourteen identification strategies the data actually supports. The skill sits between /scholar-hypothesis and /scholar-design, and is the place where you commit (in writing) to the assumptions you will defend.
The recent update broadens this skill substantially. Earlier versions handled OLS, DiD, RD, IV, FE, matching, and synthetic control. The current build covers fourteen strategies, each with assumptions, diagnostics, R and Stata code, and a journal-ready write-up template:
- OLS under selection-on-observables (with Oster δ).
- 2×2 Difference-in-Differences.
- Sharp and Fuzzy Regression Discontinuity.
- Instrumental Variables / 2SLS.
- Panel Fixed Effects (TWFE).
- Matching / Reweighting — PSM, CEM, IPW, doubly robust.
- Synthetic Control / SynthDiD.
- Causal Mediation (ACME) under sequential ignorability.
- Staggered DiD — Callaway-Sant’Anna, Sun-Abraham, de Chaisemartin-D’Haultfœuille, Borusyak-Jaravel-Spiess (with a runnable CS workflow template at
references/did-cs-workflow.R). - Double Machine Learning and causal forests for high-dimensional confounding.
- Bunching estimation at kinks and notches.
- Shift-share / Bartik instruments for local exposure to aggregate shocks.
- Distributional and quantile methods — quantile regression, RIF-OLS, changes-in-changes.
- Factorial DiD (FDID) — for a universal-exposure event (no clean control group) with a pre-event baseline factor G; distinguishes effect modification from causal moderation, with a runnable workflow template at
references/fdid-workflow.R.
8D.1 Run
> /scholar-causal effect of agricultural hukou on weekly internet hours,
using CFPS 2010-2020 panel; candidate confounders:
household income, education, parental occupation,
village infrastructure
The skill asks three things up front: (1) the causal question (effect of X on Y), (2) the data structure (cross-section, panel, natural experiment), and (3) candidate confounders and mechanisms. Everything downstream depends on those answers.
8D.2 What the skill produces
A typical run yields four artifacts in the project directory:
design/
├─ causal-dag.tex # dagitty + TikZ DAG, with adjustment sets
├─ identification-memo.md # which strategy, why, what it assumes
├─ diagnostic_plan.json # Tier 1: always emitted — checks to run pre-design
└─ sensitivity-registry.md # Oster δ / E-value / HonestDiD / Rosenbaum / Manski
logs/process-log-scholar-causal-<date>.md
The identification memo is the most important file. It names the chosen strategy, walks through the four canonical steps — estimand → identifying assumption → estimator → threats — and lists the forbidden claims that will be enforced later by scholar-write, scholar-verify, and scholar-polish. (Forbidden-claim enforcement is how the CFPS pipeline catches an Abstract that says “reduces” when the design only licenses “is associated with.”)
8D.3 The method-selection decision tree
The skill ships with a single decision table the agent walks through with you. The collapsed form:
| Data structure / variation | Core assumption | Best strategy |
|---|---|---|
| RCT (random assignment) | SUTVA + compliance | OLS / ITT / LATE |
| Cross-section + rich controls | CIA / unconfoundedness | OLS + Oster δ, matching |
| Many confounders, large N | CIA | DML / causal forests |
| Exogenous shock, two periods | Parallel trends | 2×2 DiD |
| Staggered policy adoption | Parallel trends, no forbidden comparisons | CS / SA / dCDH / BJS |
| Threshold-based assignment | Continuity of potential outcomes | Sharp / Fuzzy RD |
| Plausible instrument | Exclusion + relevance | IV / 2SLS |
| Panel data | No time-varying confounding | Panel FE |
| No instrument, observational | Overlap + unconfoundedness | Matching / IPW / DR |
| Few treated units, long pre-period | Pre-period fit | Synth / SynthDiD |
| Mediation question | Sequential ignorability | Causal mediation |
| Bunching at kink/notch | Smooth counterfactual density | Bunching estimation |
| Local exposure to aggregate shocks | Exogenous shocks OR exogenous shares | Shift-share / Bartik IV |
| Distributional heterogeneity | Quantile-specific assumptions | Quantile / RIF-OLS / CiC |
| Universal-exposure event + baseline factor G | Factorial parallel trends | Factorial DiD (FDID) |
8D.4 The sensitivity-analysis suite
Picking a strategy is half the work. The skill also writes a sensitivity registry that pre-commits you to robustness checks before you see results:
- Oster (2019) δ — for OLS with selection-on-observables.
- E-values (VanderWeele & Ding 2017) — minimum unmeasured-confounder strength to nullify the effect.
- Rosenbaum bounds — sensitivity to hidden bias for matched estimators.
- HonestDiD (Rambachan & Roth 2023) — bounded violation of parallel trends.
- Manski bounds — partial identification with weaker assumptions.
- Placebo / falsification tests — pre-treatment outcomes, never-treated leads, in-time placebos.
- Spillover sensitivity — SUTVA violations under contagion or interference.
- Specification curve / multiverse — every plausible specification, ranked.
8D.5 Tier 1 vs. Tier 2 — what runs on your data
The skill has two execution tiers. Tier 1 always emits diagnostic_plan.json — a machine-readable list of checks to run before the design is locked. Tier 2 is opt-in and executes a small set of pre-design diagnostics directly:
- Panel-data preview via
panelview+fect— to inspect treatment timing and pre-trends. - Synthetic-control preview via
gsynth(Xu 2017) — feasibility of synth/SynthDiD for your case. - Interaction-effect diagnostic via
interflex(Hainmueller, Mummolo, Xu 2019) — whether your moderator looks linear at all. - Factorial-DiD preview via
fdid(Xu, Zhao & Ding 2026) — for crossed-treatment / factorial-DiD designs.
Tier 2 is gated: you have to explicitly say “run diagnostics on this dataset” in the prompt. Tier 2 does not estimate the focal effect, fit a final model, or produce numbers that will appear in the paper. It produces diagnostic plots that inform the choice you commit to in §9 (scholar-design).
8D.6 Why the CFPS workshop routes around scholar-causal
The digital-divide example in this handbook is deliberately not a causal design. Hukou is assigned at birth and rarely changes; there is no manipulable “treatment.” We have neither an instrument nor a discontinuity. The right move — the one the workshop demonstrates — is to decline a causal identification strategy and write a descriptive-decomposition design instead. scholar-causal is still useful in that case: it produces the DAG that justifies your covariate adjustment, and it stamps the identification memo with causal_status: descriptive so that downstream skills enforce the right language ceiling.
For projects where you do have causal leverage — a CCT-style RCT, a policy shock, a regression discontinuity, a credible IV — start the project with scholar-causal, then run scholar-design. The decision is which strategy; the discipline is committing to its assumptions in writing before the analysis runs.
8D.7 Inspect
Before moving to §9, open the three artifacts and ask:
causal-dag.tex— Is the adjustment set sufficient? Are there back-door paths the DAG missed?identification-memo.md— Could a hostile reviewer attack each of the named assumptions? Is one of them empirically testable?sensitivity-registry.md— If the focal effect survives Oster δ > 1 and an E-value above the strongest control, the headline claim is defensible.
Stop and check. If the identification memo lists causal_status: descriptive, read §9.3’s “Forbidden claims” block before you start drafting — the language ceiling is now binding.
8E. scholar-lit-review and scholar-hypothesis — when you want them separately
§8A showed the integrated skill. Both halves also exist on their own, and there are good reasons to reach for them individually: a literature landscape you are not yet ready to turn into hypotheses, or hypotheses derived from a literature you already know.
8E.1 scholar-lit-review — three depths
argument-hint: "[topic or research question] [optional: landscape|targeted|rapid]
[optional: target journal] [optional: population, time period,
geographic scope]"
| Mode | Triggers | Search waves | Papers | Words |
|---|---|---|---|---|
| Full landscape (default) | landscape, map, comprehensive, state of the field | 5+ | 50–100 | 3,000–10,000 |
| Targeted | targeted, focused, for paper, intro | 3 | 15–30 | 1,000–3,000 |
| Rapid scoping | rapid, scoping, quick, preliminary | 2 | 10–20 | 500–1,500 |
> /scholar-lit-review "digital divide in China" landscape "Social Forces" 2010-2025
> /scholar-lit-review "remote work and the gender wage gap" rapid
The waves are cumulative: Wave 1 core topic · Wave 2 mechanisms and theories · Wave 3 methods and data (targeted and full) · Wave 4 recent frontier (full only) · Wave 5 contested terrain and null findings (full only).
Three features distinguish it from “search and summarize”:
- The Annual Reviews checkpoint always runs. The skill searches
site:annualreviews.org, prioritizes the Annual Review of Sociology, and extracts at least five cited papers from any relevant review. One good review article is worth twenty search results. - Citation-chain expansion (required in full mode): backward from the reference lists of three to five key papers, then forward via “cited by” for the top foundational works.
- Wave 3 hunts for named critics. Before running methods searches, the skill loads a method-critics reference and searches for each planned method’s principal critic by name — Bell & Jones for age-period-cohort, Goodman-Bacon for staggered DiD. Finding the objection to your method before you commit to it is much cheaper than finding it in review.
The output is a landscape map along eight dimensions: field-evolution timeline · theoretical landscape (framework, core claim, proponents, predictions, support, status) · established findings · contested findings with a weight-of-evidence table · null and absent findings, kept distinct from each other · mechanism inventory (proposed vs. actually tested) · methodological landscape · ranked gap analysis. Full mode also emits a PRISMA flow diagram.
The ninth dimension is a theory handoff table — gap → theoretical implication → candidate framework → why the rivals are insufficient — plus a paste-ready paragraph for /scholar-hypothesis.
Two hard behaviours: the skill hard-stops if no local reference library is detected rather than quietly falling through to web-only search; and it writes the search log to disk before the first query and appends after every query, because context compaction silently destroys in-memory hit counts.
The full-text tier (v5.27). Phase 1 searches your library before it searches the web, and it does so in order: knowledge graph (pre-extracted findings) →
scholar-rag→ Zotero (bibliographic metadata) → web. The middle tier is new. When/scholar-rag statusreportsembedded > 0, the skill queries your index for full-text passages out of your own PDFs —rag_search("<topic>", k=8, hybrid=true)if the MCP server is registered (§8F.4), otherwise thequery.pyCLI. What comes back is cited paragraphs with page numbers, which is a different kind of evidence from either neighbour: the graph gives you findings, Zotero gives you metadata, this gives you the sentences. Retrieved passages are leads to verify, never citations in themselves; every reference still passes Tier 0–2 verification.
There is also a theory gate: if your prompt mentions hypotheses or theory sections, the skill stops and redirects you to /scholar-lit-review-hypothesis (§8A) rather than producing half of what you need.
8E.2 scholar-hypothesis — formalizing predictions
argument-hint: "[phenomenon or RQ] — optionally: [design type: quant/qual/comp/
computational] [journal: ASR/AJS/Demography/NHB/NCS/SciAdv]
[theory hint]"
> /scholar-hypothesis "why cumulative disadvantage widens the wealth gap" quant ASR
> /scholar-hypothesis "language shift among heritage speakers" qualitative \
"Language in Society" Fishman
The eight steps: frame the puzzle (as an anomaly, contradiction, extension, mechanism, or scope condition) → select frameworks (one primary, at most one secondary) → determine hypothesis placement mode → specify the mechanism chain → derive and formalize → map competing predictions → build a text DAG → write the theory section.
Placement mode is dictated by the journal, not by preference:
| Mode | Journals | Shape |
|---|---|---|
BLENDED | ASR, AJS, Social Forces | Each thematic subsection closes with its derived hypothesis |
SEPARATE | Demography (≤2 hypotheses) | A distinct hypotheses block — escalates to BLENDED at 3+ |
SEPARATE-PREDICTIONS | NHB, Science Advances, NCS | Natural-language predictions, no H1/H2 labels |
INTEGRATED-RQ | Language in Society, Journal of Sociolinguistics | No hypothesis labels at all; ends with “The Present Study” |
N/A | Qualitative | Propositional claims only |
Getting this wrong fails the skill’s own pre-save check.
The derivation chain table is the core mechanism. Every hypothesis must fill every column:
| H# | Literature gap | Gap type | Framework prediction | Mechanism-chain link | Hypothesis | |—|—|—|—|—|—|
If you cannot fill every column, the hypothesis is dropped. The named failure mode is a hypothesis that matches the framework’s general prediction without pointing at a specific step in the mechanism — which reads like theory but tests nothing in particular.
Mechanisms are specified through Coleman’s boat (situational → action-formation → transformational) or Hedström’s DBO (desires, beliefs, opportunities), classified by Elster’s types (cognitive, motivational, interactional, institutional, material), and bounded by a mandatory scope-condition matrix.
Seven hypothesis forms are supported: main effect · moderation (fan-spread vs. crossover) · mediation · curvilinear or threshold · comparative/group-level · boundary condition · null-as-finding. Intersectional hypotheses have their own required form: stated multiplicatively as an interaction term to be tested, not as two separate main-effect hypotheses.
Every hypothesis also gets a competing prediction: what a rival theory predicts, what the data would look like if the rival is right, and the specific test that distinguishes them. Plus an alternative-explanations checklist — selection, reverse causation, omitted variables, measurement artifact, compositional difference — each requiring a sentence of the form “We address [alternative] by [design feature].”
Causal-language calibration is enforced here as everywhere: observational data without an identification strategy gets “is positively associated with” and “predicts,” never “causes” or “the effect of.”
Theory-section word budgets: ASR/AJS 1,000–1,500 · Demography 600–1,000 · NHB/Science Advances 300–600 (embedded in the introduction) · NCS 200–400.
The skill ships a reference library of 25+ frameworks — stratification, networks and capital, culture, assimilation, life course, Coleman’s boat, DBO, racial formation, status characteristics, social movements, signaling, rational choice, contact hypothesis, labeling, intersectionality, neo-institutional theory, organizational ecology, practice theory, feminist standpoint, labor process, actor-network theory, and non-Western traditions including coloniality, world-systems, postcolonial theory, Ubuntu, and Confucian/guanxi frameworks — each with its core claim, mechanisms, best-use cases, key papers, and ready sentence starters.
Stop and check. Take one hypothesis from your own work and fill in the derivation chain table for it. If the “mechanism-chain link” column is the hard one, that is diagnostic: you have a prediction, not yet a theory.
8F. scholar-rag — a local vector database over your own library
Goal: turn every PDF you own into searchable, cited passages — and hand that search to Claude Code and Codex as a tool, so a lit-review session can quote your library instead of paraphrasing its memory of it.
argument-hint: "[setup|ingest|query|mcp|graph|status] [args], e.g. 'ingest' or
'query how does segregation affect mobility' or 'graph run'"
This is the newest skill in the suite (v5.27, July 2026) and the one that changes the texture of literature work most directly. §8C.0 laid out three ways to get the right text into the model’s window — RAG, agentic search, and the knowledge wiki — and argued they are complementary. scholar-rag is the first of the three, built properly:
scholar-knowledge (§8C) | scholar-rag (§8F) | |
|---|---|---|
| Stores | symbolic extracted findings, mechanisms, theories | verbatim full-text passages |
| Retrieval | keyword search over structured records | dense vector similarity (+ BM25, + rerank) |
| Answers | “what does the field claim about X?” | “show me the exact paragraphs, with page numbers” |
| Unit | a paper | a ~500-token chunk of a paper |
| Cost | one careful read per paper, upfront | one embedding pass, resumable |
They share paper identity (doc_id = sha256 of the normalized DOI or title), so a passage hit cross-links to the same paper’s extracted findings, and the GraphRAG layer seeds its entity graph from the knowledge graph rather than starting cold.
Everything is local.
bge-m3for embeddings,ollamafor the GraphRAG LLM,LanceDBfor vectors, a stdio MCP server for the interface. The only network traffic is the optional open-access PDF fetch. This matters more than it sounds: the alternative — uploading your whole Zotero library to a hosted vector service — is a data transfer you would have to disclose, and for anything under embargo or IRB restriction, one you could not make.
It is self-contained. The engine provisions its own CPython 3.12 venv via
uv, reads Zotero directly, and bundles its own logging. It has no hard dependency on the rest of the plugin, and degrades gracefully whenscholar-knowledgeis absent.
8F.1 The nine modes
| Mode | Triggers | What it does |
|---|---|---|
| 0 setup | setup, install, venv | One-time: provision the venv (PyMuPDF, LanceDB, sentence-transformers, mcp, GraphRAG deps) and prefetch bge-m3 |
| 1 ingest | ingest, build, index, add | Source → extract → chunk → embed → LanceDB. Resumable. The main deliverable |
| 2 query | query, search, find, ask | Dense retrieval, optionally hybrid BM25 + cross-encoder rerank, with section/year filters |
| 3 mcp | mcp, register, serve, connect | Register the stdio MCP server with Claude Code and Codex |
| 4 graph | graph, graphrag, neighbors, communities, global | Seed → LLM entity extraction → Leiden communities → summaries; then local/global/neighbors search |
| 5 status | status, stats, coverage | Documents by stage, chunk counts, no-PDF coverage, graph counts |
| 6 citations | citations, cites, coupling | One OpenAlex call per DOI → direct citations + bibliographic coupling + co-citation → Leiden paper communities. The research lineages in your library |
| 7 keywords | keywords, tags, topics | Loads Zotero tags (~69% of items), OpenAlex topics (~95% of DOI’d papers), and the in-text “Keywords:” line (~39%). Merged under the same identity as LLM entities |
| 8 semantic | semantic, knn, duplicates | Re-uses the chunk vectors you already have: paper↔paper kNN, entity synonym linking, duplicate detection |
full runs 0 → 1 → 3. GraphRAG (mode 4) is deliberately not in full, because it is the long, LLM-bound stage — hours of local inference over a real library.
8F.2 Build it
# one-time
> /scholar-rag setup
# the whole Zotero library, auto-detected; --limit to trial a subset first
> /scholar-rag ingest
Under the hood that is run-ingest.sh, and it is worth knowing you can drive it directly for the long runs:
$ bash "$RAG_ASSETS/run-ingest.sh" --batch 64 # foreground, watch it
$ bash "$RAG_ASSETS/run-ingest.sh" --batch 64 --background # detach; tail the log
$ bash "$RAG_ASSETS/run-ingest.sh" --source folder --folder ~/pdfs
$ bash "$RAG_ASSETS/run-ingest.sh" --ocr # scanned PDFs, via llama3.2-vision
Three stages, and every document carries a status through them — new → extracted → embedded, or no_pdf / failed:
Zotero/PDFs ──ingest──▶ documents(new)
PDF ──extract (PyMuPDF → pdftotext → vision-OCR)──▶ raw/text + documents(extracted)
text ──chunk (section-aware, ~500 tok, overlap) + bge-m3──▶ LanceDB + documents(embedded)
Each stage processes only rows not yet advanced, so a killed run continues where it stopped — which you will need, because a full library is embedding-bound: thousands of PDFs is hours even on Apple-silicon MPS. Run it detached.
The extraction ladder is worth understanding, because it determines quality: PyMuPDF first (fast, keeps page mapping), pdftotext as fallback, and vision-OCR last for scanned documents. Extracted text is cached page-mapped in raw/text/<doc_id>.json, which is what makes re-chunking or re-embedding with a different model cheap — you do not re-extract.
8F.3 Query it
> /scholar-rag query how does residential segregation affect intergenerational mobility?
# or directly, with filters and reranking:
$ rag_py query.py "identification strategy" -k 6 \
--section methods,results --year-min 2010 --rerank --json
Every hit comes back with an author-year citation, section, page range, DOI, and similarity score. That page number is the point: it is what lets you verify a claim in ten seconds instead of re-reading a paper, and it is what scholar-citation uses to check a claim against its source (§16.5).
8F.4 Hand it to the agent — the MCP server
> /scholar-rag mcp
$ bash "$RAG_ASSETS/mcp-setup.sh" # register with every detected host
$ bash "$RAG_ASSETS/mcp-setup.sh" --print-only # just print the .mcp.json / config.toml snippets
This registers a stdio MCP server (§3.6) exposing four tools:
| Tool | Signature | Returns |
|---|---|---|
rag_search | (query, k=8, section="", year_min=0, hybrid, rerank) | cited passages nearest the query |
rag_get_document | (doc_id, include_text=False) | the full bibliographic record |
rag_neighbors | (doc_id, k=8) | papers sharing entities or citations |
rag_stats | () | coverage counts + index manifest |
Restart the session to pick the tools up.
8F.4.1 The three skills it is wired into
This is the part that changes your workflow without you doing anything. Once an index exists, three skills reach for it on their own — you do not invoke scholar-rag during a lit review, you just have a better lit review. Each checks /scholar-rag status first and degrades silently to its old behaviour if there is no index.
| Skill | Where it fires | What it uses the passages for |
|---|---|---|
scholar-lit-review (§8E.1) | Phase 1, between the knowledge-graph check and the Zotero search | A full-text tier: cited passages out of your own PDFs, not just metadata |
scholar-write (§14.2A) | Alongside the citation-integrity rule, in all modes — draft, revise, polish | Phrasing claims against what the page actually says instead of from memory |
scholar-citation (§16.5) | Step V-3.5, claim-level checking, keyed by DOI | Locating the supporting passage + page without opening the PDF |
What this does not do.
rag_searchsurfaces text; it does not mint citations. Every reference still passes through the Verified Citation Pool and/scholar-citation(§16). Treat a retrieved passage as a lead to verify, not as a source you have confirmed — the index can only be as honest as the PDF it chunked, and a passage torn from its section can still be misread. The division of labour is worth stating once and remembering:scholar-ragowns the text,/scholar-citationowns the bibliographic record.
8F.5 GraphRAG — the long pole
Vector search finds passages near a query. It cannot answer “what are the major theoretical camps in this literature?”, because no single chunk contains that answer. GraphRAG builds the structure that can:
$ rag_py graphrag.py seed # import scholar-knowledge concepts + citation edges (fast, no LLM)
$ rag_py graphrag.py extract # LLM entity/relation extraction per paper — the long stage, resumable
$ rag_py graphrag.py build # dedup entities → Leiden communities
$ rag_py graphrag.py summarize # LLM community summaries (the global-search corpus)
$ rag_py graphrag.py run --limit 50 # the whole chain, bounded
runis the SHORT chain, and that is a trap. It executes exactlyseed → extract → build → summarize. It does not run citations, keywords, or semantic — the three stages that must land beforebuild, becausebuildis what dedups entities and computes the Leiden communities. Runbuildearly and those communities are computed on a graph with no bibliographic edges, no keyword nodes, and no entity merges; fixing it afterwards means re-runningbuildandsummarize, which is the expensive LLM stage. Use the order in §8F.6.
$ rag_py graphrag.py local "mechanisms linking neighborhood to health" # entity-grounded passages
$ rag_py graphrag.py global "what are the major theoretical camps here?" # map-reduce over communities
$ rag_py graphrag.py neighbors <doc_id>
Model selection is the thing that will bite you. Extraction defaults to
deepseek-r1:32b, which runs and honorsformat=jsonbut is a reasoning model — slow for bulk work.gpt-oss:20bis the faster ideal, but fails with atensor "blk.0.ffn_down_exps.weight" size overflowon older ollama builds;brew upgrade ollama, restart the server, thenexport RAG_GRAPH_MODEL=gpt-oss:20b. If that is unavailable, a fast instruct model is the practical answer:ollama pull qwen2.5:7b-instruct. Extraction is section-bounded (12k chars by default) and resumable per document, so run it detached and let it cross sessions.
8F.6 The three stages that make the graph worth having
Entity co-mention answers “which papers use the same words.” These three answer “which papers actually build on each other,” “what does the field already call this,” and “which papers are plainly about the same thing.” All three were added after the first version of this handbook and none of them is in graph run.
$ rag_py citations.py fetch # one OpenAlex call per DOI — resumable, cached
$ rag_py citations.py build # direct cites + coupling + co-citation → paper communities
$ rag_py keywords.py load # Zotero tags + OpenAlex topics + the in-text Keywords line
$ rag_py semantic.py entities # link entity synonyms the normalizer cannot merge
$ rag_py semantic.py docs # paper↔paper kNN — reaches papers with no DOI at all
$ rag_py semantic.py duplicates # the same work ingested twice
Why each earns its runtime:
- citations —
seedalone covered about 12% of a 5.5k-paper corpus. Coupling (A and B cite the same work) reaches far more pairs than direct citation, and stays useful for recent papers that nothing cites yet. - keywords — inherently multi-document: one tag covers dozens of papers, which is exactly what an entity graph built per-paper is short of. And no hallucination risk.
- semantic — a paper with no DOI never enters the OpenAlex cache, so it is invisible to the whole bibliographic layer. Adding semantic edges lifted paper-graph coverage from 72% to 95% (3,923 → 5,189 papers) on that same corpus. It also merges
residential segregation/neighborhood segregation/spatial segregation, which normalize to three distinct keys and are one concept.
The order is not arbitrary — later stages consume earlier ones, keywords need the OpenAlex cache, and every graph stage must precede build:
setup → ingest → mcp → citations fetch → citations build
→ graph seed → graph extract → keywords load → semantic entities
→ graph build → graph summarize
Thresholds are not interchangeable between
docsandentities. Document similarity sits far higher than phrase similarity: the median top-10 paper neighbour scored 0.886, so a 0.55 floor keeps essentially everything (10 edges/paper, including a historical-sociology monograph next to an LLM benchmark paper). The 0.90 default gives 3.5 edges/paper. Check the distribution before trusting a cutoff.
8F.7 Where it lives
~/.claude/scholar-rag/ (override with $SCHOLAR_RAG_DIR)
├── corpus.sqlite ← documents + chunks manifest (the source of truth for status)
├── raw/text/<doc_id>.json ← page-mapped extracted text (cache; enables re-chunk)
├── raw/meta/<doc_id>.json ← full bibliographic record
├── index/ ← LanceDB table `chunks` (vector + metadata + BM25 FTS)
├── graph/ ← entities, relations, doc_edges, communities, summaries
├── manifest.json ← embed model + dim + chunk params + build stats
├── logs/ ← trace-scholar-rag.ndjson, ingest-run-*.log
└── .venv/ ← self-contained CPython 3.12
It is user-scoped, not project-scoped — the same store serves every project, exactly like scholar-knowledge. That is the right call for a reference library, which is a property of the scholar rather than the paper.
The feedback loop back to §8C. Extraction is the expensive part of both skills, and now only one of them pays it. Once a build finishes, run /scholar-knowledge re-extract: nodes that were ingested from an abstract alone can be upgraded from the full text scholar-rag already extracted. A library you index once makes the wiki deeper for free.
Configuration, all via .env or environment: SCHOLAR_RAG_DIR · SCHOLAR_ZOTERO_DIR (auto-detected) · EMBED_MODEL (default BAAI/bge-m3) · RAG_CHUNK_CHARS / RAG_CHUNK_OVERLAP · RAG_GRAPH_MODEL / RAG_SUMMARY_MODEL · RAG_OCR_MODEL · OLLAMA_HOST.
8F.8 Inspect
$ rag_py ingest.py status # documents by stage, chunk counts, no_pdf coverage
$ rag_py graphrag.py status # entities / relations / communities / summaries
Four checks before you trust it:
setup-venv.shreported every importok, and told you whether torch has MPS. (No MPS means a much slower build — plan accordingly.)ingest.py statusshowsembedded > 0and a saneno_pdfcount. A largeno_pdfmeans Zotero items whose attachment never synced locally; fix that in Zotero, or let the open-access fetch fill them.- A query on a topic you know returns the paper you expect, with the right author-year and a page number you can check.
- The MCP handshake lists all four tools. If it lists none, you did not restart the session.
Data safety. The corpus is published papers, so it is normally
CLEARED. Butfoldermode will happily ingest a directory of unpublished drafts or a colleague’s shared PDFs. If a project sidecar marks any inputNEEDS_REVIEWorHALTED, route through/scholar-safetyor/scholar-initfirst (§6) — the fact that embedding is local does not make ingestion consent-free.
9. scholar-design — design before data
Goal: lock the estimand, the model ladder, the sample restrictions, and the forbidden language. After this skill, the analysis script is essentially a template-fill.
This is the largest skill in the suite (roughly 16,000 words of instructions) and the one that most repays reading its dispatch table before you type.
argument-hint: "[quant|qual|mixed|experiment|power|methods-section|pap|
computational|NLP|ML|network|ABM|premortem|blueprint]
[research question] [optional: data source, design type,
journal target]"
9.0 Sixteen design modes
| Mode | Trigger keywords | Steps it runs |
|---|---|---|
| Quant / observational | quant, regression, survey data, panel, observational | 0→1→causal gate→3→4→5→6→7 |
| Causal | causal, DiD, FE, RD, IV, matching, natural experiment, DAG | Invokes /scholar-causal mid-flow as a gate |
| Qualitative | qual, interview, ethnography, case study | 0→1→4(qual)→7(qual template) |
| Mixed methods | mixed, mixed-methods, multi-method | All steps; integration point flagged in Step 7 |
| Experiment | experiment, RCT, vignette, conjoint, list experiment | 0→1→2→3(power)→5→7 |
| Cluster RCT | cluster RCT, cluster randomized, group randomized | 0→1→2d→3e→5→7 |
| Audit / correspondence | audit, correspondence, resume audit, discrimination | 0→1→2e→3f→5→7 |
| Stepped-wedge | stepped-wedge, sequential rollout | 0→1→2f→3g→5→7 |
| SMART | SMART, adaptive intervention, DTR | 0→1→2g→3h→5→7 |
| Bayesian | Bayesian, prior elicitation, assurance | 0→1→10→7 |
| Power only | power, sample size, MDES | Step 2/3 only |
| Methods only | methods section, write methods | Step 7/8 only |
| PAP only | pap, pre-analysis plan, preregistration, OSF | Step 6/7 only |
| Computational | computational, NLP, ML, network, ABM, corpus, annotation, topic model, classifier | 0→1→9→7 (NCS/Science Advances template) |
| Pre-mortem | premortem, design review, review blueprint | Step 11 — reviewer panel against an existing blueprint |
| Section blueprint | blueprint, section blueprint, generate blueprint | Step 12 — deterministic per-section authoring contract |
> /scholar-design quant "did hukou/cohort gaps in internet access narrow while
use-hours gaps persisted?" CFPS 2010-2020 "Social Forces"
descriptive/decomposition
> /scholar-design power "MDES for a 2,000-respondent survey experiment"
> /scholar-design computational NLP "polarization in news coverage with BERT"
"Science Advances"
> /scholar-design premortem digital-divide-china-cfps
> /scholar-design blueprint digital-divide-china-cfps
9.1 The twelve steps
Step 0 — Setup. Derives the project root, opens the RAO trace, confirms RQ, data constraints, and target journal with you.
Step 1 — Design selection decision tree. A fourteen-row table mapping (goal × data structure × assignment) to a recommended design and journal fit. Any DiD / FE / RD / IV / matching / mediation / natural-experiment claim triggers the causal gate, which hands off to /scholar-causal (§8D) and comes back with an identification strategy.
Step 1.5 — Multi-comparison policy declaration. Mandatory whenever a pre-registered hypothesis family carries K ≥ 3 tests. It emits a YAML block naming the family, K, the correction method, alpha, and the decision rule — and it makes peer-reviewer-demographics a required member of every later review panel.
Why this step exists. A real run in this corpus (cohab-fertility-cfps) shipped “PARTIAL support” for a nine-test family with no correction applied. Declaring the correction at design time — before you have seen a single p-value — is the only version of this that is not p-hacking.
Step 1.6 — Data-source requirements. Emits a ## Data-Source Requirements YAML block (unit_of_analysis, geographic_scope, time_window, design_structure, required_n, required_constructs[], excluded_designs[]) that scholar-data (§9A) consumes to score candidate datasets.
Step 2 — Experimental design module. Seven sub-modules, each with a design template, R analysis code, an assumptions checklist, and a write-up template: 2a RCT · 2b survey/vignette · 2c list experiment · 2d cluster RCT · 2e audit/correspondence · 2f stepped-wedge · 2g SMART.
Step 3 — Power analysis. Eleven sub-modules:
| Sub-step | Design | Tooling |
|---|---|---|
| 3a | Standard tests | pwr (t, r, χ², ANOVA), WebPower::wp.logistic |
| 3b | Multilevel / HLM | simr::powerSim, powerCurve |
| 3c | MDES for fixed-N secondary data | The one you need for CFPS/GSS work |
| 3e | Cluster RCT | clusterPower, CRTSize::n4means, manual DEFF |
| 3f | Audit / correspondence | McNemar exact power, pwr.2p.test, simulation |
| 3g | Stepped-wedge | swCRTdesign::swPwr, Hussey-Hughes, Woertman DEFF |
| 3h | SMART | Oetting formula, Nahum-Shani rules of thumb |
| 3i | Three-level multilevel | simr, ICC sensitivity at 0.01 / 0.05 / 0.10 |
| 3j | DiD / RD / mediation | DeclareDesign, rdpower, pwr2ppl::medjs |
| 3k | SEM / CFA | N ≥ 200; N ≥ 10 × parameters |
For secondary data your N is fixed, so 3c is the honest step: you are not choosing a sample size, you are reporting the smallest effect your fixed sample could have detected.
Step 4 — Variable specification. The variable dictionary table (Role · Name · Construct · Operationalization · Source · Type · Range · Notes), a measurement-validity checklist, and a DAG sketch.
Step 5 — Analytic strategy. Model selection by outcome type; SE and clustering choices; the presentation sequence (Model 1→4 plus appendix robustness). Note the sociology-journal rule the skill enforces: always report average marginal effects, not odds ratios or raw log-odds, for any binary, ordinal, or GLMM outcome in ASR/AJS-style venues.
Step 6 — Robustness plan. A pre-committed sensitivity registry. Each entry becomes blocking at analysis time unless marked optional: true with a rationale. A limitations-section bullet does not satisfy this gate — only a spec_id that later shows up in the spec registry does.
Step 7 — Pre-analysis plan. Ten sections — RQ and hypotheses, design, primary outcome, covariates, primary analysis, subgroup/heterogeneity, robustness, multiple-comparisons correction, deviations policy, sample size — plus an OSF registration checklist.
Step 8 — Write the Data and Methods section, calibrated to the target journal’s word budget and structure.
Step 9 — Computational methods design. Claim-type taxonomy (measurement / description / prediction / causal); corpus and sampling design with minimum-N-by-method tables; annotation design with a codebook template and inter-rater-reliability targets (κ ≥ 0.70 minimum, ≥ 0.80 preferred, plus Krippendorff’s α and ICC); train/test/validation splits with the no-peek rule; pre-specified evaluation metrics; network-boundary specification and ERGM/SAOM data requirements; ABM design under the ODD protocol with SALib Sobol/Morris sensitivity analysis.
Step 10 — Bayesian design. Prior elicitation, brms fitting, convergence diagnostics, Bayesian sample size and assurance, reporting template.
9.2 What appears in design/
From the real CFPS run — note that some of these are written by scholar-design and some by the orchestrator’s later phases, which is why the folder accumulates:
design/
├── design-blueprint-digital-divide-china-cfps-2026-05-04.md ← scholar-design
├── data-blueprint-digital-divide-china-cfps-2026-05-04.md ← scholar-data
├── pre-mortem-quant-2026-05-04.md ← Step 11 panel
├── pre-mortem-demographics-2026-05-04.md
├── pre-mortem-senior-2026-05-04.md
├── limitations-accepted.md ← RED dimensions you accepted, with reasons
├── variable-dictionary.csv
├── model-specs.json
├── coef-map.csv
├── test-inventory.json
├── project-brief.md
└── results-lock-2026-05-04.md ← written later, at the results-lock phase
9.3 The estimand and model ladder (from the real blueprint)
## 0. Headline finding (locked at Phase 3.5)
This design commits to Y2 (weekly hours of internet use among users) as the
focal outcome for the headline table and abstract sentence.
> Net of education, income, occupation, household composition, and
> province × wave fixed effects, the rural-hukou penalty on weekly internet
> hours among Chinese adults who use the internet (Y2) in 2018 is
> statistically indistinguishable from the penalty in 2014 — Y2 being
> measured only in CFPS waves 2014, 2016, and 2018 — even as the binary
> access gap (Y1, observed across CFPS 2010–2020) closed from approximately
> 40 to 15 percentage points between 2010 and 2020 […].
## 1.1 Estimation strategies in correspondence with hypotheses
| H | Estimator | Identifying assumption |
|----|---------------------------------|---------------------------------------|
| H1 | Logit (Y1) + OLS with province× | Conditional indep. of hukou and |
| | wave FE on Y2|Y1=1 | unmeasured infra within province×wave |
| | (Tobit MLE cross-check in | (cross-check adds censoring + tail- |
| | robustness section) | distribution assumptions) |
| H2 | Person FE within-changes; | HAPC: cohort & period exchangeable |
| | HAPC; Deaton-Paxson bounds | given age |
| H3 | Three-way interaction; | Common support; linearity within |
| | threefold Oaxaca-Blinder | group |
| H4 | Person FE on co-residence | No third unmeasured time-varying |
| | changers | confounder |
## 1.3 What we explicitly do NOT claim
- No causal interpretation of hukou
- No causal interpretation of cohort
- No third-level (returns) claim in this paper
One line in this blueprint is load-bearing and easy to skip past:
outcome_mechanism_alignment: prevalence-stock
The permitted values are entry-process, prevalence-stock, dissolution, and multi-state. If this line is missing, design verification fails. It exists because an April 2026 audit found a design applying an entry-process mechanism story to a prevalence-stock outcome — a silent mismatch that produces a coherent-sounding paper answering a question the data cannot address.
9.4 Step 11 — the pre-mortem panel
scholar-design dispatches a peer-reviewer panel before any data is touched. The roster is chosen by design type:
| Design type | Agents dispatched |
|---|---|
| Quant / observational | peer-reviewer-quant, peer-reviewer-theory, peer-reviewer-senior (+ peer-reviewer-demographics if population claims or a K ≥ 3 family) |
| Qualitative | peer-reviewer-qual, peer-reviewer-theory, peer-reviewer-senior, peer-reviewer-ethics |
| Mixed methods | peer-reviewer-mixed-methods, peer-reviewer-quant, peer-reviewer-qual, peer-reviewer-senior |
| Computational | peer-reviewer-computational, peer-reviewer-quant, peer-reviewer-theory, peer-reviewer-senior |
| Sociolinguistic | peer-reviewer-ling, peer-reviewer-theory, peer-reviewer-senior |
| Human subjects | add peer-reviewer-ethics |
Each reviewer scores thirteen dimensions RED / YELLOW / GREEN with a justification: RQ clarity · theory↔hypothesis linkage · operationalization validity · identification strategy · sample adequacy · internal validity · external validity · ethics · measurement and missingness · analytic-plan specificity · feasibility · journal fit · multi-comparison policy. Each memo closes with OVERALL:, TOP-3 FATAL CONCERNS:, and RECOMMENDED ACTIONS:.
The panel is mandatory to dispatch but advisory in adjudication: you accept or revise each RED dimension, up to three iterations, and design-review-check.sh blocks the next phase on any un-accepted RED. Exit codes: 0 GREEN proceed, 1 RED un-accepted → halt, 2 YELLOW → may proceed with approval. After three iterations it hard-halts, on the theory that persistent RED is a structural design problem needing human judgment, not more auto-critique.
The provenance requirement — this is the one to internalize. Every pre-mortem memo must carry a Reviewer Provenance table with real columns:
reviewer_agent | task_invocation_id | dispatched_at | model. Placeholders likeTBDor—fail the gate, anddesign-review-check.shcross-checks the process log for zeropeer-reviewer-*dispatches. The skill names inline-roleplayed reviewers — the model writing a “review” in its own voice instead of dispatching a real subagent — as the #1 silent failure of the whole pipeline. A post-mortem traced roughly 71% of manuscript defects to skipped or simulated review. §13’s surrogate disclosure is this same failure mode, caught and declared.
In our actual run, the senior reviewer flagged: “Y1 (binary access) is the wrong headline outcome. Y2 (use intensity) is the theoretically distinctive contribution and should be the abstract-target sentence.” That single comment changed the focal outcome before any analysis ran, saving an entire revision cycle.
9.5 Step 12 — the section blueprint
Run late — after the results lock, before drafting — and notable because it is deterministic: generate-section-blueprint.sh reads the results lock, the design blueprint, and the hypotheses, and emits the contract with no LLM in the loop. The drafting skill cannot negotiate with it.
> /scholar-design blueprint digital-divide-china-cfps
Writes drafts/section-blueprint.json (canonical, schema v5) plus a human-readable .md companion whose footer says, accurately, “Hand-edits will be overwritten.”
Per section — abstract, introduction, theory, methods, results, discussion — the contract carries target_words_min/max, required_hypotheses[], required_tokens[], reader_outcomes[], exemplar_paths[], derived_moves, structural_moves[], and forbidden_patterns[]. Those fields sit in a precedence ladder that scholar-write must obey:
| Tier | Fields | Status |
|---|---|---|
| 1 | target_words_min/max, required_hypotheses[], reader_outcomes[] | Binding |
| 1.5 | reader_outcomes_verifiers[] | Binding, machine-verified |
| 2 | exemplar_paths[], derived_moves | Primary source of prose rhythm |
| 3 | structural_moves[] | Advisory fallback |
| 4 | forbidden_patterns[] | Hard constraint |
Exit codes: 0 GREEN (JSON and MD written), 1 RED (missing results-locked/LATEST.txt, manifest, or design blueprint). Downstream, blueprint-completeness-check.sh re-validates the schema before drafting may start.
9.6 Inspect
limitations-accepted.md— every RED you accepted, in the form[RED-N: dimension] rationale. If this file is empty and the panel raised REDs, something was waved through.model-specs.json— the focal outcome, focal table, focal sample.- The pre-mortem memos — read the
TOP-3 FATAL CONCERNSof each, and check the provenance table has real invocation IDs. - The
outcome_mechanism_alignmentline — does the mechanism story match the outcome type?
Stop and check. Name the focal outcome, the focal table, and the focal sample without looking. Then name one thing the design says you may not claim. If you cannot do both, do not proceed.
9A. scholar-data — find, fetch, and govern the data
Goal: locate a dataset that actually fits the design, download it where possible, and produce the variable dictionary, IRB materials, and management plan the rest of the pipeline assumes exist.
This skill is invisible in the CFPS walkthrough because we arrived with data in hand. For most participants starting a new project it is the single most useful skill in the suite: it ships a directory of 100+ datasets across 14 categories, of which 57 are machine-scored and 42 can be downloaded automatically.
argument-hint: "[dataset|survey|interview|irb|manage|vignette|scrape|web|api|
social media] [topic or research question]
[optional: population, journal, design]"
9A.1 Eight workflows
| Workflow | Triggers | What you get |
|---|---|---|
| 0 — Secondary data directory | dataset, find data, what data, secondary | Topic → dataset matching, fit verification, scored suggestions, auto-fetch |
| 1 — Variable dictionary | variable, measure, operationalize, construct, blueprint | Variable table, measurement-validity checklist, one-page data blueprint |
| 2 — Survey instrument | survey, questionnaire, scale, Qualtrics, Prolific, vignette, conjoint, list experiment | Question construction, established scales, sampling plan, pilot protocol, experimental modules |
| 3 — Interview protocol | interview, qualitative, protocol, ethnography, focus group | Protocol architecture, question sequence, sensitive-topics handling, multilingual fieldwork |
| 4 — Administrative data | admin, records, linkage, Census, IPUMS | Access routes, documentation review, record linkage, spatial data |
| 5 — IRB and ethics | IRB, ethics, consent, CITI, human subjects | Exemption categories, waiver criteria, application components, security standards |
| 6 — Data management | manage, codebook, clean, pipeline, DMP, git | Directory scaffold, git hygiene, codebook, data-management plan |
| 7 — Web and digital data | scrape, crawl, API, social media, Twitter, Reddit, news | Legal/ethical framework, API-first strategy, scraping code, storage and provenance |
> /scholar-data dataset "childhood poverty and adult health" US NHB
> /scholar-data survey "hiring discrimination by race and record" vignette
> /scholar-data irb "web scraping public tweets on immigration policy"
> /scholar-data manage "codebook and DMP for an NSF proposal"
9A.2 The dataset directory
Fourteen categories, each a table of datasets with coverage, unit, N, key variables, and access tier:
- Sociology / stratification / labor — GSS, PSID, NLSY79/97, Add Health, SIPP, ACS, CPS
- Demography / family / health — HRS, NHANES, NHIS, NCHS Vital Statistics, CDC PLACES, UN World Population Prospects
- Education — NELS/ELS/HSLS, NAEP, College Scorecard, IPEDS
- Political behavior — ANES, CCES, Pew datasets
- Immigration / ethnicity / language — CPS-ASEC, New Immigrant Survey, ISSP, WVS/EVS, Luxembourg Income Study
- Neighborhoods / spatial / administrative — Census tract, HMDA, TIGER/Line, HOLC redlining maps, Opportunity Atlas
- Text / digital / computational — Congressional Record, Common Crawl, Google Trends, Twitter/X historical
- Crime and criminal justice — NCVS, UCR/NIBRS, NSDUH, NCRP, Sentencing Commission
- International surveys — WVS/EVS, ISSP, ESS, Eurobarometer, Afrobarometer, Latinobarómetro, Asian Barometer, LIS/LWS, PISA, TIMSS/PIRLS, DHS, MICS
- Economic / labor / macro — FRED, Penn World Table, EU-KLEMS, LEHD, OECD, Eurostat, ILO
- Global health / environment — WHO GHO, Global Burden of Disease, IPUMS International, NASA SEDAC, FAOSTAT
- Science of science — OpenAlex, Semantic Scholar, Dimensions, ORCID, NSF SED, Crossref, Web of Science
- General repositories — Harvard Dataverse, ICPSR, Zenodo, OSF, Figshare, QDR, Roper iPoll, Data.gov, UK Data Service, GESIS, Google Dataset Search, Kaggle
- Restricted federal / linked — SSA earnings via FSRDC, IRS/Treasury linked microdata, state administrative records, CMS claims
Plus an international/longitudinal supplement: UKHLS, German SOEP, IHDS, CFPS, EVS, UK Biobank, Fragile Families.
9A.3 The dataset scorer — how a recommendation is actually made
Step 0c.5 runs a deterministic Python scorer, not a vibe:
$ python3 scripts/gates/dataset-suggester.py "$PROJ" --top 3 --auto
It reads design/data-requirements.yml (the YAML scholar-design Step 1.6 emitted), falls back to the blueprint and then to project-state.md, and scores every entry in references/datasets-index.json — 57 datasets with fields unit_of_analysis, geographic_scope, time_window, design_structure, key_constructs[], access_tier, auto_fetch{}.
| Criterion | Weight |
|---|---|
| Unit of analysis exact match | +3.0 |
| Unit off by one hierarchy level | +1.5 |
| Unit off by more than one level | hard REJECT |
| Geographic overlap | +2.0 |
| Time window ≥ 50% covered | +1.5 |
| Each matched construct | +2.5 (capped at 7.5) |
| Access tier | 0 – 1.0 |
| Keyword tie-breaker | +0.5 |
The decision rule: ≥ 6.0 auto-select · < 6.0 needs user confirmation · zero candidates passing the hard filters exits 3, at which point the orchestrator must ask you to relax a constraint or add a dataset to the directory. There is also an existing-data audit mode: if you brought your own dataset and something in the directory outscores it, you get a YELLOW flag telling you so.
9A.4 Auto-fetch
Step 0d runs real downloads for anything in the “Immediate” access tier — 18 datasets via an R package, 24 via direct URL. Sources that need no key at all, and are therefore the fastest path to a working project: World Bank, NHANES, CDC PLACES, GSS, Google Trends, BLS v1, College Scorecard, Opportunity Atlas, GDELT, OpenAlex, Eurostat, WHO GHO, Penn World Table, FAOSTAT, Harvard Dataverse, Zenodo, Semantic Scholar, Crossref, Data.gov.
Keys and registrations you may need:
| Env var | Unlocks |
|---|---|
CENSUS_API_KEY | ACS, CPS via tidycensus / ipumsr |
FRED_API_KEY | FRED macro series via fredr |
CDC_APP_TOKEN | Higher PLACES/Socrata rate limits (optional) |
FBI_API_KEY | Crime Data Explorer |
S2_API_KEY | Semantic Scholar (optional) |
TWITTER_BEARER | X API v2 |
REDDIT_CLIENT_ID / REDDIT_CLIENT_SECRET | Reddit via PRAW |
SCHOLAR_CROSSREF_EMAIL | OpenAlex/Crossref polite pool, scraper User-Agent |
Store them in .Renviron or .env, both gitignored. Never in a script.
On a successful fetch the skill writes data/raw/download-manifest.md (File · Source · Date fetched · N rows · Variables) and flips PROJECT STATE from data-status: no-data to existing-data, which unlocks data-available mode downstream. If an API key is missing, the skill is required to ask you for it rather than silently degrading to a code template.
9A.5 Workflow 7 — the web-data rules that matter
The legal and ethical framework comes before any code: robots.txt, terms of service, rate limits, CFAA, GDPR, IRB. The web-data IRB decision table maps public tweets → Exempt, Reddit → Exempt/Expedited, private groups → Full board. The governing principle is AoIR 2019, quoted in the skill: legal accessibility ≠ ethical appropriateness.
Platform realities the skill documents, current as of this build:
- Twitter/X — the Academic Research track was discontinued in January 2025. Full-archive search now needs Pro (~$5K/month) or Enterprise; the free Basic tier caps at 10,000 tweet reads per month. For new projects, consider Bluesky (AT Protocol, free firehose) or the Meta Content Library.
- Reddit — Pushshift archive access was restricted in 2023; use PRAW against the live API.
- Never share raw tweet text. Share tweet IDs only.
The API-first order is: platform API → GDELT / MediaCloud / Internet Archive → rvest + polite (R) or requests + BeautifulSoup (Python) → chromote / playwright for JavaScript pages. Everything gets logged to docs/scraping-log.md with robots.txt status, ToS review, IRB determination, rate limiting, and record counts.
9A.6 Files written
output/<slug>/data/scholar-data-<topic>-<date>.md ← the data plan
<proj>/data/dataset-selection.json ← scorer output + fetch params
data/raw/download-manifest.md ← what was fetched, when
data/raw/<source>-<params>.{rds,csv,parquet} ← the actual data
data/codebooks/ ← var_name | var_label | type |
values | missing_codes | source
docs/scraping-log.md · docs/data_cleaning_log.md
.gitignore ← raw data, credentials excluded
The directory scaffold sets data/raw/ read-only (chmod -w). Raw data is an input, never an output.
9A.7 Gotchas
scholar-datais a Tier B skill: it checks the safety sidecar but does not implement the full LOCAL_MODE dispatch contract. ALOCAL_MODEfile must be routed to/scholar-analyzeor/scholar-edainstead.- List experiments are statistically inefficient — plan N ≥ 500 per arm.
- Conjoint designs need roughly N ≥ 500 × 5 tasks to detect an AMCE of 0.05.
- Probabilistic record linkage (
fastLink) must report match rates and characterize matched vs. unmatched cases; selective linkage is itself a validity threat.
Stop and check. Run /scholar-data dataset on your own research question. Look at the top three scored candidates and the score breakdown. If the top score is under 6.0, the honest reading is that your design and the available data are not yet aligned — fix that now, not at Phase 5.
10. scholar-eda — look before you leap
Goal: build the analytic sample, diagnose missingness, produce Table 1, and check distributional assumptions — before running any model.
argument-hint: "[dataset path or 'paste data below'] [outcome variable(s)]
[optional: key predictor, causal design, journal,
panel/cross-sectional]"
10.1 Run
> /scholar-eda data/processed/cfps-panel-long.rds
outcomes=y1_access,y2_hours,y3_breadth
focal=hukou_rural,cohort,female,eduy
panel
journal="Social Forces"
More examples across the input modes:
> /scholar-eda data/gss2022.dta happiness education income
> /scholar-eda NHANES 2017-2018 systolic_bp age race cross-sectional
> /scholar-eda paste data below wage education, tenure for ASR panel
10.2 Three input modes, and the gate in front of all of them
| Mode | Trigger | Behaviour |
|---|---|---|
| 1 — Local file | a path to .csv / .dta / .rds / .parquet / .xlsx | Standard in-context loader if the file is CLEARED/ANONYMIZED/OVERRIDE; a single summary-only Rscript/python3 heredoc if LOCAL_MODE |
| 2 — Pasted data | paste data below | Reads inline. Note the honest warning the skill gives: pasted data is already in your context by definition, so it offers to write it to a temp file, re-gate it, and continue under LOCAL_MODE |
| 3 — Online source | NHANES 2017-2018, GSS, a tidycensus/WDI reference | Fetches via the R package or API |
Before any of that, Phase 0a — the Data Safety Gate runs safety-scan.sh on every input, sets SAFETY_STATUS, and blocks on YELLOW or RED until you choose. If scholar-full-paper already set a status at Phase −1, scholar-eda inherits it and never downgrades it.
Phase 0c is the causal gate. The skill scans your prompt for DiD, difference-in-differences, FE, RD, regression discontinuity, IV, instrumental variable, matching, synthetic control, mediation, propensity score. On a hit it prints a redirect to /scholar-causal (§8D) before resuming at Phase 1. This is advisory, not a hard stop — but taking the redirect is nearly always right, because covariate choice depends on the DAG.
10.3 The eleven phases
| Phase | What happens | The decision it forces |
|---|---|---|
| 1 Orientation | skim()/glimpse(), unit-of-analysis and ID-uniqueness check, plm::pdim for panels | Is the unit of analysis what you think it is? |
| 2 Sample construction | Sequential filters printing N-before/N-after, exclusion-flow table, survey-weight design object | Does every exclusion have a reason you would print? |
| 3 Missing data | naniar summaries and upset plots, Little’s MCAR test, shadow-matrix logit | <5% listwise · 5–20% MICE · >20% flag + sensitivity · >50% consider dropping |
| 4 Univariate | Distributions against theme_Publication(), transform decision table, sparse-category flag (<5%) | log · reflect+log · winsorize · logit · leave alone |
| 5 Bivariate | Scatter + LOESS, violin + box, correlation heatmap | Which relationships are real enough to model? |
| 6 Collinearity | Pairwise r > 0.8, car::vif, condition number | VIF <5 fine · 5–10 investigate · >10 must address |
| 6b Measurement (conditional) | CFA via lavaan, invariance (configural/metric/scalar, ΔCFI < .01), reliability (psych::alpha/omega), classifier precision/recall/F1 + κ / Krippendorff’s α | Does the construct hold across groups? |
| 7 Panel (conditional) | pdim, between/within SD, attrition t-test | Is attrition selective? |
| 8 Outliers | Cook’s D > 4/N, leverage, |std resid| > 3, DFBETAS, Mahalanobis | Keep them — see the rule below |
| 8b Panel/time-series | Durbin-Watson, pbgtest, ACF/PACF, ADF/KPSS, pcdtest (Driscoll-Kraay if CD detected), Breusch-Pagan | Which SE do you owe the reviewer? |
| 8c Distribution tests | Shapiro-Wilk, Anderson-Darling, Jarque-Bera, Hartigan’s dip | Is that bimodality real? |
| 9 Pre-analysis memo | The 10-section decision memo | Written before you see a model |
| 10 Table 1 | gtsummary::tbl_summary → HTML/TeX/docx | The table a reviewer reads first |
The outlier rule, stated in the skill itself: never delete outliers solely because they weaken your result — that is p-hacking. Run the primary analysis with them in; show the without-outliers version as an appendix robustness check.
10.4 What gets written
output/<slug>/
├── eda/
│ ├── figures/fig-missing-by-var.pdf|.png ← 300 DPI, cairo_pdf
│ │ fig-missing-upset · fig-dist-outcome · fig-qq-outcome
│ │ fig-scatter-y-x · fig-violin-outcome-by-group
│ │ fig-corr-heatmap · fig-cooks-d
│ └── tables/table1-descriptives.html|.tex|.docx
├── scripts/
│ ├── E01-load-data.R … E07-table1.R ← version-checked, never overwritten
│ ├── E06b-measurement-validation.R ← only if Phase 6b ran
│ ├── viz_setting.R ← copied in on first use
│ ├── coding-decisions-log.md
│ └── script-index.md
└── logs/
├── trace-scholar-eda-<date>.ndjson ← the RAO trace (source of truth)
└── process-log-scholar-eda-<date>.md ← rendered from the trace
Two log files are worth opening every time:
coding-decisions-log.md— columnsTimestamp, Step, Decision, Alternatives Considered, Rationale, Variables, Script. This is the file that answers “why is the sample 108,509 and not 108,526?” six months from now.script-index.md— columnsOrder, Script, Description, Input, Output, Produces. This is whatscholar-replicationturns intorun-all.sh.
Scripts are version-checked, never overwritten: a second run writes E03-...-v2.R. Your first draft of a decision stays on disk next to the one that replaced it.
10.5 Real Table 1 (truncated)
| Stratum | n | age_mean | female | hukou_rural | eduy_mean | y1_access | y2_hours_mean |
|---|---|---|---|---|---|---|---|
| Overall | 204,418 | 44.6 | 0.497 | 0.749 | 7.54 | 0.329 | 12.07 |
| Wave 2010 | 33,595 | 42.4 | 0.493 | 0.844 | NA | 0.243 | NA |
| Wave 2012 | 35,716 | 42.2 | 0.505 | 0.698 | 7.28 | NA | NA |
| Wave 2014 | 37,140 | 43.2 | 0.494 | 0.709 | 8.03 | 0.369 | 11.58 |
| Wave 2016 | 36,833 | 50.2 | 0.496 | NA | 7.23 | 0.376 | 12.60 |
| Wave 2018 | 34,734 | 45.1 | 0.497 | 0.705 | 8.57 | 0.576 | 14.41 |
| Wave 2020 | 26,400 | 46.9 | 0.503 | 0.822 | 8.40 | 0.652 | NA |
| Hukou: Rural | 119,259 | 42.8 | 0.501 | 1 | 6.49 | 0.243 | 11.45 |
| Hukou: Urban | 35,762 | 42.6 | 0.488 | 0 | 10.33 | 0.492 | 12.51 |
10.6 Read this table like a reviewer
- Y1 (access) is missing in 2012 and Y2 (hours) is missing in 2010, 2012, 2020. That is a measurement window problem. If you ignore it, your “2010–2020 trend” claim will be an over-claim. The verification stage will catch this — but you will save yourself two days by noticing it now.
- Hukou rural fraction shifts from 0.84 → 0.70 → 0.82. That is sample weighting / sampling-frame variation, not population change. It needs a wave fixed effect, which the design blueprint already specified.
- Education years rises 7.28 → 8.57. Cohort replacement signal — consistent with H2.
10.7 The verification pass
At the end of the run, scholar-eda optionally dispatches a single general-purpose verification subagent against the EDA summary. It checks seven fixed items and returns PASS or FAIL with fixes:
- VIF > 10 left unresolved.
- More than 20% missing with no MI and no sensitivity analysis.
- No pre-analysis decisions memo.
- A transformation applied without justification.
- Outlier exclusions that were never documented.
- Post-treatment controls sitting in the specification.
- Table 1 not actually saved to disk.
Item 6 is the one that quietly ruins papers. Read the memo for it specifically.
10.8 Gotchas the skill documents about itself
str(df)is forbidden under LOCAL_MODE even though it looks like “classes only.” A June 2026 audit found it prints sample column values — a row-level leak. The safe substitute is a hand-builtdata.frame(variable, class).- Do not re-append the slug to output paths. Under
scholar-full-paper,OUTPUT_ROOTis alreadyoutput/<slug>; scripts that append it again produceoutput/<slug>/<slug>/eda. - Post-treatment covariates must be flagged explicitly, never silently included.
- Shell state does not persist between Bash calls, so scripts re-derive
SCRIPT_PATHon every call rather than trusting a variable set earlier.
Stop and check. Write down, in two sentences, what window of waves your Y2 analysis can actually use. (Answer: 2014–2018. This is the central teaching moment of the workshop.)
11. scholar-analyze — produce the headline table
Goal: run every model on the design ladder, save tables and figures, and write a “results lock” so later skills cannot drift.
argument-hint: "[data source + model spec, e.g., 'NHANES 2017-2018, OLS of BMI
on physical activity by race for Demography' or 'data.csv,
fixed effects of education on earnings for ASR']"
11.1 Run
> /scholar-analyze data=data/processed/cfps-panel-long.rds
outcome=y2_hours
predictors=hukou_rural,cohort,female,eduy,
household_size,coresident_yng_adult
fe=province_x_wave
models=M1,M2,M3,M4,M5
journal="Social Forces"
The skill writes scripts in scripts/, executes them under LOCAL_MODE, and saves outputs in tables/, figures/, and analysis/. About 8–15 minutes for the full run.
11.2 Five modes
| Mode | Trigger | Behaviour |
|---|---|---|
| 1 — File path | a local .csv/.dta/.rds/.parquet | Standard analysis run |
| 2 — Pasted data | inline data block | Written to a temp file, then analyzed |
| 3 — Online source | NHANES 2017-2018, GSS, WDI… | Fetches via R package or API first |
| 4 — Revise figure | revise, fix, adjust, resize, relabel, rotate labels, add reference line, change colors, refacet, restyle | Skips analysis entirely; locates the figure, reads the existing PNG and script, applies one revision from a fixed catalog, re-renders, version-saves |
| 5 — Pre-mortem | premortem, pre-mortem, analysis review | Touches no data; dispatches reviewer agents against the drafted scripts on a 14-dimension rubric |
> /scholar-analyze revise fig-coef-plot.pdf: rotate x-axis labels 45 degrees
> /scholar-analyze premortem output/digital-divide-china-cfps/scripts
Mode 5’s gate (analysis-review-check.sh) returns 0 GREEN, 1 RED (halt), 2 YELLOW (advance if approved), capped at three iterations. --skip-premortem works standalone but is ignored under scholar-full-paper, where the gate is always routed through.
Mode 4 has a subtlety worth knowing: if a results lock already exists, revising a figure emits a lock-drift reminder telling you to re-lock and re-run scholar-verify stage2. A prettier figure is still a changed artifact.
11.3 The design router — why the ladder differs by project
Before choosing estimators, scholar-analyze reads the Design Type: line from logs/project-state.md and routes to one of six ladder definitions:
| Design type | Ladder |
|---|---|
observational-descriptive | Descriptive ladder — this is the CFPS route |
observational-causal | Causal ladder (requires identification-strategy.json) |
rct | Randomized ladder |
quasi-experimental | DiD / RD / IV / synth / FDID sub-types |
decomposition | Oaxaca / Kitagawa / KHB / APC |
predictive-ml | Prediction ladder |
Fallbacks are deliberately noisy: a missing design type defaults to observational-descriptive with a WARN; an unrecognized one is a hard error; and observational-causal-with-DAG without an identification-strategy.json is a hard error. You cannot accidentally run a causal ladder without having committed to an identification strategy.
11.4 Three components
Component A — analysis. Data loading under the safety gate; Table 1; multiple imputation (mice, m = 20); the regression ladder (OLS with HC3, fixest::feols fixed effects, plm random effects, Arellano-Bond GMM, logit/probit, ordered logit, mixed and crossed random effects, Cox PH, negative binomial); average marginal effects via marginaleffects::avg_slopes; diagnostics (VIF, Breusch-Pagan, Cook’s D, Hosmer-Lemeshow, AUC, Hausman, Schoenfeld, RESET); export; robustness (Oster δ via sensemakr, E-values via EValue); then a long tail of specialized methods — Oaxaca-Blinder, Kitagawa, latent class, quantile regression, zero-inflated and hurdle models, Tobit, beta regression, competing risks, RI-CLPM, sequence analysis, full SEM/CFA, multiple-testing correction, GAMLSS, DML and causal forests, growth curves, multilevel SEM, finite mixture regression, specification curves, and BART.
Component B — visualization. 25 ggplot2 templates mirrored by 25 Python equivalents, all rendered through viz_setting.R’s theme_Publication() with the Wong-2011 colorblind-safe palette, cairo_pdf plus 300-DPI PNG, and journal dimension presets (asr, ajs, demography, nhb_single, nhb_double, ncs_single, ncs_double, sciadv, pnas). Two gates sit inside this component:
- B0b — Figure Brief. Before generating any figure code, the skill states what the figure will show and waits for your confirmation. (Auto-confirmed under
scholar-full-paper.) - B0c — Inspect and Revise. After every
save_fig(), the skill reads the rendered PNG back, checks eight defect classes, auto-fixes, and repeats — up to three iterations per figure, each logged. This is why the figures come out publication-ready rather than merely produced.
Component C — Results prose (standalone mode only). A four-paragraph structure with journal-specific sentence templates per model type, a mandatory within-group vs. between-group interpretation check whenever two or more groups are compared, and hypothesis verdicts bound to a coded adjudication vocabulary — the writer may not invent synonyms for “supported.”
Under scholar-full-paper, Component C does not run: Phase 7 drafts Results directly from the results lock, removing one hop where numbers could drift.
11.5 What gets written
scripts/
├── 01-data-loading.R · 03-descriptives-table1.R · 04-main-models.R
├── 05-marginal-effects.R · 06-diagnostics.R · 07-export-tables.R
├── 08-robustness.R · 09-decomposition.R (…09a–09p specialized)
├── 10-viz-setup.R … 19-viz-diagrams.R
├── viz_setting.R · coding-decisions-log.md · script-index.md
tables/
├── table1-descriptives.{html,tex,docx,csv}
├── table2-regression.{html,tex,docx,csv,-pub.md}
├── table2-ame.{html,tex,docx,csv} ← mandatory for every logit/probit/ologit
├── results-registry.csv · adjudication-log.csv · spec-registry.csv
├── ame-<model>.csv · coefficients-<model>.csv
├── group-period-means.csv · period-definitions.csv
└── manifest.json ← SHA-256 hash + provenance per artifact
figures/
└── fig-*.pdf|.png (+ -gs grayscale variants, .mmd/.tex/.svg for diagrams)
The registries are the spine of everything downstream, so learn their columns:
results-registry.csv — hypothesis_id, model_id, table_ref, figure_ref, focal_coef_name, beta, se, ci_low, ci_high, p_raw, p_adj, ame, ame_ci_low, ame_ci_high, n_obs, n_clusters, estimator, se_type, script, notes
adjudication-log.csv — hypothesis_id, family_id, statement, direction_hypothesized, model, focal_coef_name, beta, se, p_raw, p_adj, ci_low, ci_high, ame, alpha, adjudication_code, prose_verb, table_ref, figure_ref, script, notes
spec-registry.csv — spec_id, description, estimator, se_type, sample, ladder_file, ladder_section, design_type, status, notes, where status ∈ {focal, robustness, exploratory} and at least one focal row is required.
Note the prose_verb column in the adjudication log. That is the exact verb scholar-write is permitted to use for that hypothesis. The chain from p-value to sentence is mechanical by design.
11.6 Real headline result (Y1 access ladder)
From tables/table-Y1-models-pub.md:
| Term | M1 | M2 | M3 (focal) | M4 | M5 (2014–2020) |
|---|---|---|---|---|---|
| Rural hukou (vs. urban) | -1.708*** | -0.910*** | -0.845*** | -0.724*** | -0.845*** |
| (0.036) | (0.048) | (0.051) | (0.077) | (0.051) | |
| Cohort: 1996+ | -0.287 | -0.985** | -0.891** | -0.852** | -0.891** |
| Female | -0.410*** | -0.183*** | -0.212*** | -0.211*** | -0.212*** |
| eduy | — | 0.278*** | 0.269*** | 0.270*** | 0.269*** |
| household_size | — | — | -0.094*** | -0.093*** | -0.094*** |
| … | |||||
| Num.Obs. | 148,599 | 108,526 | 108,509 | 108,509 | 108,509 |
| FE: province × wave | X | X | X |
Cluster-robust SE in parentheses, by pid. * p<0.05, ** p<0.01, *** p<0.001.
The Y2 (use intensity) table tells the second-level story. The headline finding from the locked Y2 M3 specification:
Net of education, income, household composition, and province × wave FE, agricultural-hukou status is associated with −1.306 weekly hours of internet use among users (SE 0.295; BH-FDR p = 1.4e-5).
That is a real number from a real script. The Oaxaca decomposition (tables/oaxaca-decomp.csv) showed the coefficients component (1.151 hours) dominated the endowments component (−0.395) — supporting the institutional sorting account, not the pure resource account.
11.7 The gates that fire without being asked
These are the checks that turn a plausible analysis into a defensible one. Each is a real script that returns a colour.
| Gate | What it enforces |
|---|---|
regression-table-export-check.sh | Regression tables must be rendered (HTML/TeX/docx/-pub.md), never CSV-only. Failure is RED, marked a contract violation |
spec-status-check.sh | Every spec-registry row has a status; at least one is focal |
control-set-coverage-check.sh | RED on R-MISSING (a pre-committed control silently dropped), R-FISHING (an undisclosed control added), R-FORBIDDEN (adjusting for a mediator or collider) |
ladder-identification-distinctness-check.sh | YELLOW when every “robustness” spec shares a single identifying assumption — that is estimator robustness, not triangulation |
multiple-testing-budget-check.sh | YELLOW when a family has ≥3 tests and no correction artifact exists |
model-spec-lint.sh | RED on marginality violations — an interaction term without its lower-order main effects |
phase-5-depth-check.sh | Under the orchestrator: ≥3 specs, ≥2 robustness specs, ≥4 figures |
When a hypothesis family carries K ≥ 3 sub-tests, the skill must also emit verify/family-correction-<HID>.csv with columns family_id, k, raw_p, adj_method, adj_p, alpha, n_survive.
11.8 A9 and B9 — the verification subagents
Two general-purpose subagents run before the analysis is considered done, each returning PASS or NEEDS REVISION with a numbered fix list.
A9 (analysis) checks: correct model family for the outcome type; a progressive ladder; multiple-testing correction when there are more than five tests; SE specification (HC3, clustered, lmerTest); AMEs computed via avg_slopes for every non-linear model rather than reported as raw log-odds; diagnostics (VIF < 10, Breusch-Pagan, Hausman, Schoenfeld); journal reporting standards, including the ban on “trend toward significance”; sensitivity (Oster δ, specification curve if more than three alternative specs); cell-by-cell table verification; and whether the files are actually on disk.
B9 (visualization) checks: file export; colorblind safety; label legibility; journal-specific requirements (AME plots for ASR/AJS, uppercase panel labels for Science Advances, violin + jitter for NHB when n < 30); figure-type correctness; files on disk.
11.9 The audits behind the gates
Every gate in §11.7 exists because a real run failed. The skill documents them by name, and they are the best short course in how AI-assisted analysis actually goes wrong:
- Stars stripped from tables (May 2026, two projects). A homemade CSV→Markdown converter dropped the significance stars. The fix is the absolute rule: embed
-pub.md, never post-process the CSV. - A two-row summary posing as Table 4 (May 2026). The manuscript’s “Table 4” was an AME summary, not the full M1–R2 coefficient ladder. This is what
regression-table-export-check.shnow blocks. - Five tests, raw p-values (April 2026). The one “significant” cohort finding (p = .029) survived neither Bonferroni nor BH.
- Fake triangulation (April 2026). Three estimators — M3, AIPTW, entropy balancing — presented as convergent evidence, all resting on the same selection-on-observables assumption. Agreement between them is mathematical aliasing, not independent identification.
- A missing main effect (digital-divide v2). Interaction terms shipped without the
wavemain effect. This marginality violation flipped the H1 verdict — and all fifteen LLM reviewers missed it. A linter caught it. Prefer the linter.
That last one is the honest summary of this whole section: language models are unreliable at exactly the mechanical checks that a ten-line script does perfectly. Use each for what it is good at.
11.10 But “result exists” ≠ “result is valid”
This is where the real workshop lesson lives. When the analysis reports a beautiful number, do not believe it yet. Run §13 (scholar-code-review) and §15 (scholar-verify) first.
Stop and check. Open tables/results-registry.csv. Can you trace the headline number −1.306 back to (a) the script that produced it, (b) the table cell that holds it, (c) the sample size used? If any link is missing, the result is not yet usable.
11A. scholar-compute — computational social science
Goal: run text-as-data, machine learning, network, computer-vision, LLM, geospatial, audio, or life-sequence analyses with the same discipline the regression pipeline gets.
argument-hint: "[text|network|ml|reproduce|spatial|bayesian|dsl|audio|life2vec]
[description of data and research question]"
> /scholar-compute text "STM topic model of 50k news articles on immigration
policy, 2015-2023, covariates: outlet + year"
> /scholar-compute ml "predict recidivism, gradient boosting vs logistic,
Optuna-tuned, SHAP interpretation"
> /scholar-compute network "ERGM on a high-school friendship edgelist,
homophily on race + education, GOF check"
> /scholar-compute spatial "county opioid mortality vs poverty, Moran's I,
spatial lag model"
11A.1 The module map
| Module | Methods | Key packages |
|---|---|---|
| 1 Text-as-data | Preprocessing decisions · STM · BERTopic · Wordfish/Wordscores scaling · multilingual NLP · NER · coreference · fine-tuned BERT · Word2Vec + Procrustes semantic change · conText embedding regression · LLM annotation · DSL | R stm, quanteda, conText, dsl; Py spacy, bertopic, sentence-transformers, gensim, transformers |
| 2 Machine learning | sklearn pipelines · Optuna tuning · Double ML (PLR/PLIV/IRM/IIVM) · causal forests · Chernozhukov sensitivity · Bayesian regression · conformal prediction · SHAP | R DoubleML, mlr3, grf, brms; Py econml, sklearn, optuna, mapie, shap |
| 3 Networks | Centrality · GNNs (node2vec, GCN, GraphSAGE, link prediction) · Leiden/Louvain · ERGM and temporal ERGM · stochastic block models · ego-networks · SAOM/RSiena · relational event models | R ergm, btergm, RSiena, igraph, goldfish; Py networkx, torch_geometric |
| 5 Reproducibility | Project layout · lockfiles · Makefiles · Docker/Singularity/Code Ocean | renv, rocker/verse, Docker |
| 6 Computer vision | DINOv2 (unsupervised) · CLIP (zero-shot) · ConvNeXt/ViT fine-tuning · multimodal LLM annotation · VideoMAE · multimodal fusion | transformers, timm, open_clip_torch |
| 7 LLM-powered analysis | Structured extraction · chain-of-thought coding · computational grounded theory · prompt optimization · RAG. For LLM annotation at corpus scale, use scholar-annotate (§11E) — it ships an engine, this module ships instructions | anthropic, pydantic, dspy, textgrad, faiss |
| 9 Geospatial | sf + tidycensus · spatial weights · Moran’s I and LISA · LM tests selecting SAR/SEM/SARAR/Durbin · direct and indirect impacts · spatial panels | sf, spdep, spatialreg, tmap, splm |
| 10 Audio | Whisper transcription · pyannote diarization · Essentia/librosa features · LLM-native audio · classification | faster_whisper, pyannote.audio, essentia, librosa |
| 11 Life2Vec | Life-event sequence transformer (Savcisens et al. 2024, Nature Computational Science) with Time2Vec encoding, ScaleNorm, ReZero residuals, hybrid Performer attention, SOP + MLM pretraining, PU-learning finetuning, TCAV interpretability | torch, pytorch_lightning, performer_pytorch, pacmap |
Three gates fire before any module loads: a causal-keyword gate (routes to /scholar-causal first), a premortem gate, and a simulation gate — about 25 keywords (abm, schelling, mesa, netlogo, opinion dynamics, silicon sampling, homo silicus…) redirect to /scholar-simulate, because ABM and synthetic respondents moved there.
Where LLM annotation lives now. MODULE 1 and MODULE 7 both still describe LLM annotation, and for a few hundred documents inside a larger text pipeline that is fine. But the engine — batch and local serving, sharding, resume, the cost ledger, the κ gate, distillation — is
scholar-annotate(§11E), which is self-contained and does not call back intoscholar-compute. Rule of thumb: if the annotation is a step in a topic-model or embedding analysis, stay here; if the labels are the variable you will regress on, go to §11E.
A reporting change worth catching if you use
conText. TheconText3.x API returns a debiased normed coefficient (normed.estimate.deflated), and that is what the skill now reports — with a permutation p-value. Describe the inference as jackknife plus permutation, never as bootstrap. Older write-ups that say “normed β” from a bootstrap are describing an API that no longer exists.
11A.2 The validation floor
The rule that matters most across every module: automated annotation requires human validation at κ ≥ 0.70, benchmarked on 200 human-coded items. Below 0.60, do not proceed LLM-only. Between 0.60 and 0.70, use it as an assistant with human review. In scholar-compute this is a documented standard you are expected to honour; in scholar-annotate (§11E) the same number is a hard gate that exits non-zero.
Other module-specific floors:
- Geospatial: Moran’s I on OLS residuals is mandatory before fitting any spatial model; LM tests then choose between SAR, SEM, SARAR, and Durbin.
- Bayesian: R̂ ≤ 1.01, bulk and tail ESS > 400, a saved posterior predictive check, LOO-CV for comparison.
- Conformal prediction: empirical coverage within ±2% of nominal, checked by subgroup.
- DSL: expert sample must be random (or probability-corrected), N ≥ 200 expert labels.
- LLM annotation:
temperature = 0, prompts archived verbatim, and all four Lin & Zhang (2025) risks — validity, reliability, replicability, transparency — explicitly addressed. - Everything: seed 42, held-out test performance only, never training-set numbers.
The DSL warning worth repeating. Substituting predicted labels for measured ones biases downstream regression even at 90%+ classifier accuracy, because the errors are not random. Design-based supervised learning corrects for this; using raw predicted labels as if they were data does not.
11A.3 Prompt optimization — a genuinely useful demo
Module 7 ships a runnable demonstration that requires no API key and costs nothing — it runs against a local Ollama model:
$ cd references/prompt-optimization-demo/dspy-demo
$ pip install -r requirements.txt && python dspy_demo.py # ~4 minutes
$ cd ../textgrad-demo
$ pip install -r requirements.txt && python make_data.py && python optimize_prompt.py
The result is a small, clarifying lesson about how prompt optimizers differ. The task is 20 training items, 8 validation, and 12 held-out test items, and the number below is test accuracy — not κ. (With 12 test items, one item is 0.083, so every Δ here is one or two items.)
| Optimizer | What it optimizes | Test accuracy | Δ | Cold runs that improved |
|---|---|---|---|---|
| Baseline prompt | — | 0.667 | — | — |
BootstrapFewShot | the demonstrations | 0.667 | +0.000 | 0 of 4 |
MIPROv2 (10 trials) | the instruction | 0.750–0.917 | +0.083–0.250 | 4 of 4 |
| TextGrad (1 step) | the instruction | 0.667–0.750 | +0.000–0.083 | 1 of 7 |
BootstrapFewShot only bootstraps examples the model already gets right, so it cannot fix the hard cases. When your prompt is the problem, adding examples of what already works will not help.
But “rewrite the instruction and it improves” is too neat. Both MIPROv2 and TextGrad rewrite the instruction, and only one of them reliably moves the test split. The difference is what each optimizes against: MIPROv2 scores 10 candidate instructions on the dev set, while TextGrad takes one gradient step and checkpoints on an 8-item validation split — and that split moves by a single item, which does not transfer. At 3 and 5 steps TextGrad’s test accuracy never moves at all. Search budget, and the width of the signal you steer on, is the real axis — not “instruction vs demonstrations.”
Before you trust any number here, check it was earned. Both frameworks cache every model call to disk. A re-run returns in ~1 second, reproduces the previous accuracy exactly, and looks indistinguishable from a replication. A cold run takes ~20 minutes. Use
DSPY_COLD=1/TG_COLD=1and checkoutputs/summary.json’swall_time_sbefore believing anything. An earlier version of this table reported a single figure that came from a 0.1-second run in which no model was called.
The full DSPy optimizer menu is documented: LabeledFewShot, BootstrapFewShot, BootstrapFewShotWithRandomSearch, KNNFewShot, COPRO, MIPROv2 (the workhorse), GEPA, SIMBA, InferRules, BootstrapFinetune, BetterTogether, Ensemble.
11B. scholar-simulate — LLM-powered social simulation, with a hard validation gate
Goal: run silicon sampling, generative agent-based models, and simulated experiments at scale — and prove, before claiming anything, that the synthetic data resembles human data.
argument-hint: "[design|personas|silicon-survey|generative-abm|experiment|
interactive|validate|calibrate|run|report]
[research question | manifest path]"
The cardinal rule, stated in the skill: synthetic data is not a substitute for human data. Any synthetic result entering a publication must be validated against a held-out human benchmark, and distributional mismatch (Bisbee et al. 2023) must be disclosed.
Its sibling is scholar-annotate (§11E): here the LLM is a respondent, there it is an annotator. Both carry a hard validation gate for the same reason — an unvalidated LLM output is a guess wearing the clothes of a measurement.
11B.1 Ten modes
| Mode | What it does |
|---|---|
| design | Paradigm selection, persona spec, provider choice, validation plan naming its benchmark, cost and power estimate, ethics gate. No run starts without this |
| personas | Iterative proportional fitting of marginal tables (Census, GSS, ANES) → joint distribution → sampled persona pool |
| silicon-survey | Thousands of personas answer survey, vignette, or conjoint items |
| generative-abm | Stateful multi-turn agents over a network — opinion dynamics, diffusion, deliberation — plus mechanistic ABM via Mesa or NetLogo |
| experiment | Randomize personas to conditions; report AMEs with within-persona clustering |
| validate | The hard gate. KS, mean difference, JSD, subgroup correlation, coverage against a held-out human benchmark |
| calibrate | Sweep temperature, anchors, persona richness — on a calibration sample disjoint from validation |
| run | The batch/async/local engine with caching, checkpointing, and a cost ledger |
| report | Methods text, journal reporting block, mandatory limitations |
| interactive | Small-N multi-agent conversations — focus groups, deliberation, negotiation |
> /scholar-simulate design "silicon-sample GSS trust-in-government items by party ID"
> /scholar-simulate personas --spec output/simulate/design/persona-spec.json --n 2000
> /scholar-simulate validate --responses output/simulate/runs/trust/responses.jsonl \
--benchmark data/raw/gss-2022-trust.csv
Choose the paradigm by what you are claiming: a static cross-sectional distribution → silicon sampling; emergence or diffusion over time → generative ABM; a causal contrast under manipulation → simulated experiment; a real-world causal effect from observational data → this is the wrong skill, go to /scholar-causal.
The skill also names what it will not do: replace human survey data in published findings; make claims about marginalized populations without matched human data; predict future social behaviour.
11B.2 The validation gate in detail
assets/validate.py computes, per key variable and per subgroup:
| Metric | Threshold |
|---|---|
| KS statistic | ks_max: 0.20 in the shipped code (the prose documentation says 0.10 — the code is what runs) |
| Jensen–Shannon divergence | < 0.10 |
| Absolute mean difference | < 0.50 |
| Subgroup correlation r | ≥ 0.70 |
| Coverage | ≥ 0.80 of items whose synthetic mean falls within the human mean ± 2 SE |
| Item pass rate | ≥ 0.80 |
PASS requires all three: coverage clears, subgroup correlation is met, and ≥80% of key items clear KS, mean-difference, and JSD. A missing subgroup correlation fails by default unless you explicitly pass --allow-missing-subgroup, which is logged. A separate homogenized flag fires when synthetic SD < 0.85 × real SD — the characteristic failure mode where the model produces a population more uniform than the real one.
Verification is done by an independent subagent, never self-certified.
Interactive mode is different and weaker. Without a held-out human-transcript benchmark, its verdict is always UNVALIDATED-EXPLORATORY — good for protocol design and hypothesis generation, supporting no substantive claim. With a benchmark it can reach DESCRIPTIVE-BENCHMARK-PASS, which compares interaction statistics (turns per agent, message length, turn-taking entropy), not distributional fidelity. Do not upgrade this verdict.
Calibration and validation samples must be disjoint. Tuning on validation data is leakage.
Six disclosures are mandatory in the Limitations section and may not be omitted: homogenization bias · uneven demographic steerability · training recency · intersectionality gaps in thin cells · rare-population unreliability · (interactive only) synthetic-conversation artifacts, since agents over-produce agreeable consensus and under-produce conflict, interruption, and silence.
11B.3 Providers and honest scale
| Provider | Batch API | Env |
|---|---|---|
anthropic | Yes (≤24 h, ~50% cheaper) | ANTHROPIC_API_KEY |
openai | Yes (≤24 h, ~50% cheaper) | OPENAI_API_KEY |
openai-compatible | No — use async | OPENAI_BASE_URL, OPENAI_API_KEY |
ollama | Local | OLLAMA_HOST |
Note the deliberate default: temperature = 0.7, not 0. This skill models response distributions; the annotation skills extract single labels and use 0.
What “thousands of agents” actually means. Thousands of batched persona calls with state in a checkpoint store — not thousands of live concurrent threads. Live concurrency ceilings are around 20–25. The skill says this plainly so you do not write a Methods sentence you cannot defend.
Everything runs through the engine, which you can also drive directly:
$ python3 assets/simulate_engine.py run --manifest run-manifest.json --dry-run
$ python3 assets/simulate_engine.py validate --responses responses.jsonl \
--benchmark human.csv --out fidelity.json
11C. scholar-qual — coding, thematic analysis, and the anonymization gate
Goal: codebook development, grounded-theory coding, reflexive thematic analysis, content analysis, LLM-assisted coding with human validation, and inter-coder reliability — with CAQDAS export.
argument-hint: "[workflow: codebook|open-coding|axial|selective|thematic|
content|llm-coding|mixed|reliability]
[data: transcript path or 'paste below']
[optional: approach, codebook path, target journal]"
| Workflow | Method |
|---|---|
codebook | Inductive/deductive/hybrid; three-level hierarchy; seven-field code definitions; exports to Markdown, CSV, NVivo XML |
open-coding | Grounded theory line-by-line — in-vivo, descriptive, and process codes; constant comparison; three memo types |
axial | Strauss & Corbin paradigm model; category relationships; saturation assessment |
selective | Core-category identification; the storyline technique; conditional matrix; grounded theory statement |
thematic | Braun & Clarke reflexive TA — familiarization, coding, theme search, two-level review, theme map, write-up |
content | Krippendorff systematic content analysis; manifest vs. latent; pilot on 10–15% |
llm-coding | Lin & Zhang (2025) framework: task design, prompt templates, gold-standard pilot, confidence calibration, stratified human validation, adjudication, bias audit |
mixed | Integration strategy, case selection from residuals, joint displays, typology development |
reliability | Cohen’s κ, weighted κ, Krippendorff’s α, Fleiss’ κ, Gwet’s AC1 |
> /scholar-qual codebook "interviews with formerly incarcerated men on re-entry" grounded theory
> /scholar-qual thematic data/focus-groups/ "vaccine hesitancy among rural parents"
> /scholar-qual llm-coding output/qual/anonymized/ANON_interview-01.txt codebook.csv
11C.1 The anonymization gate comes first
Before any workflow sends text to a model, a mandatory five-step gate runs: scan → generate a pseudonym key (P01, LOC01, ORG01) → user reviews the key → anonymize → re-scan to verify → swap the path to the ANON_ file. Presidio is the preferred backend; a regex fallback always exists.
Two files are created that Claude must never read: pii-scan-detail-DO-NOT-SHARE.txt (mode 0600) and pseudonym-key-DO-NOT-SHARE.csv (gitignore it). And once an anonymized copy exists, the original is not read again.
The reason is stated plainly: IRB consent typically does not cover sending identifiable interview data to a cloud AI service.
LOCAL_MODEis fundamentally incompatible withscholar-qual. Coding requires reading the text; LOCAL_MODE forbids exactly that. The skill halts and tells you to downgrade toANONYMIZEDvia/scholar-init review, or to use/scholar-computefor aggregate-only text analytics. This is one of the clearest cases in the suite where a constraint is honoured rather than worked around.
11C.2 Reliability benchmarks
| κ | Reading |
|---|---|
| > 0.80 | Excellent |
| 0.60–0.79 | Substantial — the acceptable minimum |
| 0.40–0.59 | Moderate |
| < 0.40 | Not usable |
Krippendorff’s α: ≥ 0.667 tentative, ≥ 0.800 reliable. Choose the metric by design: two coders on nominal data → Cohen’s κ; more than two → Fleiss’ κ; missing data → Krippendorff’s α; skewed margins → Gwet’s AC1; LLM vs. human → Cohen’s κ plus per-code F1.
The reliability sample must be at least 10–20% of the corpus, stratified — or the whole corpus if you have fewer than 100 segments.
For LLM coding specifically: iterate the prompt until κ ≥ 0.70 against human coding; validate on a random 10% (minimum 100 segments) plus all low-confidence cases plus an oversample of rare codes (≥20 each); and run the bias audit — positional, verbosity, anchoring, and majority-class bias, tested with χ².
11D. scholar-ling — sociolinguistics and language variation
Goal: variationist analysis, acoustic phonetics, discourse analysis, corpus linguistics, computational sociolinguistics, and experimental sociolinguistics, calibrated to Language in Society, Journal of Sociolinguistics, and Language.
argument-hint: "[variation|acoustic|corpus|CA|CDA|attitudes|contact|
computational|experimental|MDA|TTS-guise]
[linguistic phenomenon, population, and data type]"
> /scholar-ling variation "/t/-deletion in African American English,
sociolinguistic interviews, Rbrul"
> /scholar-ling acoustic "vowel shift in Southern US English, Parselmouth
formant extraction + Lobanov normalization"
> /scholar-ling computational "semantic change of immigration terms in
congressional speech, conText"
> /scholar-ling MDA "register comparison of academic vs conversational
English, Biber 67 features"
| Module | Covers |
|---|---|
| 1 Theory | Variationist/Labovian foundations, apparent-time change, Silverstein’s indexical orders, communities of practice, raciolinguistics, language ideologies (iconization, fractal recursivity, erasure), Bourdieu’s linguistic capital, contact (GIDS, Matrix Language Frame, heritage attrition) |
| 2 Quantitative | Rbrul / Goldvarb / VARBRUL variable-rule analysis · acoustic phonetics (formants, VOT, F0, jitter/shimmer/HNR, forced alignment via FAVE/MFA/WebMAUS) · mixed-effects models · power analysis |
| 3 Qualitative | Conversation Analysis (Jefferson notation, adjacency pairs, repair, deviant-case analysis) · interactional sociolinguistics · Labov–Waletzky narrative analysis |
| 4 Attitudes | Matched Guise Technique (status/solidarity/dynamism) · IAT · LEAP-Q |
| 5 Corpus/discourse | Corpus building · keyness (G², preferred over χ²) · collocation and KWIC · semantic prosody · STM |
| 6 Computational | conText ALC embedding regression · LLM annotation · BERT classification · Word2Vec + Procrustes semantic change |
| 7 Experimental | Factorial vignettes (D-optimal designs) · IAT D-scores · reaction-time paradigms · priming · ordinal CLMM for Likert data |
| 8 Biber MDA | 67 features across 14 categories; the six canonical dimensions; factor analysis with promax rotation; MANOVA register comparison |
| 9 TTS matched guise | Synthesized guises, Praat pitch/formant manipulation, ≥30% natural-speech fillers, Latin-square counterbalancing |
11D.1 The numbers you need before collecting data
| Method | Minimum |
|---|---|
| Rbrul | ≥200 tokens total, ≥20 per cell |
| Acoustic mixed-effects | ≥20 speakers per group, ≥10 tokens per vowel per speaker |
| Keyness (log-likelihood) | ≥50,000 tokens per corpus |
| STM | ≥1,000 documents |
| Word embeddings | ≥1,000,000 tokens |
| BERT fine-tuning | ≥500 labeled examples per class |
| conText | ≥100 contexts per group per target term |
| CA collection | ≥10 instances of the phenomenon, with 2–3 turns of context each |
Keyness thresholds: G² > 3.84 (p < .05), G² > 10.83 (p < .001). Log-likelihood is preferred over chi-square.
Two method-choice rules that prevent the most common error: categorical linguistic variables go to Rbrul; continuous acoustic outcomes (F1, F2, VOT, duration, F0) go to lmer and never to Rbrul. And report average marginal effects, not raw coefficients.
Causal language is calibrated the same way as everywhere else: variationist and corpus studies are observational, so write “is associated with,” “patterns with,” or “favors [variant]” — never “causes” — unless the design is genuinely experimental, such as a randomized matched-guise study.
11D.2 The strictest safety defaults in the suite
scholar-ling treats voice as an identifier, because it is:
- Interview audio and transcripts default to
LOCAL_MODE. - Matched-guise stimuli are
CLEAREDonly if synthesized; human recordings areLOCAL_MODE. - Public corpora (COCA, COHA, BNC, Congressional Record) are
CLEARED. - No
OVERRIDEoption is offered for audio files or interview transcripts — only LOCAL_MODE, ANONYMIZE, or HALT. A voiceprint cannot be un-shared. - Student elicitations and classroom recordings default to
LOCAL_MODEas vulnerable-participant data. - Conversation Analysis halts entirely under LOCAL_MODE unless the data is anonymized first or you switch to a public corpus.
One subtle rule worth internalizing: do not print KWIC concordances under LOCAL_MODE. The concordance line is the sensitive sentence. A tool that shows five words either side of a target term has just shown you the utterance.
Finally, for non-English data, every example needs the original, a morpheme-by-morpheme gloss, and a translation — the standard the target journals actually enforce.
11E. scholar-annotate — the LLM as a measurement instrument
Goal: turn a text corpus into a validated, reproducible variable — a class, a frame, a stance, a score, an extracted field — and prove its reliability before you spend anything annotating the whole corpus.
argument-hint: "[plan|profile|codebook|devset|annotate-gold|optimize|validate|
scale|distill|report|full] [corpus path or task description]"
This is the second new skill in v5.26–5.27, and it is the one that fixes a real gap. Until now, “have an LLM code 50,000 documents” lived as MODULE 7 inside scholar-compute — a set of instructions, but no engine. scholar-annotate ships a real execution engine (assets/annotate_engine.py and friends) that scales from a few hundred documents to tens of millions via managed Batch APIs, async live requests, or a local/HPC OpenAI-compatible server. It is fully self-contained and does not depend on scholar-compute.
Place it against its two siblings and the division of labour is clean:
| Skill | The LLM is a… | You get |
|---|---|---|
scholar-annotate (§11E) | annotator / measurer | a labeled corpus + a reliability estimate |
scholar-simulate (§11B) | respondent / generator | synthetic data + a human-fidelity check |
scholar-qual (§11C) | assistant to a human coder | themes, reflexivity, an audit trail |
The skill redirects on its own if you land in the wrong one: synthetic respondents or ABM go to /scholar-simulate; small-N interpretive coding where the deliverable is themes rather than a scaled variable goes to /scholar-qual (and comes back here for the scale-and-validate steps); sociolinguistic variables go to /scholar-ling; and estimating an actual causal effect goes to /scholar-causal.
The cardinal rule, in the skill’s own words: VALIDATE BEFORE YOU SCALE. LLM labels are a measurement, and every measurement needs a reliability estimate. MODE 8 (annotate the full corpus) is blocked until MODE 7 passes at Cohen κ ≥ 0.70 against a human or gold set. This is not advisory —
annotate_engine.py validateexits 2 below the gate. p-values are irrelevant here; reliability is the currency.
11E.1 Eleven modes
| Mode | Triggers | What it does |
|---|---|---|
| 1 plan | plan, feasibility, cost, which model, batch vs local | Fix the construct, the unit, the label space, and the serving strategy; produce a pre-flight cost and throughput estimate |
| 2 profile | profile, class prior, what is in the corpus | Class prior, languages, dominant topics, and off-topic contamination — the thing that silently poisons a scheme |
| 3 codebook | codebook, scheme, rubric, frames | The measurement instrument: definitions, include/exclude rules, tie-breaking order, boundary exemplars |
| 4 devset | devset, sample, stratify | Stratified development set with rare-class over-sampling, plus a human-label template |
| 5 annotate-gold | annotate-gold, dual model, inter-coder | Turn the dev sample into gold via multi-model LLM annotation and/or human double-coding |
| 6 optimize | optimize, dspy, few-shot, mipro | Compile the prompt with DSPy against the gold set; archive the program + hash |
| 7 validate | validate, kappa, κ, f1, gate | HARD GATE — κ + per-class F1 vs gold, plus four epistemic-risk checks |
| 8 scale | scale, full corpus, batch, local, hpc, sbatch | The only mode that touches the whole corpus, and only after 7 passes |
| 9 distill | distill, cheap classifier, dsl | Train a cheap classifier on LLM labels and score the rest on-device |
| 10 report | report, methods, disclosure | The deliverable: dataset, distributions, validation report, Methods + Results prose, disclosures |
| full | full | Runs 0 → 10 in order |
11E.2 The gate, in detail
$ python3 assets/annotate_engine.py validate \
--pred output/tables/llm_dev_pred.csv \
--gold output/tables/devset_gold.csv \
--on relevance,discourse_frame --gate 0.70 \
--out output/tables/validation_report.json
Per field it reports n, Cohen κ (LLM vs gold), macro-F1, and a full classification report — then exits 2 if the primary field misses the bar.
Two things about that bar are worth arguing with your future self about:
- κ, not accuracy. κ corrects for the class prior. On a corpus that is 90% one class, accuracy is meaningless — a constant predictor scores 0.90.
- Per-class F1 can hide inside a passing κ, and the class it hides in is usually the one you care about. If the target class F1 is weak, iterate even when the overall gate is green.
Alongside the gate, all four Lin & Zhang (2025) epistemic risks must be assessed explicitly: validity (inspect chain-of-thought rationales on a sample — does it measure the construct you named?), reliability (temperature = 0; report run-to-run κ on a 50-document re-annotation), replicability (exact model id + version + date + prompt/program hash archived), and transparency (prompts reproduced in the appendix, limitations stated).
When it fails, the skill prescribes the cheapest lever first: sharpen the codebook’s definitions and boundary rules → re-optimize few-shot (MODE 6) → re-validate. A stronger model is the last thing to reach for, not the first.
The gate itself had a bug, and it is the most instructive one in this handbook (fixed 2026-08-12). An annotator that failed 40% of the documents could pass it. Three independent defects stacked:
- Predictions were INNER-joined onto gold. Every document the annotator choked on left the denominator — so failing the hard cases raised the reported κ. The subset it could handle was the easy subset, and the gate scored that.
- A NaN κ passed, because in IEEE-754
nan < gateisFalse. “Could not be computed” was silently read as “not below threshold.”- Only the first
--onfield could fail the gate. A secondary field sitting at κ = 0.000 printedFAILand still exited 0.Run against a deliberately broken fixture, the shipped gate printed
FAILon both fields and thenPASS — cleared for MODE 8, exit 0. Now gold is the denominator, coverage is reported and enforced, every excluded row is accounted for, a NaN fails closed, and every--onfield gates independently.The lesson generalizes well past this skill. A reliability number computed only over the cases your instrument could handle is not a reliability number — it is a description of the easy subset. Whenever you are handed a κ, ask what the denominator was before you ask whether it cleared 0.70.
Coverage and construct match — the two halves of the gate. κ ≥ 0.70 is now the second thing checked, not the only one. Coverage asks whether the instrument actually attempted the corpus: what fraction of gold rows received a prediction at all, and where the rest went. Construct match binds the codebook’s named construct to the field being scored, so a healthy κ against the wrong column cannot pass itself off as validity. A run can clear 0.70 on every field and still be refused for missing either half. Read them in that order — coverage, then construct, then κ.
11E.3 Gold without two human coders
Not every project can double-code 500 documents by hand, and the skill is honest about the substitutes:
- Two different models annotate the dev set via Batch APIs (e.g. Claude + GPT); agreement becomes gold, disagreement goes to an adjudication file. Inter-model Cohen κ is reported.
- Only one provider? Use two models of it (
gpt-5.6+gpt-4.1). Model diversity still filters the boundary cases, which is what gold-setting is actually for. - Model forces temperature ≠ 0 (the GPT-5 and o-series do)? Run it K times and majority-vote —
gold_reconcile.py --mode majority— to damp the non-determinism. The deployment model keeps temperature = 0 regardless. - Human double-coding, when you have it, reports Krippendorff α ≥ 0.70.
11E.4 The execution engine
Everything scaled runs through the engine, never through a hand-rolled loop in the conversation. The CLI contract is stable:
$ ENG="$SKILL_DIR/assets/annotate_engine.py"
$ python3 "$ENG" sample --corpus spec.json --text-cols title,description,tags \
--strata lang --n 3000 --oversample lexicon.json --out sample.csv
$ python3 "$ENG" annotate --manifest run.json [--dry-run] [--resume] [--shard i --nshards N]
$ python3 "$ENG" validate --pred pred.csv --gold gold.csv --on relevance --gate 0.70
$ python3 "$ENG" distill --labels labels.csv --corpus spec.json --gold gold.csv --out labels_full.csv
It is idempotent (checkpoint and resume), sharded, deduplicated by stable hash, and keeps a cost ledger with a pre-flight estimate — --dry-run tells you what MODE 8 will cost before you authorize it.
Companion assets: dspy_optimize.py and dspy_run.py (compile a program, then deploy it threaded/sharded/resumable), providers.py (OpenAI · Anthropic · any local OpenAI-compatible server — llama.cpp, ollama, vLLM), codebook_schema.py (compiles the codebook into both the system prompt and the JSON output schema, so there is one source of truth), run-annotate.sh for long headless runs, and hpc/ (SLURM sbatch, corpus mirror, rsync helper).
A gotcha the skill documents about itself. The MODE 9 distiller and reducer scripts default to
video_id/title/descriptioncolumns — the shape of the worked example. For your own corpus, pass the matching--id-col/--text-cols, or the run will silently look at the wrong fields.
11E.5 Real field lessons — a local reasoning model at 12.7M rows
The skill ships references/local-model-scale-lessons.md, which is the most useful thing in it: hard numbers from a real run measuring metalinguistic relevance (6-way) and discourse frame (7-way) over ~12.7M YouTube-metadata rows with a local GLM-5.2 on a SLURM cluster. Read it before committing GPU-days.
The throughput wall is decode, and reasoning models make it worse. At Q3 across four GPUs, decode ran ~4–9 tokens/s, so a single row took 60–150 seconds; with 8–16-way parallelism that is only ~0.1–0.4 rows/s/node. Prefill is not the bottleneck — llama.cpp caches the shared system + few-shot prefix. For millions of rows, a direct local pass is days-to-weeks.
What actually cut output tokens — and what didn’t:
| Lever | Effect | Verdict |
|---|---|---|
Drop the free-text rationale field | ~220 → ~40 tokens on a non-reasoning path | Big win when the model isn’t reasoning |
DSPy Predict instead of ChainOfThought | ~no change | The model reasons internally regardless |
--reasoning-budget 0 | Caps the 1,000-token spikes; ~70–200 tokens of preamble remain | Partial |
DSPy JSONAdapter vs ChatAdapter | ~200 → ~70–100 tokens | ~2× — real but modest |
--max-tokens 100 hard cap | ~12% invalid-JSON parse failures | Too tight; ~150 is the floor |
Stacked, those give roughly 2×, not 10×. A local reasoning model has a hard floor around 70–100 output tokens even for three labels.
Chain-of-thought bought nothing; the DSPy demonstrations bought everything. MODE 6 took frame κ from 0.31 (hand-tuned few-shot) to 0.76 (DSPy). An A/B on the same held-out split showed ChainOfThought κ = 0.705 ≈ Predict κ = 0.703 — the entire gain came from DSPy selecting good demonstrations, not from the reasoning field. The reason the hand-tuned version failed is worth memorizing: a naive “k = 2 per relevance class” few-shot showed only 1–2 of the 7 frames, so the never-demonstrated frames had zero recall. Every rare class must appear in the demonstrations.
This is the same lesson as §11A.3, arrived at independently on a different task: when the prompt is the problem, adding examples of what the model already gets right does not help. What helps is changing what it is shown, or what it is told.
Distillation is the real answer at scale (MODE 9), ranked by what worked:
| Distiller | κ vs gold | Note |
|---|---|---|
| Fine-tuned multilingual BERT (XLM-RoBERTa) | 0.77 | Trained in ~9 min from 38k labels, scored 1.87M in ~15 min — turned a ~23-day pass into ~1 hour |
| Frozen multilingual embeddings + logistic (bge-m3) | 0.706 | Dependency-light, no fine-tuning fragility; use when labels are few |
| TF-IDF + logistic | 0.607 | Failed the gate. Bag-of-words cannot do a 6-way semantic task |
And three caveats that cost real time:
- The teacher caps the student. Frame distillation topped out at κ ≈ 0.67 because the GLM frame teacher was only ~0.70–0.76. Distill the variables with a high-κ teacher; keep the LLM for the hard ones.
- Tuning is not more data. Oversampling rare classes plus more epochs regressed frame κ from 0.671 to 0.648 — overfitting. The fix for a weak class is usually more labels or a better teacher, not hyperparameters.
- Hold gold out of training and validate the student against it; silver labels are only teacher-accurate.
The two-pass pattern the run converged on generalizes: distill the cheap primary variable over all N, filter to the positive subset (~25% here), and spend the expensive LLM only on that subset for the harder secondary variable.
11E.6 The data-transfer rule
Sending text to a cloud API is an external data transfer, and the skill treats it as one: MODE 0 writes an AI-use disclosure, and the decision is logged rather than assumed.
For sensitive, LOCAL_MODE, or restricted corpora, the local strategy is not a fallback but the default — an on-premises OpenAI-compatible server, so the text never leaves the machine. Under LOCAL_MODE the skill must never Read raw rows; everything runs through the engine, which emits aggregates only, and MODE 8 is forced to strategy=local unless you explicitly authorize a cloud batch of public fields. Comments, PII, and transcripts are anonymize-first (§6.5, §11C.1).
11E.7 Stop and check
references/quickstart-hanyu.md is a complete, copy-pasteable worked example running every mode with real specs, manifests, and commands. Before you scale anything of your own, answer three questions:
- What is the unit, and what is the label space? If you cannot write the codebook entry for your rarest class in two sentences with an include and an exclude rule, you are not ready to annotate.
- What does MODE 8 cost? Run
--dry-runand look at the ledger. “Local so it’s free” is the assumption that turns into three weeks of GPU time. - What is your gold, and how reliable is it? Two models, two humans, or one model run K times — but something. A κ against a gold set you did not interrogate is a number, not evidence.
12. Reading three figures like a reviewer
The scholar-analyze run produced six figures. Three of them carry the central narrative. Read them as if you were Reviewer 2.
12.1 Figure 1 — Access converges
figures/fig1-access-trend.pdf shows the share of CFPS adults reporting any internet use, by hukou, across waves.
- What you see: rural goes from ~21% in 2014 to ~52% in 2020. Urban goes from ~48% to ~71%. The gap closes from ~27 pp to ~19 pp.
- What the manuscript first claimed (wrongly): “the gap narrowed from 40 pp in 2010 to 15 pp in 2020 across six waves.”
- What verification caught (CRIT-1): Y1 access is only measured 2014, 2016, 2018, 2020 — four waves, not six. The “40 pp / 15 pp / 6 waves” claim was figure-data drift, not the data underlying the figure.
The substantive argument (first-level convergence) survives. The numbers were corrected to “27 pp → 19 pp, four waves, 2014–2020”. You will see how this correction propagated in §15.
12.2 Figure 2 — Cohort layering
figures/fig2-Y2-by-cohort.pdf plots weekly internet hours among users, by birth cohort, across waves.
- What you see: post-1985 cohorts spend ~14–16 hours/week; pre-1965 cohorts ~6–9 hours/week. The cohort gap is large and approximately constant across waves.
- What this means for H2: consistent with cohort-as-cause. Within-person age slopes (from the FE specification) are nearly flat — the population mean is rising mostly because younger cohorts replace older cohorts.
- What you must NOT claim: that cohort causes this. APC is non-identified; we report HAPC and Deaton–Paxson as bounds, not point estimates.
12.3 Figure 5 — Oaxaca decomposition
figures/fig5-oaxaca-decomp.pdf is a stacked-bar showing the threefold decomposition of the rural–urban Y2 gap.
- Total gap: 0.815 hours/week
- Endowments: −0.395 (rural respondents have more of some inputs that predict use)
- Coefficients: +1.151 (rural respondents get less return on identical inputs)
- Interaction: small.
The coefficients (returns) component dominates, which the institutional-sorting account predicts and the pure resource account does not. This is the figure that does the theoretical work of the paper.
13. scholar-code-review — six reviewers, one report
Goal: before believing any number, dispatch six specialized reviewers to audit the scripts.
argument-hint: "[full|correctness|robustness|statistics|reproducibility|style|
data-handling] [optional: script-dir-or-file]
[optional: design-doc-path]"
13.1 Run
> /scholar-code-review full output/digital-divide-china-cfps/scripts/
> /scholar-code-review data-handling output/scripts/01-clean.R
> /scholar-code-review statistics output/scripts/04-main-models.R \
output/design/design-blueprint-2026-05-04.md
Passing the design document as the third argument matters: for the statistics and data-handling reviewers, the design blueprint is ground truth. Without it they can only check internal consistency, not fidelity to what you committed to.
Surrogate disclosure (read before §13.3 and §13.4). In the run that produced this handbook artifact, the six
review-code-*agents could not be dispatched as real Task subagent calls from the orchestrator’s execution thread. The reports shown below were therefore authored as orchestrator-internal surrogates rather than as outputs of real Task dispatches. PerCLAUDE.md“Real-agent dispatch heuristic,” surrogate-authored reports do not satisfy the Phase 5.5 gate; the scorecard in §13.4 is included as a template of what the real output looks like, not as a passing gate record. The disclosure also appears in Appendix E. When you runscholar-code-reviewyourself in a session with Task-dispatch enabled, the real outputs replace this surrogate. This is the same failure mode §9.4 names as the pipeline’s #1 silent failure — declared rather than hidden.
13.2 What runs
Step 0 discovers the scripts (your path, or a glob over output/scripts/*.{R,py,do,jl}), locates codebooks, design docs, and the manuscript, and assembles one code review package handed identically to all six agents. Then they run in parallel:
| Agent | Audits for |
|---|---|
review-code-correctness | Merge/join errors, filter logic (!= silently dropping NA), wrong model family, wrong SE spec, stale variable references, Inf/NaN from log(0) surviving into mean/sd/cor |
review-code-data-handling | Category mapping vs. codebook, dataset-specific missing codes (GSS .d/.i/.n; NHANES 7/9/77/99; PSID 0/9/99/999), reverse-coding, scale construction, sample restrictions, hardcoded absolute paths |
review-code-statistics | Estimator↔design match, principle of marginality, SE and clustering choice, per-method causal checks (DiD parallel trends, IV first-stage F, RD bandwidth and McCrary, matching balance, DML cross-fitting), multiple-comparison correction, AME reporting |
review-code-reproducibility | Pipeline completeness, dependency pinning, path portability, seeds, environment spec, documentation — issues an overall A–F reproducibility grade |
review-code-robustness | Hardcoded assumptions, silent failures (suppressWarnings around model fitting, broad tryCatch), data-boundary cases (empty df after filter, single-level factor, perfect separation), missing seeds |
review-code-style | Hallucinated function arguments and packages, deprecated APIs (aes_string(), gather()), DRY violations, dead code, R (T/F, attach(), setwd(), 1:length(x)) and Python (mutable defaults, bare except:, os.chdir()) anti-patterns |
Three properties make this trustworthy rather than decorative:
- The review is code-only. No agent may
Read,Grep, orGloba data file — even one markedCLEARED. When a recode cannot be checked without the data, the verdict is UNVERIFIABLE, never “resolved by opening the data.” The PreToolUse guard is the mechanical backstop. - Every finding cites file, line, and snippet. There is zero tolerance for false positives: “better to miss a minor issue than cry wolf.”
- The Objectivity Mandate is inlined into every agent. No opening praise, no softening a CRITICAL to a WARNING, no “minor revisions” over a real problem. A report that hedges issues into invisibility violates the mandate even if it technically produced output.
13.3 Severity, agreement, and grades
Each agent reports CRITICAL (must fix before trusting results) / WARNING (fix before submission) / INFO (may fix), with IDs like CRIT-CORR-001. The synthesis step dedupes across agents and marks anything two or more agents flagged with ★★.
| Per-script grade | Condition |
|---|---|
| A | 0 CRITICAL, ≤1 WARNING |
| B | 0 CRITICAL, 2–3 WARNING |
| C | 1 CRITICAL, or >3 WARNING |
| D | 2–3 CRITICAL |
| F | >3 CRITICAL |
| Overall verdict | Condition |
|---|---|
| CLEAN — READY TO USE | 0 CRITICAL and ≤5 WARNING total |
| FIXES NEEDED | 1–5 CRITICAL, or >5 WARNING |
| MAJOR ISSUES — DO NOT TRUST RESULTS | >5 CRITICAL, or any ★★ CRITICAL |
Some calibrations worth memorizing, because they are the difference between a real audit and a lint pass. These are CRITICAL, not warnings: a wrong model family; a merge that changes N; a missing clustering or weighting specification; a missing-value code treated as valid data; a reverse-coded item never flipped; a hardcoded absolute path (it blocks replication); a hallucinated function argument (it will error or be silently ignored); an interaction term without its main effects; and — since a recent revision — a missing multiple-comparison correction when K ≥ 3, upgraded from WARNING to CRITICAL.
13.4 Real consolidated scorecard
From reports/code-review-2026-05-04.md:
| Reviewer | CRITICAL | ERROR | WARN | INFO | Verdict |
|---|---|---|---|---|---|
| review-code-correctness | 0 | 0 | 1 | 1 | PASS |
| review-code-data-handling | 0 | 2 (accepted) | 2 | 0 | PASS-w/-accept |
| review-code-statistics | 0 | 1 (accepted) | 2 | 1 | PASS-w/-accept |
| review-code-reproducibility | 0 | 0 | 2 | 1 | PASS |
| review-code-robustness | 0 | 0 | 2 | 1 | PASS |
| review-code-style | 0 | 0 | 0 | 3 | PASS |
| Total | 0 | 3 (accepted) | 9 | 7 | PASS |
The review found no CRITICAL issues, but it did correctly flag that the H3 three-way interaction p-value reported in the script comments was the wrong row of the regression output. That same finding will reappear in §15 — the agent that catches it costs about $0.30; the reviewer who would have caught it after submission would cost you a desk reject.
13.5 Two artifacts you should actually read
Beyond the scorecard, two sections of the consolidated report are unique to this skill and repay attention:
- The variable lineage map (from the data-handling agent):
Analytic Variable | Raw Source | Transformations | Scripts | Verified?. This is the only place in the whole pipeline where you can see, in one table, howhukou_ruralgot from a raw CFPS column to a model term. - The pipeline map and dependency audit (from the reproducibility agent): which script produces which table or figure, what it depends on, and what is missing. If a manuscript table has no producing script, this is where it shows up.
13.6 Where it blocks
scholar-code-review never modifies a script — it is strictly read-only, diagnostic. But its verdict gates two pipelines:
| Context | Effect |
|---|---|
scholar-full-paper Phase 5.5 | MAJOR ISSUES blocks Phase 7 (drafting) |
scholar-grant Phase 5G.0 | MAJOR ISSUES blocks Phase 6 (mock review panel) |
After scholar-analyze / scholar-compute / scholar-eda standalone | Recommended, not gating |
It is deliberately independent of scholar-verify (§15): this skill checks whether the code is right; scholar-verify checks whether the manuscript matches the outputs. Neither substitutes for the other, and neither calls the other.
13.7 Before it runs — DRAFTED → REVIEWED+HASHED → EXECUTABLE (v5.29)
Everything above audits code that has already executed. Since v5.29 there is a second review, earlier and narrower, on the other side of the run: model-authored code is reviewed before it is allowed to produce a number. The reasoning is economic. A bug is cheap to fix in a script and expensive to fix after it has produced a table you have started writing prose around.
A qualifying script moves through three states:
| State | Meaning |
|---|---|
DRAFTED | written to a file — never run inline |
REVIEWED+HASHED | three agents have read it, and each script carries a SHA-256 in the manifest |
EXECUTABLE | the gate is GREEN; the file may be invoked |
What qualifies. Anything that fits a model, constructs or recodes an analysis variable, restricts a sample, or otherwise produces a number that could reach a manuscript. A pilot is exempt only if it is capped, feeds nothing downstream, and is logged as a pilot. “Full corpus” is one trigger for at-scale work, not the definition of it.
The rule with teeth: the reviewed bytes must be the executed bytes. You invoke the reviewed file — Rscript scripts/04-main-models.R. Copying a reviewed block back into a REPL is prohibited, and the manifest’s SHA-256 is what makes that checkable rather than aspirational. This is the no-inline-execution discipline from earlier in the workshop with a hash attached to it.
Before the first model-bearing run, the skill emits a receipt:
Pre-execution review: report <path> · review_id <id> · scripts 4 hashed · gate GREEN
The rollout covers six skills: scholar-analyze, scholar-eda, scholar-ling (v5.29.1), then scholar-compute, scholar-data, scholar-simulate (v5.29.2, which also hash-binds scholar-respond). If you run one of those and see no receipt, the gate did not run — that is a finding, not a convenience.
Stop and check. Read reports/code-review-statistics-2026-05-04-iter1.md. Find one issue marked WARN. Decide whether you would (a) fix it now, (b) accept it in analysis/limitations-accepted.md, or (c) demote it to “discussion”. Then find one marked UNVERIFIABLE and ask yourself what document — not what data file — would have made it verifiable. Finally, open your most recent analysis log and look for the pre-execution receipt: if the script that produced your headline table never passed through REVIEWED+HASHED, you know less about it than you thought.
14. scholar-write — draft from locked results, not from imagination
Goal: produce a manuscript draft in which every number traces to a locked CSV cell, every citation is marked for verification, and every figure reference matches the actual rendered figure.
argument-hint: "[draft|revise|polish] [section] on [topic] for [journal],
e.g., 'draft Introduction on redlining and activity-space
segregation for ASR'"
14.0 Before you draft — what scholar-write needs configured
scholar-write is the skill most sensitive to setup, because it reads from more places than any other. Run through this once; it takes about five minutes and it is the difference between a draft that cites your library and one that cites the open web.
1. Confirm the suite is installed as personal skills. bash setup.sh (§2.4.2) installs all 44 skills into ~/.claude/skills/, which is what makes /scholar-write available in any directory rather than only inside the cloned repo:
$ ls ~/.claude/skills/scholar-write/SKILL.md # should exist
$ ls ~/.claude/agents/ | wc -l # 22 agents
2. Confirm your reference library was detected. This is the step that matters most. setup.sh auto-detects Zotero and optionally configures BibTeX, EndNote, and a CrossRef email; the result is recorded in the repo’s .env:
$ cat "$SCHOLAR_SKILL_DIR/.env"
SCHOLAR_ZOTERO_DIR=/Users/you/Zotero
SCHOLAR_CROSSREF_EMAIL=you@university.edu
If detection failed or you keep your library somewhere unusual, set the override that matches your manager and put it in your shell profile so it persists:
| Env var | Points at |
|---|---|
SCHOLAR_ZOTERO_DIR | The Zotero directory containing zotero.sqlite |
SCHOLAR_BIB_PATH | A .bib file, if you use plain BibTeX |
SCHOLAR_ENDNOTE_XML | An exported EndNote XML library |
SCHOLAR_CROSSREF_EMAIL | Your email, for the CrossRef/OpenAlex polite pool |
Zotero is searched by copying the live database to a temp file first, so you do not need to close Zotero — but the file must exist where the variable points. Verify the library is actually reachable before you draft:
> /scholar-citation verify drafts/any-existing-draft.md
If the report shows Tier 1 (local library) hits, you are configured. If everything resolves at Tier 2 or 3, the library was not found and every citation is coming from the web.
3. Understand what a missing library costs you. Nothing errors. scholar-write degrades quietly:
- The Tier 0/1 citation pool is empty, so drafting leans on external APIs and produces more
[CITATION NEEDED]markers. - The article library is empty, so there is no voice calibration at all — this applies to both editions and is the single biggest quality difference you control. §14.3 is how you fix it, including seeding it with your own published papers.
- (Extended only) Exemplar retrieval falls back from the curated library to a per-project Zotero scan, and if Zotero is missing too, to nothing.
- The Theory-section carry-forward rule still fires, but with fewer verified sources to carry forward.
4. Know that scholar-write is data-safety gated. It is a Tier B skill: it checks .claude/safety-status.json and refuses fail-fast on NEEDS_REVIEW:*, HALTED, or LOCAL_MODE inputs. It does not implement the LOCAL_MODE dispatch contract itself — it just declines. Resolve the sidecar with /scholar-init review (§6.2) first.
5. Under Codex, there are no slash commands. Export SCHOLAR_SKILL_DIR to the repo root and symlink the skill folders into ~/.codex/skills/, then invoke in prose — “Use scholar-write to draft the Introduction for ASR.” Persist the variable:
$ echo 'export SCHOLAR_SKILL_DIR="$HOME/open-scholar-skills"' >> ~/.zshrc
14.1 Run
> /scholar-write draft section=full-paper
results-lock=design/results-lock-2026-05-04.md
blueprint=drafts/section-blueprint.json
journal="Social Forces"
word-target=10000
Sections it knows: introduction, theory, data_methods, results, discussion, abstract, full, book-chapter.
| Mode | When |
|---|---|
| draft | No existing text — write the section |
| revise | You paste existing text plus feedback; every substantive change is annotated [REVISED: reason] and summarized |
| polish | Text is structurally fine; vocabulary, tense, abbreviation, hedging, and citation-format audit only |
| expansion (internal) | Auto-detected from a Phase 11.5 word-budget directive or a Phase 7b route_back_to block — splices new content into named targets, never redrafts |
14.2 The three modes — and the audits that keep REVISE honest
| Mode | When | Input |
|---|---|---|
| DRAFT (default) | Writing a section from scratch | Topic + findings + hypotheses |
| REVISE | Improving existing text against feedback | Your text, pasted, plus the feedback |
| POLISH | Final pass before submission | Your text; no structural change needed |
Mode is inferred from whether you paste text: text present → REVISE or POLISH, absent → DRAFT.
There is also a no-journal mode. If no target journal is named or inferrable, the skill skips journal-specific formatting, word limits, and section conventions and writes general academic prose. Pass a numeric word budget and it overrides the journal default — useful for a book chapter or a report.
REVISE annotates every substantive change [REVISED: reason] and appends a Change Summary. Before it revises anything it runs a nine-item checklist — topic sentences present, hedging matched to design strength, no passive voice in Methods/Results, Theory naming mechanisms explicitly, Results leading with findings rather than model descriptions, all [CITATION NEEDED] markers listed — plus three audits that are the real substance of this mode.
The Claims Audit (mandatory for Results and Discussion)
Every interpretive claim — any sentence that goes beyond reporting a number to characterize a pattern, name a mechanism, or draw an inference — goes in a table:
| # | Claim | Supporting numbers | Holds cross-group? | Holds within-group? | Measured or imported? | Verdict |
|---|---|---|---|---|---|---|
| 1 | … | … | YES/NO | YES/NO | Measured / Imported from … | KEEP / REVISE / FLAG |
Two rules make this worth the effort:
- A claim that holds cross-group but not within-group (or vice versa) must state both. The skill’s own example: “CN has less negative Democrat content than EN” is true across groups, while within CN, Democrats still face a 5:1 negative-to-positive ratio. Both facts are true; reporting only the first is a real misrepresentation, and it is the kind that survives peer review.
- “Imported” claims must be marked. If a sentence asserts something about your study context but rests on other literature rather than your data, it gets
[IMPORTED: source], and the cited source must actually apply to your specific case. Unsupported imports become[UNVERIFIED MECHANISM CLAIM].
The Borrowed Claims Detector (mandatory for Theory and mechanism sections)
Scans mechanism prose for three failure shapes: causal claims about your context with no citation; claims describing features of your data environment (“absence of gatekeeping,” “algorithmic amplification”) that you never measured; and claims lifted from one literature and applied to another context without checking they transfer — English-platform findings asserted about a non-English ecosystem, say.
Each flagged claim needs one of: a citation demonstrating it in the context you are studying; hedging (“If [feature] holds in this context…”, “To the extent that…”); or removal and replacement with something your data supports.
Literature Claims Verification (Introduction and literature review)
Every characterization of what a cited paper found or argued is checked against the verified citation pool or the knowledge graph — catching paraphrase drift, strength inflation, and finding conflation.
Together these three are the most useful part of the public skill, and they are what makes REVISE more than a rewrite. Run REVISE on a section you drafted by hand and read the Claims Audit table: it is an unusually direct way to see which of your own sentences outrun your evidence.
14.2A What it reads before writing — and what wins
scholar-write runs a Step 0 before writing a word. How long that Step 0 is depends on your edition.
Both editions:
| Step | Reads | Effect |
|---|---|---|
| 0a-safety | .claude/safety-status.json | Halts on NEEDS_REVIEW / HALTED / LOCAL_MODE |
| 0b | references/writing-protocol.md | Builds three things: the article-knowledge-base calibration (§14.3), the verified citation pool, and the artifact registry |
Extended edition adds the machinery that binds drafting to locked results and a per-section contract:
| Step | Reads | Effect |
|---|---|---|
| 0a-lock | results-locked/LATEST.txt | Verifies the lock; refuses to draft (exit 1) if verification fails; pins tables and figures to the locked snapshot |
| 0a-blueprint | drafts/section-blueprint.json | The per-section authoring contract from §9.5 |
| 0a-revision-directive | Phase 11.5 / 7b directives | Switches to expansion or patch mode; directives older than 24 h are ignored |
| 0a-exemplars | The curated exemplar library (§14.3, §20G) | Real paragraphs from your target journal, for shape only |
| 0a-outcomes | reader_outcomes[] | What the reader must be able to do after reading |
| 0a-lrh | drafts/scholar-lrh-*.md | Binding for Theory sections |
On the extended edition, when these conflict a precedence ladder decides:
| Tier | What | Status |
|---|---|---|
| 1 | Word budget · required hypotheses · reader outcomes | Binding |
| 1.5 | Reader-outcome verifiers | Binding, machine-checked |
| 2 | Exemplar paths, derived moves | Primary source of prose rhythm |
| 3 | Structural moves | Advisory fallback |
| 4 | Forbidden patterns | Hard constraint |
Two extended-only rules deserve emphasis:
The Theory section is bound to the literature review. When drafting Theory, the skill locates the Phase 2 scholar-lrh-*.md file and treats it as canonical. At least 70% of the citations named there must carry forward into the Theory prose or the .bib, enforced by lit-review-carry-forward-check.sh. Dropping one requires a logged justification (superseded / duplicate / low-quality / out-of-scope). The skill must not re-derive citations from its training data. This is why the drafted theory cites the literature you actually reviewed rather than the literature the model vaguely remembers.
Exemplars are studied for shape, never copied. expansion-quality-check.sh detects 10-gram overlap with an exemplar and fails the run.
Grounding in passages, not memory (both editions, all three modes). This one sits next to the citation-integrity rule rather than inside the Step 0 ladder, because it applies to draft, revise, and polish alike. If
/scholar-rag statusshows an index (§8F),scholar-writeretrieves supporting passages from your own library —rag_search("<claim or subtopic>", k=6, hybrid=true), or thequery.pyCLI — and phrases claims against what the page actually says rather than against a remembered gist. Page-anchored text is also what keeps a claim from drifting upward in strength while you paraphrase it. The distinction that keeps this honest:scholar-ragsurfaces the text,/scholar-citationowns the bibliographic record. Retrieval never mints a citation; every reference still comes from the Verified Citation Pool.
On the public edition none of that machinery exists — no results lock, no section blueprint, no reader-outcome verifiers. The equivalent discipline is procedural rather than mechanical: you supply the numbers, and §14.2’s Claims Audit is what stops the prose outrunning them. The public skill compensates with stronger in-mode auditing; the extended one compensates with stronger pre-draft contracts. Neither is a substitute for reading the draft.
14.3 Making it draft in your voice
Everything so far makes the draft correct. This subsection makes it sound like you rather than like a language model writing sociology. It is the highest-leverage part of §14, and the part most people never do.
Three mechanisms do the work, at three different moments:
| Mechanism | When | Granularity | |
|---|---|---|---|
| A | Article library — scholar-write/assets/ | Read at write-time to pick examples | Whole papers |
| B | Curated exemplars — /scholar-exemplar-curate | Step 0a-exemplars, before drafting | Single paragraphs |
| C | Tiny topos — /scholar-polish (§17) | After drafting | Sentences |
They are complements, not alternatives. A teaches the model how you build an argument across a whole paper; B shows it the shape of one paragraph in one section of one journal; C repairs sentence-level tells afterwards. If you only ever do one, do A — it is the cheapest and it calibrates everything downstream.
14.3.1 Path A — the article library
scholar-write ships with an assets directory that it reads at write-time to select worked examples. Three PDF corpora:
.claude/skills/scholar-write/assets/
├── example-articles/ ← PUBLIC: your own published papers
│ └── (extended edition names these user1-articles/ + user2-articles/)
├── top-journal-articles/ ← 5–20 recent papers from journals you target
├── index.md ← the catalog scholar-write actually reads
├── article-knowledge-base.md
└── section-snippets.md
The public edition uses example-articles/; the extended edition renames it user1-articles/ and adds user2-articles/ for a second voice — a co-author, or your own work in a different subfield. index.md in each edition names the directories that edition reads, so it is the authority.
Confirm the directory name before you copy anything in — a directory by the wrong name is silently ignored:
$ ls "$SCHOLAR_SKILL_DIR/.claude/skills/scholar-write/assets/"Public shows
example-articles/; extended showsuser1-articles/.
How the skill uses it. At write-time it reads index.md, picks 1–2 user articles matching your domain and method, plus 1–2 top-journal articles matching your target venue, then extracts text from just those:
$ pdftotext "assets/user1-articles/<paper>.pdf" - | head -250
So the library scales without cost: only the handful of selected papers are ever read.
The three generated files, and what each is for:
| File | Contents |
|---|---|
index.md | One row per paper — filename, citation, journal, method, topics, best-for. This is the selection table; without a row, a PDF is invisible |
article-knowledge-base.md | Per paper: opening line, gap sentence, contribution claim, voice register, sentence architecture, paragraph rhythm. Also the empirical section word counts by journal that §14.5’s budget table is calibrated from |
section-snippets.md | Verbatim quotes sorted into nine rhetorical categories: opening hooks · gap statements · contribution claims · theory and mechanism descriptions · methods lead sentences · results lead sentences · discussion openers · hedging and scope conditions · high-impact quantitative sentences |
Setting it up — three steps.
- Copy your own published PDFs into
example-articles/(extended:user1-articles/). - Copy 5–20 recent papers from your target journals into
top-journal-articles/. - Ask Claude Code to index them. One prompt builds all three files:
Scan all PDFs in .claude/skills/scholar-write/assets/example-articles/ and
.claude/skills/scholar-write/assets/top-journal-articles/. For each paper,
use pdftotext to extract the first 300 lines, then populate:
1. assets/index.md — a row per paper (filename, citation, journal, method,
topics, best-for)
2. assets/article-knowledge-base.md — a structured entry per paper (opening
line, gap sentence, contribution claim, voice register, sentence
architecture, paragraph rhythm)
3. assets/section-snippets.md — verbatim quotes in the 9 rhetorical categories
Re-run it whenever you add papers.
The directory ships empty. On a fresh public install index.md, article-knowledge-base.md, and section-snippets.md are ~50–85-line templates with zero PDFs behind them — so the calibration they provide is nil until you add papers. For scale, a heavily used install runs about 32 of your own articles, 87 top-journal exemplars across 15+ journals, and a 1,300-line knowledge base. You do not need anything near that: three of your own papers and five from your target journal already change the output noticeably.
scholar-write works with an empty assets directory — it falls back to built-in journal conventions. It just writes like nobody in particular.
14.3.2 Path B — curated paragraph exemplars [Extended]
(scholar-exemplar-curate ships only in the extended edition — see §2.4. Path A above works on both, and is the one to do first regardless.)
Where the article library teaches whole-paper architecture, /scholar-exemplar-curate builds a cross-project library of individual annotated paragraphs, keyed by journal × section. Each is a real published paragraph plus a note on what it does well:
---
journal: american-sociological-review
section: methods
source_id: zotero:ABCD1234
curated_by: user-work
---
## Excerpt
> [80–350 words, verbatim]
## What it does well
- Opens with the sampling frame rather than a tour of the dataset.
- Justifies the analytic-sample restriction in the same sentence that states it.
## Caveats / when not to mimic
- Assumes a panel; a cross-section cannot borrow the attrition move.
The “What it does well” block is load-bearing — generic praise like “clear writing” is banned by the extraction contract. Excerpts are studied for structure only: expansion-quality-check.sh fails the run on 10-gram overlap, so exemplar text cannot leak into your manuscript.
What ships pre-seeded — eight journals:
| Journal | Exemplars |
|---|---|
| american-sociological-review | 28 |
| demography · journal-of-sociolinguistics | 25 each |
| american-journal-of-sociology | 23 |
| social-forces | 22 |
| pnas | 21 |
| nature-human-behaviour | 20 |
| journal-of-marriage-and-family | 5 |
Write for anything else and you have none — silently.
Three sourcing modes:
| Mode | Source | Use for |
|---|---|---|
user-work | Zotero items tagged My Publications | Your voice. Start here |
top50 | ~/.claude/scholar-knowledge/top-50.bib | Aspirational voice |
zotero | Your library, filtered by journal × time window | Coverage for a target journal |
> /scholar-exemplar-curate user-work
> /scholar-exemplar-curate zotero "Social Forces" methods --year-from 2020
> /scholar-exemplar-curate review
user-workoutranks everything else. When several candidates exist for the same journal × section, user-work exemplars are sorted first — the skill’s stated reason is that your own published voice is the most relevant template for your next paper.
Tag your papers My Publications in Zotero first (or use --user-tag <tag> / SCHOLAR_USER_WORK_TAG). For top50, create the list yourself — it does not exist by default:
$ ${EDITOR:-nano} ~/.claude/scholar-knowledge/top-50.bib
Plain BibTeX, each entry with a file = {…} field pointing at the PDF. Ten papers you genuinely admire beat fifty you merely cited.
Nothing enters without your approval. Every candidate stages first:
_staging/<journal>/<section>/ → review → <journal>/<section>/ (approved)
↓
_rejected/<journal>/<section>/ (+ reason, never re-proposed)
/scholar-exemplar-curate review walks each one and waits for [a]ccept / [r]eject / [s]kip. Budget realistically: one journal across all sections with 20 candidates dispatches up to ~140 extraction agents, about five minutes, with a 30–50% accept rate. Steady state is 5–15 exemplars per journal × section.
14.3.3 Verify both paths are actually feeding the draft
# Path A — is the catalog populated?
$ wc -l "$SCHOLAR_SKILL_DIR/.claude/skills/scholar-write/assets/index.md"
# Path B — is the curated library being hit?
$ bash "$SCHOLAR_SKILL_DIR/scripts/exemplar-lookup.sh" social-forces methods
STATUS=GREEN
SOURCE=curated # curated | fallback | both
COUNT=4
SOURCE=curated means your library is feeding drafting; fallback means it found nothing and is scraping Zotero per-project; COUNT=0 is the silent failure this whole subsection exists to prevent.
Both libraries are cross-project and cumulative. Curate once and every future paper for that journal drafts against them. They are the parts of this pipeline that compound.
Stop and check. Put three of your own papers in example-articles/ (extended: user1-articles/), run the indexing prompt, then draft a section and read it aloud. If it still does not sound like you, that is what /scholar-polish (§17) is for — but fix the architecture first, because polish cannot repair structure.
14.4 The eighteen forbidden patterns [Extended]
(Extended edition only — the public skill has no forbidden-pattern table. It is still worth reading: most of these are failure modes of AI-drafted prose generally, and scholar-polish §17 catches several of them on both editions.)
Step 0d loads a table of eighteen classes of pipeline machinery that must never appear in body prose. This is the difference between a manuscript and a pipeline log:
| # | Forbidden | Write instead |
|---|---|---|
| P1 | Limitation IDs (L-A4) | Plain prose |
| P2 | (spec_id=M3, results-registry.csv) | (Table 2, Model 3, β = 0.18, p = .003) |
| P3 | Floating M3 / R5 | “Model 3 (Table 2)” |
| P4 | “Read against H2” | A named theory bridge |
| P5 | Raw method jargon (KHB, IKY) | The method named in words |
| P6 | Mangled variable names (raclive_int) | The concept |
| P7 | “K=6 primary tests” | “the six primary tests” |
| P8 | A bulleted - H1 / - H2 list in Theory | One paragraph with (H1) tags |
| P9 | Heading parentheticals — (Demoted), (Superseded) | Remove |
| P10 | Pre-registration ledger vocabulary outside Methods | Substantive prediction language |
| P11 | Enumerated **Limitation: X** blocks | 1–3 prose sentences grouped by kind |
| P12 | Visible anchor brackets | HTML comments |
| P13 | “Pre-registered” with no public registry ID | Plain hypothesis-testing language |
| P14 | Test statistics inside the Abstract | Direction and magnitude in words |
| P15 | Lexical tics (>5 uses of one AI-fingerprint word) | Vary the diction |
| P16 | Tournament framing (“adjudicate among the three accounts” ×4) | Continuous-tradition framing |
| P17 | A four-sentence “Section 2 does… Section 3 does…” roadmap | One sentence, or none |
| P18 | A trailing future-work caveat in the Abstract | Move it to the Conclusion |
Enforcement is mechanical: pipeline-machinery-check.sh at the polish phase and submission-hygiene.sh at the submission-hygiene phase.
14.5 Word budgets, by journal
The public skill ships a full per-section grid. This is the one to work from — it is the table scholar-write actually applies:
| Section | ASR | AJS | Demography | Science Advances | NHB / NCS |
|---|---|---|---|---|---|
| Abstract | 150–200 | 150–200 | ~150 | ~250 | ≤150 |
| Introduction | 800–1,200 | 800–1,200 | 600–800 | 500–700 | 400–500 (no heading) |
| Theory / Background | 1,500–2,500 | 1,500–2,500 | 800–1,200 | in intro | integrated |
| Data & Methods | 1,500–2,500 | 1,500–2,500 | 1,500–2,000 | 800–1,200 (after Results) | 600–800 (after Results) |
| Results | 2,000–3,500 | 2,000–3,500 | 2,000–3,000 | 1,200–1,800 | 800–1,200 |
| Discussion | 2,000–3,500 | 2,000–3,500 | 800–1,500 | 500–800 | 400–600 |
| Conclusion | 200–500 | 200–500 | 200–300 | (in Discussion) | (in Discussion) |
| Total | 10,000–12,000 | 10,000–15,000 | 8,000–12,000 | 5,000–8,000 | 3,000–5,000 |
Two structural facts the table encodes, easy to miss and expensive to get wrong: for Science Advances and the Nature family, Results comes before Methods, and there is no separate Theory section — background is folded into the Introduction. Results subsections there take descriptive headings (“Redlining predicts lower activity-space diversity”), never model numbers.
The extended edition carries its own budget table driven by per-journal JSON profiles (§18.2.1), which adds Social Forces, JMF, and others, and applies hard floors — Discussion ≥ 1,200 words, Conclusion ≥ 500 — enforced by section-length-check.sh. Where the two disagree, the JSON profile is authoritative on that edition.
Both are calibrated against a corpus of 53+ published papers, and that corpus is not abstract: it is the article library from §14.3.1. assets/article-knowledge-base.md carries the per-journal empirical section counts these ranges derive from, with per-paper detail (ASR n=10, AJS n=13, NHB n=6, Science Advances n=4). Add your own target journal’s papers and the calibration improves for it — which is the concrete reason §14.3.1 is worth an afternoon.
14.6 The Methods section has a canonical shape
For JMF, ASR, AJS, Demography, and Social Forces:
### 4.1 Data — source, rationale, sampling frame
### 4.2 Analytic Sample — restriction rules + rationale, attrition, effective N
### 4.3 Measures — outcome, predictor, control construction and coding
### 4.4 Analytic Strategy — model ladder, estimand named, SE policy,
robustness plan, identification assumption
(or an explicit associational disclaimer)
Regression tables must embed the full coefficient ladder — at least 80% of the source table’s rows — never a five-row focal-contrast stub. And a footgun worth memorizing: never embed a table from the .csv when an .html exists. The CSV export flattens the two-row coefficient/SE layout and drops the significance stars, shipping a hollow table that looks complete.
14.7 Real abstract (from drafts/manuscript-final-...md)
Internet access in China rose from a minority privilege to a near-universal
condition between 2010 and 2020. Whether the underlying social structure of
digital engagement narrowed in step is the open question. Drawing on six
waves of the China Family Panel Studies (N = 204,418 person-waves; 54,825
unique respondents), we estimate internet access and weekly use intensity
models that decompose digital inequality into structural, institutional,
and life-course components. Holding education, household income, occupation,
household composition, and provincial infrastructure constant, agricultural-
hukou status is associated with -1.306 weekly hours of internet use among
users (SE 0.295; BH-FDR p = 1.39e-5) in the focal weekly-internet-hours
model and with log-odds of access lower by -0.845 (BH-FDR p < 1e-60). The
threefold decomposition of the rural-urban use gap (total = 0.815 hours/
week) attributes 1.151 hours to coefficient differences and -0.395 hours to
endowments, indicating that the gap reflects differential returns to
identical resources rather than shortfalls in resources themselves. […]
Notice the anchors embedded in the live source (HTML comments in markdown) — an extended-edition mechanism:
agricultural-hukou status is associated with -1.306 weekly hours
<!--anchor: lit focal-Y2-M3-->
... total = 0.815 <!--anchor: design total-gap-r4b--> hours/week ...
These anchors are how scholar-verify later checks that every number matches a locked cell. They are HTML comments precisely so they are invisible in the rendered document, machine-readable to anchor-verify.sh, and strippable by submission-prep.sh before export. Don’t strip them yourself, and don’t let them become visible brackets — that is forbidden pattern P12.
On the public edition there are no anchors and no lock to anchor to. The equivalent check is manual and is exactly §14.9’s: pick a number, trace it to the table, trace the table to the script. Do it on a sample of ten numbers rather than all of them, and do it before the draft leaves your machine.
14.8 What runs before it saves
The tail of every drafting run is a stack of checks. Steps 4.5 through 5b are on both editions — they are the core of the skill:
- Step 4.5 — citation verification. A hard stop. Any citation that cannot be verified becomes
[CITATION NEEDED]. - Step 4.5e — claim-content verification. Checks that each cited source actually supports the claim, flagging
CLAIM-REVERSED,CLAIM-MISCHARACTERIZED,CLAIM-OVERCAUSAL,CLAIM-UNSUPPORTED,CLAIM-WRONG-POPULATION,CLAIM-IMPRECISE,CLAIM-NOT-CHECKABLE. - Step 4.6 — reflection diagnostics. Word count, citation density, hedging calibration, hypothesis-to-result alignment, structural balance — then a self-revision pass.
- Step 4.7 — artifact placement audit. Every table and figure referenced at least once.
- Step 5 — the five-agent review panel. R1 Logic · R2 Rhetoric · R3 Journal Fit · R4 Citations · R5 Clarity → a scorecard → one reviser pass prioritizing items two agents flagged → you accept, edit, or reject.
- Step 6 — Source Integrity. A three-agent panel: Originality Auditor, Claim Verifier, Attribution Analyst.
Then the file is written to exactly one path: drafts/draft-<section>-<slug>-<YYYY-MM-DD>.md. Both editions run a version-collision check before any Write, so an existing draft is never overwritten — you get -v2. On the extended edition, alternate paths are additionally rejected by draft-path-contract.sh before Write is called — because Phase 11 assembly discovers manuscripts by globbing that pattern by modification time, and a file written anywhere else is silently dropped from the final paper. That is not hypothetical; it is the documented cause of a real content-loss incident.
The specific failure this guards against is worth naming, because it is a pure model-behaviour bug rather than a user error. Language models have seen an enormous amount of Jekyll and Hugo source, where sectioned documents live at content/manuscript-sections/01-introduction.md. That is a strong attractor: left unconstrained, the model writes drafts/manuscript-sections/NN-section.md, which looks entirely reasonable, passes every content check, and is invisible to the assembler. The pre-Write self-check (added in v5.11.1) means those paths can no longer land on disk at all.
14.9 Stop and check
Open drafts/draft-manuscript-...md. Find one numeric claim. Confirm:
- There is an
<!--anchor: ...-->next to it. - The anchored cell exists in
tables/. - The number in prose matches the cell to the rounding shown.
If any of those three fails, the draft is not ready for verification yet.
15. scholar-verify — the workshop’s central lesson
Goal: find the errors you would have missed before submission.
A pipeline that never fails verification is a pipeline that isn’t checking hard enough. Our run found 7 CRITICAL issues and 6 WARN issues. That is a successful verification, not an embarrassing one.
# public edition
argument-hint: "[full|stage1|stage2|numerics|figures|logic|completeness]
[manuscript-path] [output-dir]"
# extended edition adds
[--lock <id>] [--scope 'Section A,Section B']
15.1 Run
> /scholar-verify full
> /scholar-verify stage1 --artifacts-dir output/digital-divide-china-cfps/
> /scholar-verify stage2 draft.md --lock LATEST --scope "Results §3.2"
> /scholar-verify numerics --no-manuscript # Phase 6.5 pre-draft mode
| Mode | Runs |
|---|---|
full (default) | All four agents, both stages |
stage1 | Agents 1 + 2 — raw outputs vs. manuscript objects |
stage2 | Agents 3 + 4 — manuscript objects vs. prose |
numerics / figures / logic / completeness | One agent only |
Flags: --manuscript <path> skips auto-detection; --artifacts-dir overrides where tables and figures come from; --no-manuscript runs Stage 1 before a draft exists. --lock and --scope are extended-edition only.
15.2 Two stages, four agents
Raw script outputs ──[Stage 1]──▶ Manuscript tables & figures ──[Stage 2]──▶ Prose claims
(CSV, HTML, PDF) (what the reader sees) (what you assert)
| Agent | Compares | Catches |
|---|---|---|
verify-numerics | Raw CSV/HTML → manuscript tables | Transcription slips, rounding, dropped rows or columns, log-odds↔AME conversion errors |
verify-figures | Rendered figure files → captions and prose | Claims about a figure that the image does not support |
verify-logic | Manuscript tables/figures → prose | Misquoted numbers, wrong table references, significance and direction errors, hypothesis-adjudication errors, causal overreach |
verify-completeness | The whole artifact chain | Orphaned outputs, numbering gaps, missing cross-references, variable-name drift, untraceable scripts |
verify-figures must actually look at the picture. The rule is explicit: it renders or reads every image file and checks counts, identities, colours, presence, and structure against the caption. If it cannot render an image, the verdict is UNVERIFIABLE — never a default PASS. This is the agent that caught four of our seven CRITs.
15.3 The lock — why verification is not a moving target [Extended]
(Extended only — the public edition has no results lock. There, verification reads the live tables/ and figures/, which means you must not regenerate outputs between drafting and verifying. That discipline is manual: finish the analysis, then draft, then verify, and do not go back and re-run a script in the middle.)
By default, when results-locked/LATEST.txt exists, scholar-verify reads tables and figures from the lock, not from the live output directories, and refuses a live read otherwise. To override you must create .claude/unlock-verify.sentinel or set SCHOLAR_VERIFY_UNLOCK=1; a bare --no-lock exits with an error.
Each report also pins manuscript-sha256: and manuscript-path: in its first 30 lines. This closes a real bug: without SHA pinning, a gate could re-flag a CRITICAL that a later polish pass had already fixed, and the pipeline would loop forever re-routing between phases. That failure was observed on a real project in May 2026.
15.4 Severity and verdicts
Findings: CRITICAL (must fix) / WARNING (should fix) / INFO (may fix), plus two special tiers — UNTRACEABLE (a number with no provenance; CRITICAL) and DERIVED-UNVERIFIED (derivable in principle, not checked; WARNING).
| Verdict | Condition |
|---|---|
| READY FOR SUBMISSION | 0 CRITICAL, ≤3 WARNING |
| REVISIONS NEEDED | 1–3 CRITICAL, or >3 WARNING |
| MAJOR ISSUES — DO NOT SUBMIT | >3 CRITICAL, any ★★ CRITICAL, or any DEGRADED agent |
That last clause is extended-only, and it is the anti-silent-failure rule: every agent report must state SCANNED: <N> artifacts, and if the line is missing or the count is zero the agent is marked DEGRADED and the whole verdict is forced to MAJOR ISSUES — because an agent that scanned nothing and found nothing looks exactly like an agent that scanned everything and found nothing.
Two further extended-only guards work the same way. Every agent is dispatched with an explicit --write-to <path> and must end its output with WROTE: <path>; if the file is not on disk, the orchestrator fails closed rather than scraping the agent’s chat output for its report. And if any of the four agent profile files is missing, the skill refuses to start at all.
On the public edition you are the degraded-agent check. Nothing forces an agent to declare how much it scanned, so a verification run that inspected two figures and a run that inspected twelve produce similarly confident-looking reports. Before trusting a PASS, open each of the four agent reports and confirm it actually names the artifacts it checked. A report that discusses no specific table or figure by name did not do the work.
Rounding tolerance, since it comes up constantly: ±1 in the last decimal is a WARNING; ±2 or more is CRITICAL; inconsistent decimal places within a table, or between a table and the text, is a WARNING.
15.5 Real findings — the seven CRITs
From verify/verification-report-2026-05-04.md:
| Agent | Verdict |
|--------------------|--------------------------------------|
| verify-numerics | NEEDS-REVISION (1 WARN) |
| verify-figures | NEEDS-REVISION (4 CRIT, 2 WARN) |
| verify-logic | NEEDS-REVISION (2 CRIT, 3 WARN) |
| verify-completeness| NEEDS-REVISION (1 CRIT, 5 WARN) |
The seven CRITs (paraphrased):
- CRIT-1 (Fig 1). Manuscript says “6-wave 40 pp → 15 pp”; data is “4-wave 27 pp → 19 pp”. Action: revise prose to match figure.
- CRIT-2 (Fig 2 subtitle). Subtitle says “2014–2020”; analytic Y2 window is “2014–2018”. Action: edit subtitle inline.
- CRIT-3 (Fig 3 type). Manuscript describes a “wave-by-wave coefficient trajectory”; rendered figure is a “Y1-only descriptive bar chart”. Action: prose now describes the actual figure; coefficient trajectory is cited in tables instead.
- CRIT-4 (Fig 4 cohort × hukou). Three claims about Fig 4 do not match the rendered image. Action: rewrite the three sentences.
- CRIT-5 (Table 1 dual identity). Table 1 referenced as both “descriptives” and “Y1 ladder”. Action: renumber.
- CRIT-6 (H3 wrong row). The H3 p = 0.92 cited in Abstract / Results / Discussion / Conclusion is the main-effect row, not the triple-interaction row. Action: re-extract from
adjudication-log.csvH3-CORRECTED. (Verdict survives — H3 is still null.) - CRIT-7 (Y1 M3 N). Two N values reported (108,526 and 108,509). Action: standardize on locked cell.
Four of seven were figure-related. That is not a coincidence: prose about figures is where a language model’s fluency most easily outruns the evidence, because nothing forces it to look.
15.6 Routing a fix back [Extended]
(Extended only.) Each agent can append a machine-readable route_back_to block that scholar-write consumes to make a targeted patch instead of a rewrite:
route_back_to:
phase: 7
section: "Results §3.2"
specific_item: "Figure 2 subtitle wave range"
action: re-embed-from-source # or rewrite-paragraph | add-citation |
# fix-stutter | restore-subsection |
# extend-paragraph
source_artifact: figures/fig2-Y2-by-cohort.pdf
severity: MAJOR
15.7 The pipeline impact
Honest note (read first). The “fix-up then re-pass verification” pattern shown below is in tension with the project’s
feedback_preserve_ai_failure_casesdiscipline rule (CLAUDE.md §”Preserve AI failure cases — without conflating with mark-pipeline-done”), which warns against silently rewriting defects + re-passing them as if the original gate had cleared. The honest framing of what happened here: we did not silently rewrite the artifact, but we did re-route the gate state from a verify-FAIL to a verify-PASS via targeted edits + re-run. Future workshop iterations should either (a) keep the defective verify-FAIL artifact and record the fix as a separate verify-PASS-after-fix-iter2 artifact (so both states are visible), or (b) usepipeline-state.sh halt 7b --reason "..."to log the FAIL state explicitly before applying edits.
Per the project’s feedback_preserve_ai_failure_cases rule, we did not silently rewrite the manuscript. We applied targeted edits for each CRIT, then re-ran verification. The fix-up pass added these lines to the verify report:
CRITs addressed:
- CRIT-1: Abstract / Methods / Results edited to "four waves (2014–2020),
27 pp → 19 pp" framing.
- CRIT-2: clarifying sentence added; rendered subtitle update deferred to R&R.
- CRIT-3: Results prose now describes Fig 3 as the M1 access-gap pp
trajectory; coefficient trajectory citations re-routed to Tables.
- CRIT-4: three contradicted claims replaced with descriptions matching
the rendered cell pattern.
- CRIT-5: Tables renumbered: 1=desc, 2=Y1, 3=Y2, 4=Oaxaca, 5=intersect.
- CRIT-6: H3 p re-extracted from H3-CORRECTED row; substantive verdict
(H3 NOT supported) preserved.
- CRIT-7: standardized on N=108,526.
The headline finding (Y1 convergence + Y2 persistence + Oaxaca coefficient-dominance) survived every CRIT. The corrections sharpened the manuscript rather than overturned it. That is what verification is for.
15.8 Where it gates
| Caller | Mode | Effect |
|---|---|---|
scholar-analyze | stage1 | Advisory |
scholar-write | stage2 | Conditional gate |
scholar-grant | stage2 | CRITICAL blocks |
scholar-respond (revise) | full | CRITICAL blocks |
scholar-journal | full | MAJOR ISSUES halts submission prep |
scholar-full-paper Phase 7b | full | MAJOR ISSUES halts the pipeline |
15.9 Statistical red flags it is trained to notice
Beyond mismatches, the skill flags patterns that are individually legal and collectively suspicious: coefficients that are suspiciously round (0.100, 0.200); identical coefficients across supposedly different models; an N that changes between models with no explanation; R² decreasing when predictors are added; every result significant; a confidence interval that exactly touches zero; standard errors that are implausibly small. None of these is proof of anything. All of them are worth one more look.
Stop and check. Pick one sentence from your own draft. Trace it: prose → table → script → sample → log entry. If any link is missing, you cannot publish that sentence.
16. scholar-citation — no citation by vibe
Goal: verify every reference, replace fabricated ones, and export a clean BibTeX file.
LLMs hallucinate citations. They are confident and specific. They invent author names, plausible journal volumes, and DOIs that resolve to unrelated papers. The citation skill exists because of this.
argument-hint: "[draft text or section] [journal or style: ASA|APA|Chicago|
Nature|NCS|numbered] [mode: insert|audit|convert-style|
full-rebuild|verify|export|materialize|retraction-check|
reporting-summary (default: insert)]"
16.1 Nine modes
| Mode | Produces |
|---|---|
| 1 insert | Citations inserted into uncited draft text; [SOURCE NEEDED] where nothing resolves |
| 2 audit | Orphan citations, ghost references, year/author mismatches, disambiguation needs, style errors |
| 3 convert-style | Reference list and in-text markers reformatted to a target style |
| 4 full-rebuild | The ten-step end-to-end pipeline: audit → claim inventory → library search → CrossRef → insert → assemble → verify → claim-verify → final audit → save |
| 5 verify | Per-entry field verification plus mandatory claim-faithfulness checking, plus three mechanical gates |
| 6 export | A .bib built from an existing reference list, with fields enriched from canonical sources |
| 6b materialize | A .bib rebuilt entirely from canonical sources, keyed only on in-text cites — the LLM-authored reference list is discarded |
| 7 retraction-check | Retracted papers found, with reason, impact tier, and replacement suggestions |
| 8 reporting-summary | A pre-filled NHB/NCS Reporting Summary plus a gap checklist |
> /scholar-citation verify drafts/manuscript-final-2026-05-04.md
> /scholar-citation materialize drafts/manuscript-final-2026-05-04.md --from-intext-cites
> /scholar-citation audit drafts/draft-methods-2026-05-01.md ASA
> /scholar-citation retraction-check drafts/manuscript-final-2026-05-04.md
16.2 The verification tier chain
Every mode that resolves a citation walks the same ladder, stopping at the first hit:
| Tier | Source | Note |
|---|---|---|
| 0 | Your scholar-knowledge graph | Fastest; no network call |
| 1 | Local library — Zotero, Mendeley, BibTeX, EndNote | Highest trust: you curated it |
| 2a | CrossRef | |
| 2b | Semantic Scholar | Preprints, working papers, conference papers CrossRef misses |
| 2c | OpenAlex | Broadest (250M+ works): grey literature, dissertations, non-DOI books |
| 2d | Google Scholar | Scraped, rate-limited, last-resort API tier |
| 3 | WebSearch | Genuine last resort; requires an authoritative landing page before acceptance |
This is why §8C (scholar-knowledge) pays off: a well-fed graph makes Tier 0 hit, and Tier 0 is free and instant.
16.3 materialize — the strongest anti-fabrication move
Mode 6 (export) trusts a reference list the model wrote and fills in missing fields. Mode 6b (materialize) throws that list away and rebuilds every entry from a canonical record, keyed only on the in-text (Author Year) cites it can find in your prose. It parses et al., ampersands, signal phrases, year-disambiguated 2020a/2020b, and grouped cites — then routes each through the tier chain.
If a cite cannot be resolved after every tier, it does not guess. It emits a [SOURCE NEEDED] placeholder entry and exits RED.
The governing discipline is seven rules, of which three matter most:
- D-3 — never synthesize a DOI. An invented DOI resolves to a real-but-wrong paper, which is worse than no DOI: it produces confusing downstream flags instead of an honest miss. Omit the field and let verification fall back to title + author + year.
- D-6 — never invent entries. If a claim cannot be tied to a real verified source, rewrite the prose or mark it
[SOURCE NEEDED]. - D-7 — construct from the source, never from memory. Copy the BetterBibTeX export verbatim, or format directly from the CrossRef/OpenAlex JSON. Transcribing from the model’s memory is the fabrication site.
Every entry carries a provenance note: note = {source: RefLib; zotero-key: ABCD1234}.
16.4 Three mechanical gates — and the two incidents that created them
Prompt instructions alone do not stop fabrication. Three scripts run after materialization and after verification, and a RED on any of them means the run is not complete:
| Gate | Catches |
|---|---|
verify-citation-metadata.sh | Field-level mismatches against CrossRef. Verdicts: REAL (green) / MISREMEMBERED (red — blocks the phase) / UNVERIFIABLE (yellow) |
verify-rendered-references-against-bib.sh | A rendered References entry with no .bib counterpart — a phantom citation |
verify-citation-local-library.sh | Bib entries that are not in your real reference library — the strongest fabrication signal, because a model cannot retroactively insert a record into your Zotero database |
Both of the first two exist because of documented failures in this corpus:
May 24, 2026. In one project, 13 of 43 bib entries (26%) shipped with hallucinated metadata — including the project author’s own paper, misattributed to a fabricated “Yuanting Zhang” when the real author is Yongjun Zhang. That incident created the metadata gate.
May 25, 2026 — the very next day. With the metadata gate in place, a regeneration step introduced six brand-new phantom citations with no
.bibcounterpart at all. None of the then-existing eleven citation gates caught them, because every one of them iterated the.bibforward and none reverse-mapped the rendered reference list back against it. That created the second gate.
The lesson generalizes well beyond citations: a checking system that only walks one direction will miss everything introduced in the other.
16.5 Claim-level checking (Step V-3.5)
Existence is the easy half. A citation can be perfectly real and still be cited for a claim the paper does not make. Step V-3.5 is mandatory in every verify and full-rebuild run: it extracts every prose claim that attributes a finding to a source, checks it against the knowledge graph and then the paper’s actual text, and flags:
[CLAIM-REVERSED] · [CLAIM-MISCHARACTERIZED] · [CLAIM-OVERCAUSAL] · [CLAIM-UNSUPPORTED] · [CLAIM-WRONG-POPULATION] · [CLAIM-IMPRECISE] · [CLAIM-NOT-CHECKABLE]
Newly discovered findings feed back into the knowledge graph, so the check gets cheaper each time you run it.
The expensive part of this check has always been “then the paper’s actual text” — reading a whole PDF to adjudicate one sentence. A scholar-rag index (§8F) collapses that step: rag_search("<claim>", doi="<doi>") retrieves the supporting passage with its page number without opening the paper. The tier order is knowledge graph (fast path) → scholar-rag full-text retrieval → PDF text. If you intend to run claim-level checking over a long manuscript, building the index first is the single highest-leverage setup step.
The evidence ledger short-circuits it further (v5.28.2). If the claim was anchored when it was written (§8A.6), the passage that justified it is already on disk in evidence/claim-anchors.ndjson — with its locator and its access_tier. The faithfulness layer reads the ledger before it goes looking, which turns “find the supporting sentence again” into “compare what we wrote against the quote we captured at the time.” Claims anchored at T4_none are exactly the ones this step cannot short-circuit, and they are the ones worth your attention.
16.6 Styles supported
ASA author-date (default; sociology and demography — all authors spelled out, no “et al.” in the reference list) · APA 7th · Chicago author-date · APSA (APSR/AJPS) · Unified Linguistics (Language in Society, Journal of Sociolinguistics) · Nature/Science/NCS numbered.
One formatting rule that bites people in Word: in every author-date style, each reference is a plain paragraph separated by a blank line — never a markdown bulleted list, which renders as bullet glyphs in the exported document.
16.7 What “no citation by vibe” looks like in practice
In a real audit of 26 AI-generated social-science papers (April 2026), even the highest-scoring paper had a reviewer flag a suspicious post-2023 reference. Of the unverified citations the skill flagged in our digital-divide run, two turned out to be fabricated when checked against CrossRef — a 2024 paper that didn’t exist, and a 2023 paper whose DOI led to an unrelated article. Both were removed from the manuscript.
The canonical closing sequence for any drafting skill is:
write the .md → /scholar-citation materialize → /scholar-citation verify → save
Write this rule on a post-it: No citation by vibe. Every citation must be verified, flagged, or removed.
17. scholar-polish — last, not first
Goal: improve flow, register, and authorial voice without changing claims, findings, or causal strength.
argument-hint: "[scan|rewrite|full] [file-path]"
> /scholar-polish scan drafts/manuscript-final-2026-05-04.md
> /scholar-polish full drafts/manuscript-final-2026-05-04.md moderate
| Mode | Behaviour |
|---|---|
| scan | Diagnoses only. Produces a Style Score (0–100), a tell-frequency table, the five worst paragraphs, and an intensity recommendation. Writes no changes |
| rewrite | Applies fixes at the chosen intensity and injects 2–4 human micro-patterns per page |
| full | scan, then rewrite |
Intensity: light (high-severity tells only) · moderate (default) · aggressive (everything). Style Score = 5 × HIGH + 2 × MEDIUM + 1 × LOW, capped at 100 — lower is better.
17.1 The tells — nineteen public, twenty-four extended
The public edition hunts nineteen named patterns, T1–T19. The extended edition adds five more, T20–T24, which exist because the extended pipeline generates machinery that can leak into prose — on the public edition there is no such machinery to leak.
Knowing them makes you a better writer even without the tool:
| Tell | Signature | |
|---|---|---|
| T1 | Hedging stacks | Three or more hedges in one sentence |
| T2 | Formulaic transition openers | “Moreover,” “Furthermore,” “Importantly,” “Notably,” “It is worth noting that” |
| T3 | Symmetrical parallelism | “Not only X but also Y”; identically shaped list items |
| T4 | The tricolon habit | Everything comes in threes |
| T5 | Anaphoric “This” | Consecutive sentences opening “This finding… This suggests… This approach…” |
| T6 | Over-enumeration | “There are several reasons: first… second… third…” |
| T7 | The definitional opening | A paragraph that begins by defining a term the reader knows |
| T8 | Empty metacommentary | “In this section, we examine…” |
| T9 | Uniform sentence length | Everything lands in the same 20–30 word band |
| T10 | Adjective inflation | “particularly important and highly significant” |
| T11 | Passive overcorrection | Active voice forced where Methods convention wants passive |
| T12 | Conclusion echo | The conclusion restates the introduction near-verbatim |
| T13 | Overused lexis | Tier A: delve, tapestry, realm, pivotal, meticulous, intricate, underscores, multifaceted. Tier B: crucial, foster, leverage, navigate, nuanced, robust, shed light on, cornerstone, holistic, transformative. Tier C: elucidate, illuminate, unravel, unveil, bolster, catalyze, resonate, pave the way |
| T14 | Performative depth | “This raises important questions about the very fabric of…” |
| T15 | Connective overload | “Therefore,” / “Thus,” / “However,” on every transition |
| T16 | Em-dash overuse | >2 per page MEDIUM, >4 per page HIGH — AI writes them at 3–5× human rate |
| T17 | Terminology inconsistency | The same phenomenon named differently across sections |
| T18 | Causal language in a non-causal design | “shapes,” “drives,” “the effect of X on Y” in cross-sectional data |
| T19 | Enumerated-Methods tell | Bulleted model ladders, bulleted robustness batteries, compliance-signaling headers |
| T20 ◆ | Pipeline-machinery leakage | L-A# IDs, spec_id= pseudo-citations, floating M#/R# |
| T21 ◆ | Section-tour-guide forecasts | Three or more “Section N does…” sentences |
| T22 ◆ | Tricolon as structure | “Three X follow” as a recurring paragraph opener |
| T23 ◆ | Numbered limitations | “First… Second… …Tenth,” in lockstep with L-A1–L-A10 |
| T24 ◆ | Abstract pseudo-citation density | (β = −0.025, p = 0.004; spec_id=M3) inside the abstract |
◆ = extended edition only.
Two of these are not stylistic preferences:
- T18 is a methodological correction. “Shapes” and “drives” in a cross-sectional design is a claim your data cannot license. The skill checks the Methods section first and skips T18 entirely if the design is causal. Reviewer 2 will flag it if you don’t.
- T20 is the largest real-world defect observed in this corpus — larger than T1–T19 combined. One May 2026 draft shipped 13
L-A#markers, 8spec_idpseudo-citations, and 12 floatingM#/R#references in a single manuscript. It is extended-only for a good reason: those markers are artifacts of the extended pipeline. If you work on the public edition you cannot hit T20, which is one concrete advantage of the simpler toolchain. - On the public edition, T19 carries the weight T20 does on the extended one. The skill calls the enumerated-Methods pattern the dominant prose-quality tell in AI-authored manuscripts, ahead of T1–T18 — bulleted model ladders and robustness batteries that seasoned reviewers read as machine output.
A documentation bug worth knowing. Both editions’ quality checklists still say “all 18 tell types (T1–T18) scanned,” but the public catalog runs to T19 and the extended one to T24. Following the checklist literally under-scans — by one category on public, by six on extended. Ask for the missing ones explicitly.
17.2 What polish must never do
Five absolute rules:
- Never alter citations, statistics, table references, or figure references.
- Never change the argument structure — claim → evidence → interpretation must survive.
- Never introduce or remove a claim. This is restyling, not rewriting.
- Preserve every
[CITATION NEEDED]marker and verification label. - Never manufacture hedging where the original was appropriately assertive. The goal is a distinctive voice, not false modesty.
17.3 The tooling rule — why this matters more than it sounds [Extended]
(This rule is written into the extended edition. It is not in the public SKILL.md — but the failure it prevents is identical on both, so apply it yourself either way.)
Fixes are applied with the Edit tool, one call per occurrence. Bulk sed -i, re.sub, or one-line regex passes over the manuscript are forbidden.
Why. On 2026-05-09, in a real production run, a single regex pass intended to fix em-dashes destroyed a structural sentence in the Results section, which then failed a downstream depth check. A regex does not know which em-dash is holding up an argument.
Expect 30–50 Edit calls for a 9,000-word manuscript with moderate em-dash overuse — roughly 3–5 minutes. The only exception is a pure one-to-one lexical swap (“delve into” → “examine”), which may use replace-all after a grep -n confirms every hit is body prose.
Then it injects 2–4 “tiny topos” per page — the micro-patterns that make prose sound human: a mid-sentence qualification, a concessive opening, a self-aware limitation, an aside about the data, a specific detail where a generic one would do, at most one rhetorical question per paper, a tonal break, a deliberately imperfect enumeration, a late-arriving caveat.
17.4 Diff before you accept
$ diff drafts/draft-manuscript-...md drafts/draft-manuscript-polished-...md | head -50
If the diff shows "X is associated with Y" becoming "X causes Y", reject the polish run and reduce its scope. Also confirm the word count stayed within ±5% and that no [CITATION NEEDED] marker vanished.
One operational note: when run inside the orchestrator, polish writes a new versioned manuscript file rather than overwriting its input. An earlier convention that overwrote the input silently dropped polished prose from final assembly.
Stop and check. Run scan on something you wrote without AI assistance. Most academic prose scores 20–40. If yours scores well above that, the tells are yours, not the model’s — which is genuinely useful to know.
18. scholar-respond + scholar-journal — before submission
Goal: simulate reviewers, check journal fit, prepare the cover letter and submission package — and, when the real reviews arrive, answer them.
18.1 scholar-respond — five modes
argument-hint: "[simulate|respond|revise|resubmit|cover-letter]
[paper file or reviewer comments] [journal] [round:R1|R2|R3]"
| Mode | Trigger | What it does | When |
|---|---|---|---|
| simulate | simulate, mock review | Journal-calibrated reviewer panel, severity matrix, revision roadmap. Advisory only — never auto-rewrites | Before submission |
| respond | respond, response letter, point-by-point | Triage dashboard + full response letter + changes summary table | Real reviews arrived |
| revise | revise, edit manuscript | Executes the edits via /scholar-write revise, item by item, with diffs | After the letter is planned |
| resubmit | resubmit, rejection, desk reject | Rejection triage → root cause → journal-ladder retargeting → reframed intro → cover letter | After a rejection |
| cover-letter | cover letter | Standalone R1 / R2 / minor-revision / new-journal cover letter | Cover letter only |
> /scholar-respond simulate drafts/manuscript-final-2026-05-04.md "Social Forces"
> /scholar-respond respond reviewer-comments.txt JMF round:R1
> /scholar-respond revise round:R2
> /scholar-respond resubmit
18.1.1 How the panel is chosen — and why it matters
scholar-respond simulate dispatches three to five reviewer agents drawn from the full inventory: peer-reviewer-quant, peer-reviewer-theory, peer-reviewer-senior, peer-reviewer-r2-skeptic, peer-reviewer-demographics, peer-reviewer-qual, peer-reviewer-mixed-methods, peer-reviewer-computational, peer-reviewer-ling, peer-reviewer-ethics.
The composition is journal-aware, not generic. A lookup table maps nine journal classes — JMF/JFI/JFTR · ASR/AJS/Social Forces · Demography/PDR/Population Studies · Science Advances/NHB/PNAS · NCS/EPJ Data Science · Language in Society/Journal of Sociolinguistics · Qualitative Sociology/Ethnography · Sociological Methods & Research · APSR/AJPS — to the four profiles that should fill R1–R4, plus a fifth slot that is always the skeptic (or the computational reviewer for computational papers).
Why journal-aware selection is mandatory rather than optional. A JMF simulation run with the generic ASR-style panel missed the union-vs-marriage primacy issue, the gender-asymmetry issue, and the family-process framing issue — all three of which a real JMF reviewer would raise first. The panel you convene determines the blind spots you keep.
Two mechanisms guard against fake consensus:
peer-reviewer-r2-skepticis always present. It reads the packet without prior-round RESOLVED stamps, amendment logs, or response letters — because a reviewer who saw the R1 issues will tend to re-validate a packet that carries those same issues marked resolved.- Theme rotation. Each reviewer gets at most one priming theme, no theme is reused, and the senior reviewer is always unprimed. Priming themes are drawn from four independent sources (Phase 7b warnings, design pre-mortem red-team flags, prior-round unresolved items, lit-review gaps). Without this, several “independent” reviewers converge because they were all pointed at the same thing.
Output is a Severity × Confidence matrix — every issue cross-tabulated as CRITICAL/MAJOR/MINOR against HIGH (two or more reviewers) / MEDIUM / LOW — feeding a four-phase revision roadmap, plus a “strengths to preserve” list and an effort estimate.
Note: simulated reviewers do not replace real reviewers. Use them to prepare better questions for the real ones.
18.1.2 Responding to real reviews
respond mode categorizes every comment into one of eight buckets — [CRITICAL], [MAJOR-FEASIBLE], [MAJOR-INFEASIBLE], [MINOR-SUBSTANTIVE], [MINOR-EASY], [DISAGREE], [CONFLICT] (reviewers contradict each other), [NEW-IN-R2+] — and produces a two-pane triage dashboard: Pane A is the six-row, thirty-minute author view; Pane B is everything.
It also emits reports/resolution-state-<slug>-<date>.yaml, the machine-readable gate record. Three rules govern it: no auto-promoted tag may remain active; every issue at severity 2 or above needs a status (RESOLVED / ADDRESSED / DEFERRED / PENDING-USER / NOT-APPLICABLE); and the tags title-overclaim, desk-reject-risk, and data-fabrication must be RESOLVED before the pipeline advances.
The letter itself comes with a phrase bank by situation (full agreement, partial agreement, respectful disagreement, infeasible request, misunderstanding, cross-reviewer overlap), a tone-calibration guide with too-defensive / too-deferential / just-right examples, and tracked-change markers ([ADDED: R2.3], [REVISED: R1.7], [DELETED], [MOVED], [CONSIST.]).
18.1.3 The New-Analysis Gate
This is the rule that keeps an R&R honest. If a reviewer asks for a new analysis, you may not simply report a number the agent produced in conversation. The re-analysis must:
- Live in a script under
scripts/rr-NN-*.R; - Pass
scholar-code-review; - Emit
rr-results-registry.csvandrr-adjudication-log.csv; - Trigger a re-lock if a results lock exists.
Then the response letter cites the number by disk location — [rr-results-registry.csv row=4 model_id=M3b] — never as a paraphrase of what an agent said. verify-numerics enforces this.
Before finalizing, revise mode runs scholar-verify full and requires zero CRITICAL issues to proceed.
The R2+ scope rule. No new analyses, citations, or arguments beyond what the reviewers actually asked for. The skill names unrequested scope creep as the #1 cause of R3 rejection. Round 3 revisions should be surgical.
18.2 scholar-journal — six modes
argument-hint: "[journal name] [paper type: article/research-note/letter/
brief-report] — optionally: mode [FULL-PACKAGE/FORMAT-CHECK/
COVER-LETTER/SELECT-JOURNAL/RESUBMIT-PACKAGE]"
| Mode | Trigger | Produces |
|---|---|---|
| SELECT-JOURNAL | select, which journal, or no journal named | Ranked fit list |
| JOURNAL-BRIEF | brief, pre-draft | A pre-draft compliance brief — hard ceilings, section order, abstract template, forbidden patterns, canon authors |
| FULL-PACKAGE | a journal named, or full/prepare | Everything: audit, requirements, open-science package, cover letter, checklist |
| FORMAT-CHECK | format, check, audit | Compliance audit only |
| COVER-LETTER | cover letter | Cover letter only |
| RESUBMIT-PACKAGE | resubmit, R&R | Re-targeted package for a new venue |
> /scholar-journal "Social Forces" article
> /scholar-journal # → SELECT-JOURNAL
> /scholar-journal Demography format-check
> /scholar-journal NHB brief # pre-draft profile
Journal selection scores eight dimensions 1–5: scope fit, methods fit, theory fit, word-count fit, prestige target, open-science readiness, turnaround priority, audience breadth. It is cross-checked against a quick-selection guide and against journal ladders — pre-mapped rejection-routing chains per subfield, so “rejected from ASR” has an answer that is not improvised.
18.2.1 The journal profiles
The skill ships 24 machine-readable profiles at references/profiles/*.json: ajs, annual-review-sociology, apsr, asr, demography, du-bois-review, gender-society, jmf, journal-of-sociolinguistics, language-in-society, mobilization, nature, nature-computational-science, nature-human-behaviour, pdr, plos-sociology, pnas, poetics, science-advances, smr, social-forces, social-problems, social-science-and-medicine, sociological-theory, plus an explicit default.
Each profile carries house_style, citation_style, total_word_budget, section_order, per-section min_words/max_words/structural_moves/anchor_artifacts, a four-part Methods subsection structure (4.1 Data / 4.2 Analytic Sample / 4.3 Measures / 4.4 Analytic Strategy), canon_authors with a citation threshold, forbidden_patterns, and display_architecture.
A slice of the narrative metadata behind those profiles:
| Journal | Word limit | Abstract | Blind | Style | Turnaround | Accept |
|---|---|---|---|---|---|---|
| ASR | ~12,000 | 150–200 unstructured | Double | ASA | 3–6 mo | ~5–6% |
| AJS | 8–15k typical | 150 unstructured | Double | Chicago AD | 3–6 mo | ~5–8% |
| Demography | ~10,000 | ~150, 4–6 kw | Double | ASA | 3–5 mo | ~10–15% |
| Social Forces | 10,000–12,000 | 150, 4–6 kw | Double | ASA | 3–5 mo | ~10–12% |
| Science Advances | 4,000–6,000 + ≤250-char teaser | ~250 | Single (~50% desk-reject) | Numbered | 6–10 wk | ~15% of submitted |
| Nature Human Behaviour | Articles 3–5k | ≤150, 3-sentence structured | Double | Numbered superscript | 6–12 wk | ~5% |
| Nature Comp. Science | Articles 3–5k | ≤150 structured | Double | Numbered | 8–12 wk | <10% |
| JMF | 8,000 | 200, 3–5 kw | Double | APA 7th | 3–6 mo | ~15–20% |
| Language in Society | 8,000–10,000 | 150, 6–10 kw | Double | APA 7th | 3–6 mo | ~15–20% |
| APSR | ~12,000 | 150 unstructured | Double | APSA AD | 3–6 mo | ~7–8% |
| PNAS | ~3,500 + 125-word significance statement | ≤250 | Single | Numbered superscript | 4–8 wk | ~10–15% |
| SMR | 10,000–15,000 | 200, 5–7 kw | Double | ASA | 3–6 mo | ~15–20% |
The regression this guards against. If you name a journal that has no profile, Step 1.5 scaffolds one from the closest template and refines it by web search. Before that step existed, naming a journal without a profile silently produced a generic six-section blueprint instead of the journal’s real structure — a run documented in May 2026 where “Social Forces was specified but DEFAULT was used.” When a profile genuinely cannot be resolved, the skill falls back to the ASR profile explicitly and records the fallback, rather than inventing a generic shape.
18.2.2 The submission checklist and its gates
The universal checklist: anonymous manuscript · word count · line numbers · double spacing · 12pt · abstract format · keywords · citation consistency · complete reference list · editable-text tables (not images) · 300+ DPI figures · figure and table counts · CRediT statement · data and code availability · conflict of interest · funding and acknowledgments · IRB. Journal-specific items layer on top, including the full Nature Reporting Summary template for the Nature family.
Two hard gates:
- Step 6b invokes
scholar-citation(audit + style conversion) and thenscholar-verify full. MAJOR ISSUES halts submission prep. - Step 7.0 is a blind-review prose scrub. RED (identifying disclosures present) exits with an error; for genuinely single-blind venues (Nature family, Science Advances, PNAS, PDR, SMR) it downgrades to YELLOW.
Author identity is handled through canonical placeholder tokens — [AUTHOR_NAME], [AUTHOR_AFFIL], [AUTHOR_EMAIL], [AUTHOR_ORCID], [IRB_PROTOCOL], [FUNDING_SOURCE] and friends — substituted in one shot at the very end by substitute-author-placeholders.sh, which refuses to write any unrecognized bracket token. Under a lock, the submission package sources tables and figures from results-locked/, never from live output/tables/.
18A. scholar-ethics — the disclosure you will be asked for
Goal: produce the actual disclosure text journals now require, plus an honest self-audit of AI use, originality, and research integrity.
This skill is easy to skip and increasingly not optional: every major journal family now asks what AI tools touched the manuscript and what data they saw. It writes text you can paste, not warnings you can nod at.
argument-hint: "[ai-audit|plagiarism|integrity|general|full]
[manuscript or data file path]
[optional: journal target, tool list, concern description]"
| Mode | Produces |
|---|---|
| ai-audit | AI tool inventory table; privacy-framework compliance check (IRB / GDPR / HIPAA / DUA / institutional); risk rating; the journal AI-use disclosure paragraph |
| plagiarism | Section-by-section originality review; self-plagiarism decision tree; AI-generated-text classification; similarity-score interpretation; originality statement |
| integrity | QRP screening (Wicherts et al. 2016, categories A/B/C); p-hacking diagnostic with runnable multiverse and specr code; fabrication cross-check protocol; misinterpretation audit; self-certification |
| general | IRB determination; the eight consent elements; CRediT table; COI disclosure; data-availability statement; per-journal ethics checklist |
| full | All four, in order |
> /scholar-ethics ai-audit "Claude Code, Codex CLI" "Social Forces"
> /scholar-ethics integrity tables/results-registry.csv
> /scholar-ethics full drafts/manuscript-final-2026-05-04.md Demography
18A.1 The disclosure text it writes
The AI-use declaration, ready to adapt:
“The authors used [Tool Name] ([Provider], [Year]) for [task]. No personally identifiable participant data were processed by AI tools. All substantive intellectual contributions — research design, interpretation, and conclusions — were made by the authors. All AI-assisted content was reviewed and verified by the authors prior to inclusion.”
For our CFPS project the honest version of that first sentence names Claude Code and Codex CLI, names the tasks (script generation, table formatting, prose drafting, verification), and — critically — can truthfully say no participant-level data was processed by a cloud model, because LOCAL_MODE was enforced from §6 onward. The safety discipline in Part II §6 is what makes this sentence true rather than aspirational.
It also generates the IRB statement, the CRediT contribution statement across the fourteen roles, COI text (both the “no competing interests” and the disclosed-financial-interest variants), and four variants of the data-availability statement (fully public / replication package / restricted with access instructions / a mix).
18A.2 The integrity audit is a self-check, not an accusation
The skill says this explicitly and repeatedly. Mode 3 screens for the documented QRP taxonomy — optional stopping, selective exclusion, post-hoc design change, undisclosed attrition, specification searching, covariate fishing, outcome switching, transformation p-hacking, subgroup fishing, outlier manipulation, HARKing, selective reporting, misleading significance language — and supplies p-curve, z-curve, and GRIM-test code so you can check yourself before someone else does.
Two things it flags as red flags rather than virtues, which surprises people: perfect inter-rater reliability (κ = 1.0) and zero missing values in a survey. Real data is messier than that.
18A.3 The verdict file and the Phase 9b gate
Alongside the human-readable report, the skill writes a machine-readable verdict:
{
"overall_status": "CLEAR", // CLEAR | MINOR | CRITICAL | UNRESOLVED
"critical_count": 0,
"minor_count": 2,
"unresolved_blockers": [],
"dimensions": {
"irb": "...", "consent": "...", "vulnerable_populations": "...",
"data_handling": "...", "ai_transparency": "...",
"positionality": "...", "coi": "..."
}
}
ethics-verdict-check.sh reads this at orchestrator Phase 9b. A status of CRITICAL, UNRESOLVED, or UNKNOWN — or any non-empty unresolved_blockers — REDs the phase and blocks Phase 10. The skill is explicitly forbidden from inventing a clean verdict: the JSON must reflect the same flags recorded in the human report.
Files land at <proj>/ethics/scholar-ethics-log-*.md (the per-item audit trail), <proj>/ethics/scholar-ethics-report-*.md (the report, ending in “Declarations ready to paste into submission”), and <proj>/ethics/ethics-verdict.json.
Stop and check. Run /scholar-ethics ai-audit on this workshop’s own project. Read the generated disclosure paragraph and ask: is every sentence in it true of what you actually did today? If one is not, that is the sentence to fix — in your practice, not in the paragraph.
19. scholar-replication + scholar-open — reproducibility is a habit, not a deadline
Goal: assemble a package someone else can actually run, and prepare the open-science statements journals now require.
The division of labour: scholar-open writes declarations, templates, and checklists. scholar-replication builds the directory on disk, copies and renumbers the scripts, generates the docs, runs the clean-run test, and audits paper-to-code correspondence.
19.1 scholar-replication — six modes
argument-hint: "[BUILD|DOCUMENT|TEST|VERIFY|ARCHIVE|FULL]
[project description or journal name]"
| Mode | What it does |
|---|---|
| BUILD | Assembles replication-package/ on disk: copies and renumbers scripts, copies tables/figures/EDA output/registries, applies the data-handling decision tree, captures the environment, generates run-all.sh, LICENSE, CITATION.cff, Makefile, and (conditionally) a Dockerfile |
| DOCUMENT | Generates the nine-section AEA README, the codebook, COMPUTATIONAL-REQUIREMENTS.md, the dependency graph, and check_inputs.R |
| TEST | Six pre-flight checks, then a clean-environment run in an isolated copy, then output comparison against tolerances → TEST-REPORT.md |
| VERIFY | Paper-to-code correspondence audit: every table, figure, and in-text statistic mapped to a producing script → VERIFICATION-REPORT.md |
| ARCHIVE | Cleanup, .gitignore, size check, repository selection, git init/commit/tag, deposit metadata, post-deposit checklist |
| FULL | All five in sequence — mandatory when dispatched from the orchestrator’s Phase 12 |
> /scholar-replication BUILD
> /scholar-replication test
> /scholar-replication verify Demography
> /scholar-replication full "Social Forces"
19.2 What BUILD produces
replication-package/
├── README.md ← 9-section AEA template
├── LICENSE ← dual: MIT (code) + CC-BY-4.0 (data/docs)
├── CITATION.cff
├── DECISIONS.md ← from your coding-decisions log
├── Makefile
├── renv.lock / environment.yml
├── .Rprofile
├── Dockerfile ← only for NCS targets, computational methods, or on request
├── scripts/run-all.sh ← the single entry point
├── data/{raw,processed,codebook}/
├── code/00_master.R · 01_clean.R · 02_construct.R · 03_analysis.R
│ 04_robustness.R · 05_figures.R · utils/
├── output/{tables,figures,models}/ · eda/ · artifact-registry.md
└── paper/
Two of those are mandatory, and both exist because of a documented failure:
- A working
renv.lock/environment.yml. AEA and JMF open-materials reviewers reject prose install instructions. An earlier version of this skill ranrenv::init()inside the package before the scripts had been copied there, producing a near-empty lockfile — and the error was hidden by a2>/dev/null. The skill now sanity-checks that the lockfile actually contains packages and fails loudly if not. scripts/run-all.sh. One shell entry point. It restores the environment, discoverscode/*.{R,py,do,jl}, and runs each script in order — exiting with code 3 (RUNNER MISSING) if an interpreter is not on PATH, rather than silently skipping a language. It is written in Bash-3.2-safe style (nomapfile) because macOS still ships Bash 3.2.
A third detail worth copying into your own practice: BUILD is lock-aware. When results-locked/LATEST.txt exists, it copies tables and figures from the lock rather than from the live output directory, so the package matches what the manuscript was actually drafted against.
The README’s §4a carries a SHA-256 integrity check in pure R (no second runtime required) that walks the lock manifest and prints OK=N DRIFT=0 TOTAL=N, exiting non-zero on any mismatch — CI-suitable, and the fastest way for a replicator to know whether they got what you shipped.
19.3 TEST — the five levels of “it reproduces”
The skill defines an explicit ladder, and each journal has a floor:
| Level | What it means |
|---|---|
| 1 | It runs on your machine |
| 2 | The environment is documented |
| 3 | It runs in a fresh environment on your machine — the minimum for submission |
| 4 | Someone else runs it successfully |
| 5 | It runs in Docker or a VM from scratch |
| Journal | Minimum | Recommended |
|---|---|---|
| ASR / AJS / Demography | Level 2 | Level 3 |
| Science Advances / NHB | Level 3 | Level 4 |
| APSR / AJPS | Level 3 | Level 4 |
| Nature Computational Science | Level 4 | Level 5 (Docker) |
| AEA journals | Level 4 (external verification is mandatory) | Level 5 |
Numerical reproducibility tolerances, so “it reproduced” has a definition: coefficients ±0.001 · SEs ±0.002 · p-values ±0.005 · CIs ±0.005 · bootstrap ±0.05 · MCMC ±0.01 · figures visual match.
The six pre-flight checks run before any of that: every backtick path in the README exists; all scripts parse; no absolute paths (abs-path-scan.sh, where RED blocks ARCHIVE); script headers present; every random draw paired with a set.seed; README has all nine sections.
19.4 VERIFY — does every claim have a producing script?
VERIFY extracts every Table, Figure, and in-text statistic reference from the manuscript — coefficients, N, p-values, percentages, confidence intervals — and maps each to the script that produced it, marking each MAPPED / PARTIAL / UNMAPPED / SUPPLEMENT. It distinguishes two failure directions: ORPHAN (a file exists but nothing references it) and MISSING (something is referenced but no file exists). The completeness score is N/M; the quality bar is ≥80% of in-text statistics traceable.
19.5 ARCHIVE — where to deposit
| Journal | Recommended | Alternative |
|---|---|---|
| ASR, AJS | AJS Dataverse / Zenodo | Harvard Dataverse |
| Demography | Zenodo / Harvard Dataverse | ICPSR |
| Science Advances | Zenodo + Code Ocean | Dryad |
| NHB | Zenodo | figshare |
| Nature Computational Science | Zenodo + Code Ocean | GitHub + Zenodo |
| APSR | Harvard Dataverse | ICPSR |
| AJPS | AJPS Dataverse | Harvard Dataverse |
| AEA journals | openICPSR | — |
Size limits to plan around: GitHub 100 MB per file · Zenodo 50 GB · Dataverse 2.5 GB per file · ICPSR 30 GB.
The DOI flow is: git tag v1.0.0 → push to GitHub → enable the Zenodo GitHub webhook → create a GitHub release, which mints the DOI → add the DOI badge to the README.
19.6 Restricted data — what our CFPS package actually shares
CFPS microdata cannot be redistributed, which is the common case in this field. The decision tree routes restricted data to access instructions plus synthetic data (fabricatr or synthpop), never to a silent bundling. Our package therefore contains:
- All scripts in execution order, driven by
run-all.shand the R controller00_master.R. - An
environment.yml/renv.locklockfile. - A README following the AEA template.
- A
data-availability.mdexplaining what is shared and what is not — derived tables, code, mock data, and instructions for obtaining CFPS access. - Expected outputs hashed with SHA-256 so anyone re-running can confirm bit-identity of the locked tables.
If you wait until submission week to do this, reproducibility becomes archaeology.
19.7 scholar-open — five modes of declaration
argument-hint: "[PREREGISTER|DATA-SHARE|CODE-SHARE|FULL-PACKAGE|
REPLICATION-PACKAGE] [study description or journal name]"
| Mode | Produces |
|---|---|
| PREREGISTER | Preregistration document; Registered Report Stage 1/2 structure; OSF workflow; secondary-data preregistration language; deviation-reporting template |
| DATA-SHARE | FAIR checklist; sensitivity decision tree; repository guide; de-identification (k-anonymity k=5 via sdcMicro); platform-policy handling; data-availability statements |
| CODE-SHARE | Minimum vs. gold-standard package structure; README; renv/conda/Docker; CITATION.cff; the Zenodo-via-GitHub DOI flow |
| FULL-PACKAGE | Data management plan (NSF SBE six-section / NIH DMSP ≤2 pages); CRediT 14-role table; COI; IRB statements; open-access and APC strategy |
| REPLICATION-PACKAGE | An audit checklist for an existing package |
> /scholar-open PREREGISTER survey experiment on political trust, target Science Advances
> /scholar-open DATA-SHARE secondary analysis of CFPS data for Social Forces
> /scholar-open FULL-PACKAGE DMP for an NSF-funded study
Preregistration registries it supports: OSF Preregistrations (the full template — Study Information, Design Plan, Sampling Plan, Variables, Analysis Plan, Software and Versions, Other), AsPredicted’s nine questions, EGAP, the AEA RCT Registry, and OSF Registered Reports.
Two rules worth stating plainly, because they trip people:
- An OSF registration, once locked, cannot be modified. Embargo up to four years is available; changes afterwards exist only as disclosed deviations. That is the point of the mechanism.
- Every deviation must be disclosed, using the skill’s template. A preregistration you quietly departed from is worse than none.
The data-availability statement templates cover the situations you will actually face: fully open · restricted via DUA · public secondary data with an archived derived dataset · qualitative data that cannot be shared · social-media data whose ToS forbids redistribution (share IDs only). The last is not hypothetical: Twitter/X, Reddit, Meta, TikTok, and LinkedIn all forbid redistributing raw content, and both Pushshift (2023) and CrowdTangle (August 2024) have shut down since these workflows were designed.
Preprint servers covered: SocArXiv, SSRN, arXiv (cs.SI, cs.CY, stat.AP), PsyArXiv, medRxiv. ASR, AJS, and Demography permit preprints at any stage; NHB and NCS permit them before or after review; Science Advances permits them with a post-publication DOI update.
Stop and check. Delete your renv/ directory, run bash scripts/run-all.sh, and see what happens. That is Level 3, and it is the lowest bar any journal will accept.
20. scholar-presentation — talks and print posters [Extended]
Once the paper is verified, the same skill suite produces downstream artifacts. The general rule for all of them: every downstream product must trace back to a locked result, a verified citation, or an accepted limitation. Presentation is claim selection under time pressure, not decoration.
20.1 Eight modes, including print posters
argument-hint: "[talk-type: conference|job-talk|colloquium|dissertation|
guest-lecture|poster-lightning|workshop|conference-poster]
[topic or paper] [time in minutes, or poster dims like 48x36]
[audience level] [optional: target journal]
[output: slides-only|pptx|pptx+pdf]"
| Mode | Length | Shape |
|---|---|---|
| 1 Conference talk | 10–20 min | One contribution, fast — 8–18 slides |
| 2 Job talk | 45–60 min | Research identity + design defense + agenda — 28–45 slides |
| 3 Colloquium | 40–60 min | Mixed-audience framing |
| 4 Dissertation talk | 45–75 min | Chapter coherence around one anchor chapter |
| 5 Guest lecture | 30–75 min | Teaching plus a live research example |
| 6 Poster lightning | 3–5 min | Max 5 slides, one figure, hook and call to action |
| 7 Workshop | 60–120 min | Hands-on, with exercise breaks budgeted at 1.5× |
| 8 Conference poster | one page | Print poster — Parser → Planner → Renderer |
| R Revise | — | Read an existing deck, diagnose, fix |
> /scholar-presentation conference talk on "Access convergence, use divergence",
15 minutes, mixed audience, pptx
> /scholar-presentation job-talk on digital inequality, 55 minutes, pptx+pdf
> /scholar-presentation conference-poster from drafts/manuscript-final.md,
48x36 landscape, 3 columns, pptx+pdf
A bare poster is ambiguous between mode 6 and mode 8, and the skill will ask rather than guess.
Slide budget is computed, not eyeballed: slides = floor(minutes × slides_per_minute) − buffer. And there is one content rule that improves decks more than any other single change:
Content-slide titles must be complete claim sentences, ≤70 characters — not topic labels. “Rural–urban use gap persists as access converges” beats “Results.”
20.1.1 Generation, and the two gates
Slides are produced by a pre-built module, not by generated code: a JSON manifest goes in, a PPTX comes out.
$ python3 references/pptx_layouts.py slides.json out.pptx
$ python3 references/pptx_layouts.py poster.json poster.pptx # type: "poster"
The module ships 45 slide layouts — title, TOC, content-bullets, content-figure, two-column, section-divider, card-grid, highlight-rows, code-block, closing-summary, executive-summary, backup, process-flow, funnel, matrix, timeline, comparison-table, stat-callout, waterfall, pillar, split-comparison, pyramid, hub-spoke, concentric, cycle, venn, swim-lane, quote, status-matrix, staircase, decision-tree, three-panel, annotated-figure, SWOT, pros-cons, data-callout, roadmap, risk-matrix, equation, thank-you, agenda, icon-text-list, horizontal-bar, donut, assumption-check. If python-pptx is unavailable, it falls back to pandoc.
Two gates keep the output usable:
- The content-fit gate. Every slide type has hard limits (
max_bullets,max_body_words,max_chars,max_title_chars,max_caption_words). Overflow is fixed in a fixed order — tighten language, auto-split into “(1/2)”/”(2/2)”, break long lines, shorten captions, shorten titles — and if it still overflows, the pipeline stops. A slide nobody can read is not a deliverable. - The PDF gate. After conversion, the file must exist, be non-empty, and start with a
%PDFheader. The skill fails loudly rather than reporting success on a zero-byte file.
For posters (mode 8) there is a third: a VLM render-and-critique loop. The poster is rendered to PNG at 150 DPI, the model reads the image back, applies a ten-criterion critique, fixes the top three high-severity problems in poster.json, and re-renders — up to three iterations, with each iteration snapshotted to vlm-preview/iter-N/. Poster defaults: 48×36 inches, three columns, Georgia Bold 72–96pt title, Arial 22–28pt body with a 16pt hard floor, ≤60 words per section, ≤600 words total.
Box-style PPTX layouts (per user preference): the layout uses bordered boxes around content blocks rather than horizontal divider lines, which presents better on conference projectors.
Outputs land in output/presentation/: the full plan, the slide plan, speaker notes, the PPTX, the PDF, and the JSON manifest — the manifest being the thing to keep, since it regenerates everything else.
20A. scholar-image — decorative figures only, and a hard refusal [Extended]
argument-hint: "[generate|prompt|preview|list-venues] [venue] [freeform intent]"
Four modes: generate (compose prompt, save it, produce the image), prompt (save the prompt JSON only), preview (compose and print, save nothing), list-venues.
Seven venue profiles: neurips (NeurIPS/ICML/ICLR), acl (ACL/EMNLP/NAACL), chi (CHI/UIST/CSCW), nature (Nature family incl. NHB, NCS, Science Advances), generic-poster, generic-slide, generic-figure-panel — each with style directives, a palette, and the invariant typography policy: no rendered text inside the image; labels are overlaid externally.
Generation goes through the Codex CLI (codex exec, using your ChatGPT session — no API key), with an OpenAI SDK fallback (gpt-image-2, needs OPENAI_API_KEY). Every run saves a prompt JSON to output/images/prompts/ — the reproducibility receipt.
What it refuses, and where it sends you instead. A scope gate runs before any prompt is composed:
| You asked for | Routed to |
|---|---|
| A DAG or causal diagram | /scholar-conceptual diagram dag or /scholar-causal |
| Results, effect sizes, coefficients | /scholar-analyze |
| Bar chart, scatter, boxplot, forest plot, heatmap, histogram | /scholar-analyze |
| Architecture or labeled model diagram | /scholar-conceptual (TikZ) |
| Flowchart or methodology diagram | /scholar-conceptual (Mermaid) |
| Confusion matrix, attention map, saliency map | /scholar-compute |
| A typeset equation | LaTeX in the document |
| A UI mockup | Figma or a screenshot |
There is also a global negative-prompt floor that cannot be removed: no rendered text, no fake data, no hallucinated numerical values, no fake axis labels, no fabricated plots, no logos. This skill will make you a nice poster header. It will not make you evidence.
20B. scholar-grant — from pilot to proposal [Extended]
argument-hint: "[nsf|nih|rsf|spencer|aims|budget|data-plan|review|compare|
resubmit|biosketch|letters] [research topic or file]"
> /scholar-grant nsf digital divide and aging in China using CFPS pilot findings
> /scholar-grant aims computational text analysis of policy discourse
> /scholar-grant review drafts/proposal-draft.md
> /scholar-grant resubmit nih-a0-reviewer-comments.pdf
The full pipeline is deep — it invokes scholar-idea for the research question, scholar-lit-review-hypothesis for the literature, scholar-design plus scholar-causal for the design, optionally scholar-compute or scholar-ling, then drafts, then reviews.
What it produces per funder:
| Funder | Core document | Structure |
|---|---|---|
| NSF | 15-page Project Description | Problem & Significance (2–3 pp) → Theory & Hypotheses (2–3) → Data & Methods (4–5) → Preliminary Evidence (1–2) → Feasibility & Timeline (1) → Broader Impacts (1–2). Plus the 1-page 3-paragraph Project Summary, SciENcv biosketch, budget, facilities, ≤2-page DMP |
| NIH | 12-page Research Strategy (R01) | Significance (2–3) → Innovation (1–2) → Approach, per aim (3–4 × 3 aims) → Timeline → Rigor & Reproducibility. Plus the 1-page Specific Aims, human-subjects section, 5-page SciENcv biosketch |
| RSF | 8–15 pages | Problem → Literature & Theory → RQs & Hypotheses → Data & Methods → Feasibility → Products & Dissemination (policy-facing required) |
| Spencer | 5–25 pages | Education Problem → Prior Evidence & Framework → RQs & Design → Research-Practice Relevance → Feasibility → Expected Outputs |
Three mechanisms are worth borrowing even if you never write a grant:
- The framing panel. Three agents draft competing framings of the same project — theory-forward, methods-innovation, impact-forward — and you pick. Most proposals are written in whichever framing occurred to the author first.
- The mock panel. Five personality-calibrated reviewers (methods-skeptical, compliance-perfectionist, significance-constructive, approach-skeptical, program-fit-pragmatic) score against real funder criteria — NSF’s Intellectual Merit / Broader Impacts on the E/VG/G/F/P scale, NIH’s five criteria on 1–9 plus Overall Impact.
- The prior-awards search. Shipped scripts search actual funded awards, so “does this look like something they fund?” has an evidence-based answer:
$ bash assets/find_nsf_sbe_awards.sh "digital divide aging" 20
$ bash assets/find_nih_awards.sh "social determinants mortality" 20
$ bash assets/find_rsf_grants.sh "immigration labor market" 20
$ bash assets/find_spencer_grants.sh "education inequality" 20
Gates: a budget cannot be drafted before the aims are final; a pre-panel gate blocks any remaining [CLAIM-*] or [CITATION NEEDED] markers; and a scholar-code-review pass with zero CRITICAL issues is required if the proposal carries analysis scripts.
20C. scholar-teach — syllabus-first course materials [Extended]
Goal: turn your research into teaching materials that are actually aligned to a course, not free-floating handouts.
argument-hint: "[syllabus|lecture|discussion|assignment|exam|reading-list|
slides|rubric|adapt] [topic or paper]
[optional: level, course, weeks]"
The architecture is syllabus-first: the syllabus is the persistent scaffold every other artifact is generated against. Run any other workflow without one and the skill warns you and offers to proceed standalone.
| Workflow | Produces |
|---|---|
syllabus | Full course syllabus via a four-agent design panel |
lecture | Lecture notes for one session (50- or 75-minute structures) |
discussion | 8–12 scaffolded prompts, small-group activities, Socratic chains, devil’s-advocate prompts |
assignment | Prompt + rubric + peer-review worksheet |
exam | Questions by type + answer key + a tagged question bank |
reading-list | Annotated list, verified through the full citation tier chain |
slides | Slide-by-slide outline plus a fill-in-the-blank handout |
rubric | Analytic, holistic, or single-point rubric with calibration notes |
adapt | A published paper → lecture summary, discussion questions, glossary, methods explainer, policy implications |
> /scholar-teach syllabus social stratification and inequality level=intermediate weeks=15
> /scholar-teach lecture residential segregation week=5 format=75min
> /scholar-teach adapt output/papers/digital-divide-china-cfps.pdf
The multi-agent panels here are blocking by design: the syllabus workflow’s four agents (curriculum architect using backward design, disciplinary expert, student-centered/UDL, DEI/critical pedagogy) present competing designs in a comparison table and wait for you to choose. Same for the three-agent assignment panel and the three-agent exam review panel (content validity, psychometric, accessibility/fairness). This is the right shape for teaching: the pedagogical choice is yours, and the agents’ job is to make the alternatives visible.
Every reading is tagged [VERIFIED-LOCAL], [VERIFIED-CROSSREF], [VERIFIED-WEB], or [UNVERIFIED], and lecture content citing specific findings passes a claim-faithfulness gate. A syllabus with a hallucinated reading is a bad first day.
Note that lecture and slides produce outlines; hand them to /scholar-presentation (§20.1) for actual PPTX files.
20D. scholar-book — the long form [Extended]
Goal: plan, draft, revise, and assemble a book — with the argument threading intact across chapters.
argument-hint: "[proposal|outline|chapter|revise|assemble|diss2book|full]
[book-type] [topic or file]"
Four book-type profiles: monograph (70–100k words, 8–12 chapters) · edited volume (80–120k, 12–18) · textbook (100–150k, 15–20) · trade/crossover (60–80k, 8–10).
> /scholar-book proposal monograph on the Chinese digital divide for Princeton UP
> /scholar-book outline monograph on digital inequality
> /scholar-book chapter 3
> /scholar-book diss2book ~/dissertation/final.pdf
> /scholar-book assemble digital-divide-book
Four features distinguish this from “write me eight long documents”:
- The voice-calibration read. Before drafting chapter 2 or later, the skill reads the voice fingerprint plus the last 2,000 characters of the previous chapter and the first 2,000 of chapter 1. This is what stops chapter 6 from sounding like a different author than chapter 1.
- The outline hard gate. Chapter drafting refuses to start unless an outline exists, is non-trivial, and contains at least three chapter cards. No chapter gets written into a vacuum.
- The edited-volume asymmetry. For an edited volume, only chapter 1 (introduction) and the final chapter (conclusion) get full AI drafts. Everything in between produces a contributor brief — because auto-drafting someone else’s chapter is a workflow collision, not a feature.
- The style-score gate. After polishing, a chapter that fails the style ceiling (
SCHOLAR_BOOK_STYLE_MAX, default 30, three retries) is moved tochapters/_blocked/and blocks assembly until you deal with it.
The diss2book mode is the one most readers of this handbook will want. It runs a candid assessment protocol — find the book’s argument (which is usually not the dissertation’s), audit the usable yield per chapter, then execute six restructuring steps: rewrite the introduction from scratch, dissolve the literature review into the argument, cut the methods chapter in half, restructure the empirical chapters, rewrite the conclusion, and develop a voice fingerprint.
One mechanical caution the skill documents about itself: sub-skills write to their own directories (scholar-write → output/drafts/, scholar-polish → output/<slug>/polish/), so the book pipeline relocates each output back into output/<slug>/book/ after every delegation. And numeric fidelity in empirical chapters must be re-checked after polishing, because style editing has been observed to corrupt numbers (0.15 → 0.051).
20E. scholar-collaborate — CRediT, tasks, and difficult conversations
Goal: the administrative scaffolding of multi-author work, written down before it becomes a dispute.
argument-hint: "[credit|tasks|communication|contributions|mentor|team-setup|
conflict|meeting] [project name or context]
[optional: team size, roles]"
| Workflow | Produces |
|---|---|
credit | An author × role matrix across the 14 CRediT roles, conflict detection (no lead for a role, solo claims, ghost authorship, ICMJE minimum), and the statement formatted four ways (Nature narrative, Science Advances role-first, PLOS CSV, ASA acknowledgment) |
tasks | Phase breakdown, assignment table with dependencies, critical path, ASCII Gantt |
communication | Eight email templates, meeting agendas, and — usefully — difficult-conversation templates for authorship order, removing a co-author, and scope disagreements |
contributions | Contribution log, version history with attribution, NIH/NSF compliance statements |
mentor | Skill assessment across 11 areas, a training plan, five-stage milestone check-ins, a feedback framework, and documented authorship expectations |
team-setup | Roster, shared infrastructure, DUA template, IRB coordination (including the sIRB requirement for NIH since 2020), communication norms, an authorship agreement signed before work begins, folder structure |
conflict | The ICMJE + ASA five-step dispute protocol, an escalation tree, mediation guide, withdrawal protocol |
meeting | Agendas, minutes, action items, summary emails |
> /scholar-collaborate credit multi-site digital divide study team size=5
> /scholar-collaborate team-setup multi-institution demography collaboration
> /scholar-collaborate mentor training plan for a PhD student on causal inference
The highest-value item is the one people skip: the authorship agreement in team-setup, signed before work begins. Almost every authorship dispute this workflow’s conflict mode exists to resolve would have been prevented by the document its team-setup mode produces.
Unlike its siblings, this skill spawns no subagents and writes markdown only — no PDF conversion. These are working documents, not deliverables.
20F. scholar-monitor — staying current without drowning
Goal: a delta-based digest of new work in your area, delivered on a schedule, ingested into your knowledge graph.
argument-hint: "[source_id | all | preview | init | list | status | add |
remove | configure delivery | digest [date-range]]"
> /scholar-monitor init
> /scholar-monitor preview # what would be fetched — no network calls
> /scholar-monitor # fetch everything due
> /scholar-monitor add
> /scholar-monitor configure delivery
> /scholar-monitor schedule daily 08:00
> /scholar-monitor digest last-7
Three sources are enabled out of the box — ASR (weekly), Nature Human Behaviour (weekly), and an arXiv cs.CL LLM query (daily) — with 19 more shipped but disabled: AJS, Social Forces, Social Problems, Annual Review of Sociology, Demography, PDR, Gender & Society, Sociology of Education, JMF, Ethnic and Racial Studies, Du Bois Review, Social Science Research, SMR, Science Advances, Nature Computational Science, APSR, PNAS, arXiv cs.CY, arXiv econ.GN. Enable what you will actually read.
The delta mechanism is per-source state: a last_seen_date cursor plus the last 200 seen IDs, with a 14-day first-run lookback. The cursor only advances on success — a failed fetch does not silently skip a week of papers.
Delivery goes to a file (always, as the audit trail) and optionally Telegram, ntfy, or email. The discipline here is worth noting: a configured-but-broken channel RED-fails the run rather than silently skipping, and the digest is still written.
For a durable daily digest, use the skill’s own scheduler:
> /scholar-monitor schedule daily 08:00
This installs a macOS launchd job. The skill is explicit that the alternatives do not work for this: /loop is session-bound and dies when you close the terminal, and /schedule runs on remote cloud infrastructure with no access to your local config, secrets, or knowledge graph. On Linux, use crontab.
The absolute rule: no fabricated papers, ever. If the fetch returns zero, the digest reports zero — it never pads. An empty abstract is reported as “no abstract available,” never inferred.
New papers flow into the scholar-knowledge graph (§8C) at extraction_tier: abstract_only; run /scholar-knowledge re-extract later to deepen them once you have PDFs.
20G. scholar-exemplar-curate — teaching the writer what good looks like [Extended]
Goal: build the annotated paragraph library that scholar-write reads when it drafts.
This closes a loop most people never notice. scholar-write produces better prose when it has exemplars — real paragraphs from real papers in your target journal, annotated with what they do well. This skill builds that library.
Three sourcing modes plus a review gate:
| Mode | Source |
|---|---|
zotero | Auto-extract from your Zotero library, filtered by journal × time window |
top50 | A list you maintain of the 50 papers worth imitating most |
user-work | Your own publications, via the Zotero My Publications tag |
review | Walk the staged candidates and approve or reject each |
> /scholar-exemplar-curate zotero "Social Forces" methods --since 2020
> /scholar-exemplar-curate review
Nothing enters the live library automatically. Each candidate is staged in _staging/, annotated by the extract-section-exemplar subagent (which pulls the strongest 1–3 paragraphs plus a “what it does well” block and caveats), and held until you run review. Approved exemplars promote to scholar-journal/exemplars/<journal-slug>/<section>/; rejected ones go to _rejected/ so they are never proposed again.
The library is cross-project: curate once, and every future paper you write for that journal drafts against it. §14.3 walks the whole personalization workflow from the drafting side, including why user-work outranks the other sources.
PART III — ORCHESTRATORS
So far we’ve run skills one at a time. For a real paper, you want the entire chain in a single, resumable, gated workflow. That is what scholar-full-paper and scholar-auto-research provide — plus scholar-resume to tell you where you are, scholar-loop to run a queue of ideas unattended, and scholar-auto-improve to audit the suite itself.
An orchestrator adds exactly three things the individual skills do not have: ordering, gates, and resumable state. It adds no new research capability. If you understand those three things, you can use it well — and, more importantly, you can tell when it is lying to you.
On the public edition,
scholar-auto-research(§22) andscholar-auto-improve(§22B) are available;scholar-full-paper,scholar-resume, andscholar-loopare extended-only (§2.4). That is less limiting than it sounds — §22’s 21-phase contract is the more legible of the two orchestrators and the better one to learn from, and the sentence above is the reason: an orchestrator adds no capability the individual skills lack. Read §21 anyway for the gate and state-machine design; it is the fullest worked example of the ideas §22 implements.
21. scholar-full-paper — the canonical heavy chain [Extended]
Goal: one command takes you from data + research question to a verified, polished, submission-clean draft.
argument-hint: "[research idea OR data/codebook file paths | resume [slug] |
relock [slug] [--cosmetic] | --slug <name> <research idea> |
--validate-signal <research idea> <data files>]"
21.1 The invocation forms
> /scholar-full-paper --slug digital-divide-china-cfps
"RQ: In CFPS 2010-2020, did hukou/cohort gaps in internet access narrow
while gaps in weekly use hours persisted? Target Social Forces."
> /scholar-full-paper data/raw/cfps2020.dta materials/cfps-codebook.pdf
> /scholar-full-paper resume digital-divide-china-cfps
> /scholar-full-paper relock digital-divide-china-cfps --cosmetic
> /scholar-full-paper --validate-signal --slug gss-polarization \
"Has affective polarization risen?" data/raw/gss.dta
Arguments are parsed in a fixed order: resume and relock keywords first, then --slug, then --validate-signal. A slug must match ^[a-z][a-z0-9-]{1,63}$. Handing it data files with no research question routes into Phase 0-PRE (brainstorm); --validate-signal forces the brainstorm’s empirical signal tests to run even when you do have a question.
21.2 The complete phase route
The canonical sequence is defined in scripts/gates/pipeline-state.sh as 28 entries:
-1 0-PRE 0 1 2 3 3.5 4 5 5A.5 5A.7 5.5 5C 6 6.5 7 7b 7c 7c.5
8 9 9b 10 10.5 11 11b 11.5 12
| Phase | What happens | Gate |
|---|---|---|
| −1 | Safety scan | All files CLEARED / LOCAL_MODE |
| 0-PRE | Brainstorm (conditional) | Top-10 ranked RQs; auto-excused if materials absent or an RQ exists |
| 0 | Idea selection | One focal RQ; writes the full project CLAUDE.md |
| 0.D | Auto-infer data status | Data Status: no-data \| materials-only \| existing-data |
| 1 | Research brief | Journal, word limit, scope; project state initialized |
| 2 | Lit review + theory | ≥50 papers (RED floor), ≥70 for GREEN, ≥2,000 words, mechanism chain, ≥95% verification rate |
| 3 | Design blueprint | DAG, identification-strategy.json, model-specs.json, test-inventory.json |
| 3.5 | Design pre-mortem | ≥3 real reviewer dispatches with provenance |
| 4 | Data blueprint | Variable dictionary, IRB determination, CRediT draft |
| 5 | EDA + analysis | ≥3 model specs, ≥2 robustness checks, ≥4 figures |
| 5A.5 | Pre-execution code review | Universal — never auto-excused |
| 5A.7 | Analysis pre-mortem | Reviewer panel; a RED-headline-contingent finding cannot be waved through |
| 5B | Execute analysis | (no separate gate — implicit via 5.5) |
| 5.5 | Full code review | Six separate agent dispatches, counted by unique agent ID |
| 5C | Runtime sanity | Overall verdict: PASS; any CRITICAL halts |
| 6 | Compute / linguistic branch (conditional) | Auto-excused if not a compute or linguistics project |
| 6.2 | Compute pre-mortem (if 6 active) | Reviewer panel |
| 6.5 | Results lock + pre-draft verify | SHA-256 manifest; state must record lock_manifest_sha: |
| 6.8 | Section blueprint | Per-section authoring contract |
| 7 | Manuscript drafting | Reads only from the lock; each section ≥60% of budget |
| 7b | Verification gate | Four real verify-agent dispatches; halts at >3 CRITICAL |
| 7c | Style polish | Em-dash density RED above 2.5/page; shape checks S1–S4 |
| 7c.5 | Prose quality review | Codex cross-model panel + a holistic Claude reader |
| 8 | Citation harmonization | .bib present, zero [CITATION NEEDED], ≥10 rendered entries |
| 9 | Submission package | Cover letter, open-science declarations |
| 9b | Ethics compliance | ethics-verdict.json; any flag blocks Phase 10 |
| 10 | Review simulation | ≥3 real peer-reviewer-* dispatches; revisions advisory by default |
| 10.5a | Cross-phase reviewer synthesis | Every Bucket A resolved, every Bucket B disclosed |
| 10.5b | Independent editorial panel | ≥4 fresh reviewers, senior unprimed |
| 11 | Final assembly | All four formats — md, docx, tex, pdf |
| 11b | Submission prep | Reviewer-facing manuscript; fails closed |
| 11.5 | Submission hygiene | Three stages: A hygiene → A.5 Codex prose → B semantic read |
| 12 | Replication package | Terminal. Every contract clause is RED, not YELLOW |
Every phase gate is a hard gate unless marked advisory. Phase 5B is the one execution step with no gate of its own.
21.3 The state machine
State lives in output/<slug>/logs/project-state.md, in two layers: an auto-managed === PIPELINE STATE === block that you must never hand-edit, and a human-readable === PROJECT STATE === audit log below it.
=== PIPELINE STATE ===
phases_completed: -1,0,1,2,3,3.5,4,5,5A.5,5A.7,5.5,5C
current_phase: 6.5
current_phase_status: in_progress
relock_count: 0
started_at: 2026-05-04T09:12:33Z
last_updated: 2026-05-04T16:41:07Z
current_phase_status is one of not_started, in_progress, completed, or halted-RED-at-<phase>.
There is also a body_checksum — a hash over every non-blank line outside the block. If you hand-edit the markdown log, the checksum goes stale, and the next resume returns STALE_BLOCK_REQUIRES_REBUILD rather than guessing. This is a feature: the system notices that a human edited its state file.
Do not append a second ## Phase N heading by hand. It duplicates the heading and staleness-flags the checksum. Use pipeline-state.sh note instead.
The operator surface:
$ bash scripts/gates/pipeline-state.sh status "$PROJ"
$ bash scripts/gates/pipeline-state.sh next "$PROJ"
$ bash scripts/gates/pipeline-state.sh halt 7b --reason "verify found 4 CRITs"
$ bash scripts/gates/pipeline-state.sh rebuild "$PROJ"
$ bash scripts/gates/phase-verify.sh 7b "$PROJ"
Three other scripts do most of the real work: results-lock.sh snapshots tables, figures, EDA output, and verify reports into results-locked/<LOCK_ID>/ with a SHA-256 manifest, then makes them read-only; results-lock-verify.sh re-hashes every file against that manifest; and phase-verify.sh runs the per-phase gate battery — 123 distinct gate scripts across the pipeline.
21.4 Session seams — why it stops and asks
Long runs blow through context. The pipeline therefore marks cluster seams at Phases 5C, 6.5, 8, and 10.5 — the boundaries between Plan-and-Execute, Lock, Draft-and-Verify, Ethics-and-Replication, and Final-Assembly — plus lighter advisory seams after Phases 2, 7, 7b, and 10.
At a cluster seam the orchestrator stops the turn and hands you a resume command. That is not a failure; it is the design. You are expected to /clear and resume.
The skill is candid about why: it has no harness API to measure remaining context, so “I was running low on context” is explicitly inadmissible as a reason to skip a phase.
21.5 Back-routing — when a downstream gate blames an upstream phase
When Phase 7b’s verification finds that the prose misstates a table, the fix belongs at Phase 7, not 7b. The gates emit a back-route directive:
BACK_ROUTE=7:fix-verify-findings
BACK_ROUTE_COUNT=1
BACK_ROUTE_FINDINGS_DIGEST=a3f9c21b7e40d8ff
Back-routes are emitted from the RED arms of Phases 5C, 7b, 8, and 11.5. When several fire, the most upstream target wins. Two brakes prevent infinite loops: a numeric cap of 9 (dropping to 2 under an autonomous loop), and a same-signature cap of 3 — if the identical set of findings routes back three times, the pipeline escalates rather than trying a fourth time. The counter resets only on genuine forward progress.
21.6 Hard blocks — the honest part
These gates cannot be waved through. Three hard blocks refuse at the call site:
| Block | Refuses | Exit |
|---|---|---|
| HB1 | Capping user_authorized_through_phase at a phase whose gate is currently RED | 5 |
| HB2 | Bypassing heterogeneous-review coverage | gate RED |
| HB3 | Any attempt to mark a phase complete while its gate is non-zero — for any reason | 3 |
HB3 is the important one. SCHOLAR_PSTATE_FORCE_REASON no longer bypasses it; the force-handling code below the refusal is dead code kept for git history. Every refusal is logged to logs/hardblock-refusal-audit.md with the reason and the last 20 lines of gate output, and recorded in the state block as phases_force_complete_blocked.
The only two legitimate ways forward from a RED gate:
- Fix the defect the gate surfaced.
pipeline-state.sh halt <phase> --reason "<text>"— which records the failure honestly rather than erasing it.
Every mutating command is also logged to logs/state-mutations.md with a timestamp, the arguments, and the parent process — so the audit trail survives even if the markdown is later edited.
The disclaimer that makes this trustworthy. The suite ships a document,
structural-bypass-limits.md, stating plainly that these provenance gates are a speed-bump, not a structural barrier. The residual bypass is a three-file consistent forgery: the artifact, the process log, and the dispatch manifest are all files a language model can write. Closing that hole would need runtime-signed manifest entries or a non-writable sink, and neither exists in Claude Code today.Read that twice. A system that documents its own defeat conditions is more trustworthy than one that claims to be airtight — but it also means the gates protect you from an agent taking shortcuts, not from an agent that has decided to fabricate. The human reading the artifacts is still the last line.
21.7 Provenance — how the pipeline knows a reviewer was real
The single largest failure mode in this whole system is an agent writing a review in its own voice instead of dispatching a real subagent. The countermeasure is a dispatch manifest:
$ bash scripts/gates/emit-task-dispatch.sh --proj "$PROJ" \
--subagent peer-reviewer-quant --purpose design-premortem \
--phase 3.5 --agentId a7f3c9e21b884
Every gated dispatch appends a row to logs/dispatch-manifest.jsonl, and the gates cross-check three ways: the agent ID must appear in the artifact, the process log, and the manifest; the purpose is bound on first record; duplicates are first-seen-wins. Invocation IDs must match ^[a-z][a-z0-9_]{12,}$ — placeholders fail. And a project whose process log shows zero dispatches while its memo claims three reviewer rows is REDed as “inline-simulation suspected.”
This is exactly the check that §13’s surrogate disclosure failed, honestly and in public.
21.8 Resume
> /scholar-full-paper resume digital-divide-china-cfps
This reads the state block, identifies the last completed phase, and continues. If verification finds a problem at Phase 7b, the orchestrator routes back to Phase 5 or 7 — never forward.
21.9 Empirical baseline — scoring the example corpus
Source and caveat. The head-to-head table below comes from
workshop/workshop-papers-analysis-2026-05-07.md(1,369-line audit memo, generated 2026-05-07). Methodology: 26 AI-produced manuscripts fromworkshop/cfps-example/output/andworkshop/GSS/Projects/output/, scored 1–10 by five parallel domain-aware reviewer agents against Zhang 2017 JMF as benchmark, using a consistent rubric (theory · data · methods · findings · 3-reviewer simulation · journal verdict). Cost estimates derived from manuscript word count, project artifact size, and number of analysis scripts (no direct API logs available). The rubric is internal and not formally validated — replace with your own audit results before citing externally. The corpus has since grown well beyond these 26 — see the note below the table.
From the audit (post-correction cell breakdown, per audit memo §Re-analysis):
| Configuration | Mean score (out of 10) | N | Source |
|---|---|---|---|
scholar-full-paper × Claude Code | 6.36 | 18 | audit memo §Re-analysis line 1094 |
scholar-auto-research × Claude Code | 5.50 | 3 | audit memo §Re-analysis line 1094 |
scholar-auto-research × Codex CLI | 4.40 | 5 | audit memo §Re-analysis line 1095 |
scholar-full-paper × Codex CLI | (unfilled — recommend running 3–5 papers to populate) | 0 | — |
| Whole-corpus mean | 5.94 | 26 | audit memo §Headline line 60 |
Cost (per audit memo per-paper cost column): ≈ $20–$60 per paper, ≈ $700–$1,200 total across the 26 papers (range varies with manuscript length: a 3,000-word paper sits near $20, a 14,000-word paper near $60).
Most outputs were salvageable drafts, not submission-ready (median verdict: Major Revision at a Q2 journal). The takeaway: scholar-full-paper + Claude Code + human verification gates is the current best-observed cell (mean 6.36, n=18). The Codex × scholar-auto-research cell (mean 4.40, n=5) is the weakest in the corpus; the orchestrator may improve on the v5.18.0 / v5.19.0 gates, especially on Claude — re-run before re-evaluating.
Since the May-7 audit, the example corpus has grown to ~40 assembled CFPS + GSS papers — but the scoring did not keep pace, and that gap is itself the lesson: production outran verification. Only 6 of the ~40 carry a real numeric panel score, and only 4 were put through a full 5-plus-reviewer panel (workshop/materials/vibe-researching-slides-2026-05-29.md, “How These Papers Were Scored (and Why Most Have No Number)”). Of the drafts that did face a real editorial panel, the trustworthy publishability verdicts span the full range:
| Paper (short) | Score / 10 | #rev | Verdict |
|---|---|---|---|
| Cohab → marital quality (selection vs. diffusion), CFPS | 8.00 | 4 | editorial panel, all MINOR |
| Rising age & hazard of cohabitation, CFPS | 7.26 | 5 | editorial panel, MAJOR revision |
| Digital divide v2, CFPS | 6.38 | 5 | editorial gate, FAIL |
A separate prose-quality revise pass (cfps-example/output/workshop-updated-manuscripts/SCORECARD.md, 2026-05-09) lifted 11 produced manuscripts to a mean 8.04 on a 12-dimension writing-craft scale — but the scorecard itself flags that craft ≠ publishability: a fresh independent reviewer panel re-reading the 8.17-craft flagship (cohabitation-marriage-cfps v5) still returned MAJOR_REVISION on all four reviewers. Bottom line: an 8+ auto self-critique or prose-craft score is not a peer-review verdict — only the four editorial-panel numbers above are trustworthy, and they still land at major-revision-or-worse.
21.10 When to ask the user rather than push through
The skill names the moments where an agent should stop and ask — worth adopting as your own rule set:
- A gate REDs twice at the same phase and you are considering a third fix.
- You are about to rewrite agent-authored JSON or YAML in order to clear a gate.
- You are about to invoke a force reason, cap authorization past a RED, or write an
[EXCUSED:*]tag on a strong-trigger gate. - A pre-mortem RED names an artifact that is absent from the lock manifest.
- A reviewer’s prose verdict disagrees with its own structured metadata.
21A. scholar-resume — where am I, and what runs next [Extended]
Goal: one advisory line telling you exactly what to do next. It executes nothing, writes nothing, and modifies no state.
> /scholar-resume # newest project
> /scholar-resume digital-divide-china-cfps
It is a thin wrapper over scripts/resume-dispatch.sh, so /scholar-resume <slug> and /scholar-full-paper resume <slug> route identically. Output ends with a single directive:
RESUME_ROUTE= | Meaning | What to do |
|---|---|---|
execute:<phase> | Next phase is ready | Run it |
resume:<phase> | Phase was interrupted mid-run | Re-execute from step 1, reading partial outputs first |
fill-gap:<phase> | A subphase was skipped | Run it before advancing, or formally excuse it |
back-route:<phase>:<reason> | A downstream gate blamed an upstream phase | Re-execute that phase with the reason as the goal |
back-route-escalate:<phase>:<reason> | The back-route counter hit its cap | Stop. Surface verbatim. Do not re-route |
stale-block | The state markdown was hand-edited | Run the rebuild command manually — never auto-rebuilt |
done:pipeline-complete | Everything finished | Ask what’s next |
done:capped-at-<N> | You capped authorization at phase N | Stop. No further phases without re-authorization |
error:no-project-state-found | No such project | Check the slug |
A malformed slug fails closed — it refuses to silently fall back to your newest project, which is exactly the behaviour you want at 11pm.
Between the state dump and the directive, it also prints lessons from prior phases in this project and cross-project lessons keyed by dataset (CFPS, GSS, PSID) and by keywords from your research question. That injection is always advisory and silent on a miss.
22. scholar-auto-research — deterministic teaching scaffold
> /scholar-auto-research "Does platform trust mediate the digital divide in China?"
> /scholar-auto-research data/raw/cfps2020.dta materials/codebook.pdf
> /scholar-auto-research resume output/cfps-platform-trust-asr
> /scholar-auto-research verify output/cfps-platform-trust-asr
scholar-auto-research defines exactly 21 phases (0 through 20) in references/phase-contract.json. Each phase declares required_inputs, required_outputs, a verifier, a pass_schema the verdict JSON must satisfy, next_phase, and route_back_phase.
| # | Phase | Required artifact |
|---|---|---|
| 0 | Safety | safety/safety-status.json; unresolved high-risk files block the run |
| 1 | Research Question | Candidate RQs, evaluation panel, journal fit, selected RQ, rationale |
| 2 | Literature and Theory | lit-theory.md, coverage matrix, verified references.bib (>30 entries) |
| 3 | Design | Blueprint, model specs, identification strategy, revision log |
| 4 | Data and Measurement | Variable dictionary, data status, measurement plan, manifest |
| 5 | Analysis Plan | Spec registry, scripts inventory, analysis plan — no execution |
| 6 | Pre-Execution Review | Six-lens planned-code review + fix log + re-review |
| 7 | Analysis Premortem | Risk register, null-falsification table, go_no_go must be GO |
| 8 | Execute Analysis | Execution report, results registry, figure registry |
| 9 | Post-Execution Review | Review + fix log; unresolved blockers route back to 6 |
| 10 | Runtime Sanity | Rerun plausibility, invariants, drift checks |
| 11 | Results Lock | Immutable snapshot, manifest hash, Stage 1 verify |
| 12 | Manuscript Blueprint | Per-section authoring contract |
| 13 | Draft Manuscript | Draft, drafting plan, self-critique, polish report, journal spec |
| 14 | Verify Manuscript | Verification report (numerics, figures, logic, completeness) |
| 15 | Citation and Claim Support | Citation audit + claim-source map + references.bib |
| 16 | Ethics and Open Science | Ethics + open-science statement |
| 17 | Replication Package | Package, test report, verification report, manifest |
| 18 | Manuscript Quality Gate | Quality report — hard gate before assembly |
| 19 | Final Assembly | manuscript-final.{md,docx,tex,pdf} + manifest |
| 20 | Submission Hygiene | Submission-clean outputs; pipeline_complete: true |
22.1 What makes it “deterministic”
Three mechanisms the heavy chain does not have in the same form:
- A contract hash. State records the SHA-256 of
phase-contract.json. If the contract changes underneath a running project, mutating commands refuse withCONTRACT_DRIFTrather than proceeding against a moved target. - Verify stamps.
auto-research-verify.shmints a stamp per passing phase. Marking a phase complete without a stamp fails withVERIFY_STAMP_REQUIRED; a stamp that no longer matches the artifacts fails withVERIFY_STAMP_STALE. Routing back deletes the stamps of every invalidated downstream phase, so you cannot accidentally keep a stale pass. - Explicit run modes. The mode starts
unset, andnextreturnsMODE_SELECTIONuntil you choose. Inhuman_in_loop, every phase transition creates a pending decision that blocks completion until you approve. Autonomous mode is never inferred from silence.
Route-backs cap at 3 per finding ID; the third exits with code 2 and requires a human to inspect the underlying issue and clear the retry counts by hand.
Phase 18’s quality gate is unusually explicit: every dimension ≥7 across ten named dimensions, mean ≥8, no critical or major finding open, no reviewer returning REJECT or MAJOR_REVISION, and at least one reviewer pair with Jaccard ≥0.7 on what they identified as the contribution — a direct test of whether the reviewers agree on what the paper is about.
22.2 The rule that outranks the contract
The skill states it as a MUST-FOLLOW rule, and it is the best sentence in the entire suite:
Contract compliance is a means, not the end. A manuscript that passes every contract but is thin, generic, mechanically templated, poorly cited, weakly argued, or visually incomplete fails.
That is the correct relationship between a checklist and a paper, and it is worth saying out loud to any participant who starts treating green gates as the goal.
It is the right tool for classroom demos and pipeline prototypes. It is not the heavy default for a serious paper — use full-paper for that.
If you want to build your own orchestrator, copy the structure: phase-id → purpose → required inputs → actions → outputs → verification gate → next/route-back. Start with five phases for your own workflow before attempting a full chain.
22A. scholar-loop — a queue of ideas, run unattended [Extended]
Goal: hand it a set of research ideas and let it drive each one through a full pipeline across scheduled wakeups — blocking honestly when a gate goes RED rather than bypassing it.
argument-hint: "[init <ideas|file> [--no-triage] | run | status |
unblock <id> | add <idea> --orchestrator <o>]"
> /scholar-loop init planning/ideas.txt
> /loop /scholar-loop run # start the loop
> /scholar-loop status
> /scholar-loop unblock q03
The queue lives in output/_queue/ as three files: queue.json (the authoritative state, written atomically so Google Drive sync cannot corrupt it), decisions-needed.md (an append-only ledger of blocked items), and loop-journal.md (one line per wakeup).
Each item moves through pending → active → done | blocked | failed | skipped, and only one item may be active at a time — a serial queue by design.
22A.1 The per-wakeup contract
Each wakeup does exactly one seam-cluster of work: pick the next item → charge its wakeup budget → dispatch or resume the orchestrator → capture the terminal signal by probe, never by reading prose → act → re-arm.
That fourth step is the interesting one. The loop never interprets an orchestrator’s chatty output itself. It pipes the raw KEY=value dump into queue-state.sh interpret, which is the single place signals map to actions:
| Signal | Action |
|---|---|
Safety status NEEDS_REVIEW or HALTED (checked first) | blocked |
RESUME_ROUTE=back-route-escalate:* / error:* / stale-block | blocked |
RESUME_ROUTE=done:* | done |
RESUME_ROUTE=execute: / resume: / fill-gap: / back-route: | continue |
Auto-research route-back escalation, or APPROVAL_REQUIRED=1, or run mode unset | blocked |
| Empty or unrecognized output | blocked (uninterpretable-signal) |
Note the last row: an unparseable signal blocks. It does not optimistically continue.
22A.2 The invariants that make unattended running safe
These are stated as absolutes, and they are the reason this is publishable rather than reckless:
- Blocked, never bypassed. On an unresolvable RED, mark the item blocked and move to the next idea. Never set a force reason, never cap authorization past a RED phase, never write an
[EXCUSED:*]tag, never writeOVERRIDEinto a safety status file, never hand-edit any state file. There is no loop-driver exception to any of these. - Never re-arm when the queue is empty or everything is terminal.
- The loop is the sole wakeup owner — the orchestrator must not double-arm underneath it.
- The re-arm prompt is the fixed literal
/scholar-loop run— never with an ID or slug embedded. - Notify sparingly: per-item completion, per-item block, budget stop, final summary. A “continue” is a journal line, not a notification.
- Run
/looplocally, not as a cloud-scheduled agent, whenever any queued project is LOCAL_MODE. Remote infrastructure has no access to your local safety configuration.
Budgets bound the cost: 40 wakeups per item, 200 total. Exceeding either blocks the item rather than continuing to spend.
unblock is interactive-only and never runs autonomously — and the ledger tells you what to do for each block reason, because a blocked item usually needs a real fix, not a retry.
22B. scholar-auto-improve — auditing the suite itself
Goal: find out whether the skills are producing what they claim to, and fix them when they are not.
argument-hint: "[mode: observe|audit|improve|evolve] [optional: skill-name]
[optional: output-path]"
| Mode | Inspects | Produces |
|---|---|---|
| observe | The artifacts a skill just wrote — missing, empty (<100 chars), unexpected; content quality; unresolved [CITATION NEEDED] and SOURCE NEEDED markers | An audit report and a health verdict |
| audit | Every SKILL.md in the suite against 14 structural checks (A1–A14) | A Suite Health Score /100 |
| improve | The latest observe/audit report | Verified, falsifiable fix proposals — applied only after you confirm |
| evolve | The whole improvement-log.md history | Recurring issues, skill hotspots, regression patterns, systemic fixes |
> /scholar-auto-improve observe scholar-analyze
> /scholar-auto-improve audit
> /scholar-auto-improve evolve
Health scoring is mechanical: start at 100, subtract 20 per CRITICAL, 5 per ERROR, 1 per WARN. 90–100 GREEN · 70–89 YELLOW · 50–69 ORANGE · below 50 RED.
22B.1 Why IMPROVE mode is more careful than it looks
The interesting engineering is in how a proposed fix has to prove itself, and the reason is a documented failure: earlier rounds shipped fixes that passed the author’s own validation and then broke on a peer project.
So a fix proposal now carries a falsifiable contract — a before-state with an observable (RC=<n>; MATCH=<regex>), a predicted after-state, a reproduction command, and a peer project to test against, or an explicit limitation note if none exists. Then:
- A bounded diagnostic loop — max 3 hypothesis-test cycles, max 6 tool calls per issue — must identify a mechanism, citing
file:line. No confirmed cause means the issue is routed tounexplained-issues-<date>.mdfor human triage and is never auto-applied. fix-contract-verify.sh --phase BEFOREmust reproduce the failure on both the author’s and the peer’s project.validate-patch.shchecks schema, target existence, and line-range overlap.- You confirm. Nothing is applied without it.
--phase AFTERmust flip on both projects, and for CRITICAL fixes an independentreview-code-correctnessagent reads the raw fixtures and does not trust the verifier’s own status line.
The captured fixtures persist as regression tests. Re-running BEFORE in a later round must still match — if it does not, the bug came back.
22B.2 The rule worth stealing
Among its five absolute rules, one generalizes far beyond this suite:
Never fabricate evidence. File paths, line numbers, function names, gate names, and any citation in an audit report must be verified against the live tree before being written. A memory that names a file, function, or flag is a claim to re-verify, not a fact to assert.
Unverified claims get [CITATION NEEDED: <what to verify>] — the same discipline the citation skill applies to literature, applied to the codebase.
A documentation inconsistency to know about. This skill describes itself as running at “Phase 14” of
scholar-full-paper. The orchestrator now terminates at Phase 12 and explicitly routes post-submission audits to a standalone invocation. The Phase-14 framing is stale. Run it yourself after a pipeline completes; do not expect the orchestrator to call it.
23. Codex as external reviewer — by hand
Goal: independence. The agent that ran the pipeline is not a reliable judge of the pipeline.
After Claude finishes, hand the work to Codex:
$ cd output/digital-divide-china-cfps
$ codex
Inside Codex:
> Audit scripts/04-models-Y2.R against design/design-blueprint-...md.
Check that: (a) the focal Y2 estimator is OLS with province×wave FE conditional on Y1=1, with Tobit MLE as cross-check (per CRIT-STAT-001;
province × wave FE; (b) cluster-robust SE are clustered by `pid`;
(c) BH-FDR is applied across H1-H4 focal tests; (d) the final coefficient
matches tables/table-Y2-models.csv cell M3.hukou_rural to 3 decimal places.
Report each as PASS / FAIL / UNCERTAIN with one-line evidence.
Codex will read the script, the blueprint, the table, and reply with a four-row PASS/FAIL/UNCERTAIN audit. This is exactly the format of a code-review subagent — except the reviewer is a different vendor’s model, which is the point.
What not to ask Codex to do:
- “Fix the paper” (no constraints → mass rewrite).
- “Invent missing data” (this should never be asked).
- “Choose the journal” (editorial judgment is yours).
23A. scholar-openai — the same review, orchestrated
argument-hint: "[code|stats|logic|full|prose|custom] [manuscript-path]
[scripts-dir|phase]"
| Mode | Agents | Reviews |
|---|---|---|
code | A1–A3 | Correctness, robustness, reproducibility |
stats | A4 | Every manuscript number against the raw table outputs, cell by cell |
logic | A5 | Every prose claim against its referenced table or figure |
peer-audit | A4, A5, A6 | Strict numeric audit bound to the locked registry |
prose | P1–P3 | Register, argument, and an unprimed reviewer-eye read |
full (default) | A1–A5 | Everything except the peer audit |
> /scholar-openai full output/digital-divide-china-cfps/drafts/manuscript-final-2026-05-04.md
> /scholar-openai prose drafts/manuscript-submission-2026-05-06.md 11.5
Agents spawn in parallel as background processes with a 300-second timeout each:
codex exec -C "$CODEX_WORKDIR" --skip-git-repo-check \
-c 'sandbox_permissions=["disk-full-read-access"]' \
-o "${REVIEW_DIR}/A1-code-correctness-${RUN_TS}.md" \
"You are a code review agent for a social science research project. …" &
Reports land in reviews/codex/, and Claude — not Codex — synthesizes them into a scorecard, a deduplicated fix checklist, and a cross-agent agreement section.
Three details matter for using this honestly:
- The read-only guarantee is architectural, not sandboxed. The skill documents that
disk-full-read-accessdoes not actually confine reads — Codex cancatany absolute path. The real guarantee against modification is that Codex is only ever given-o <file>(it writes only its own report) and is prompted to review, never to edit. - Under LOCAL_MODE, a data-free mirror is built first, and every failure mode of that mirror build — an empty path, a hardcoded absolute data path, a missing
rsync— halts fail-closed rather than falling back to the live tree. - P3, the reviewer-eye lens, is deliberately unprimed. It must not read the prior peer-review or verification outputs. It answers three questions: what is your first impression, would you recognize this as a paper a reviewer would take seriously, and would you recognize it as AI-drafted.
Codex review is on by default in the orchestrator (SCHOLAR_CODEX_DEFAULT=true). Opting out requires both the environment flag and a documented reason — and the accepted reasons are a short whitelist: Codex not installed, Codex API unavailable, OpenAI API unavailable. Explicitly rejected rationales include “context pressure,” “workshop context,” “operator chose not to invoke,” and “gate bug.” You may skip the external reviewer because it is unavailable, not because it is inconvenient.
PART IV — RESPONSIBLE PRACTICE
24. The First-20-Minutes Protocol
Whenever you start a new project:
Make the directory.
mkdir -p projects/<slug>/{data/raw,data/interim,data/processed,\ materials,output,logs}- Copy raw data into
data/raw/. Do not edit. cd projects/<slug>and runclaude.- Run
/scholar-init --slug <slug>. - Run
/scholar-init review. Resolve every NEEDS_REVIEW. (Thereviewmode lives onscholar-init, notscholar-safety.) - Run
/initto generateCLAUDE.md. Edit it. Add forbidden actions. - Run
/scholar-brainstormto widen the menu. Pick one RQ manually. - Run
/scholar-idea. Confirm hypotheses are pre-specified.
Only after all eight are done should you let the agent touch a model.
25. Five Common Participant Mistakes
- “Write me a paper on X.” Skip step 7 above; agent invents both question and evidence.
- Letting AI read everything. No
scholar-safetystep. Raw rows enter context. Privacy boundary lost. - Accepting citations by sound. No
scholar-citationverify. Bibliography becomes fiction. - Ignoring logs. No audit trail when verification finds a problem.
- Polishing before verifying. Polish makes a wrong claim more confident. Reverse the order: verify first, polish last.
26. The Take-Home Checklist
Treat each line as a commitment:
- I will run
scholar-init+scholar-safetybefore my agent reads any sensitive data. - I will write
CLAUDE.mdfor every project. - I will switch into
planmode (Shift+Tab) for any risky multi-step task. - I will keep the
output/<slug>/scripts/folder as the single source of truth for analysis. - I will lock results before drafting (
scholar-analyze→results-lock-*.md). - I will run
scholar-verifybefore believing any number in my draft. - I will run
scholar-citation verifybefore submitting. - I will only run
scholar-polishafter verification PASSes. - I will use a second-vendor agent (Codex) as an external reviewer on high-stakes claims.
- I will preserve AI failure cases in the verification log, not silently rewrite them.
27. Five Principles for Responsible Vibe Researching
- Disclose. State which AI tools touched the manuscript, in what role, at what stage. (
scholar-ethicsproduces this disclosure for you.) - Verify. Every claim → table → script → sample. Numbers, citations, figures, hypotheses — all of them.
- Maintain skills. Don’t outsource what you should still be able to do yourself. Run the regression by hand once a year.
- Protect originality. Your research question, theoretical taste, identification judgment, and final accountability are not delegable.
- Design for access. AI productivity is a multiplier on existing institutional gaps. Share scripts, codebooks, mock data, and skills generously.
27A. How this maps to Anthropic’s 4D framework
Anthropic’s official AI Fluency curriculum organizes every interaction with an AI system around four verbs — the 4D framework: Delegation, Description, Discernment, Diligence. The workshop’s five principles, the hands-on protocol in §3, and every scholar-skill are recognizable as instances of the same four moves. This crosswalk gives participants a vocabulary that aligns with Anthropic’s own training when they continue learning after the workshop ends.
| 4D | What Anthropic teaches | Where it lives in this workshop |
|---|---|---|
| Delegation | Decide what to hand to the agent vs. keep human; project planning | §3.5 model picker (Haiku / Sonnet / Opus tiering) · the V×A delegation typology (output verifiability × process articulability) · the delegation framework in the take-home block |
| Description | Effective prompting --- the input contract | §5 prompt anatomy · §3.3 CLAUDE.md as durable brief · §8D identification-memo.md as a structured input contract |
| Discernment | Critical evaluation; the Description ↔ Discernment loop | §13 scholar-code-review · §15 scholar-verify (the workshop's central lesson) · §23 Codex as external reviewer |
| Diligence | Verification + responsible use; the final gate | §27 above (the five principles) · §26 reusable workflow ending at Verify · §19 scholar-replication / scholar-open |
Note what Anthropic emphasizes that you might otherwise miss: Description and Discernment are a loop, not separate steps. That is exactly what the request → propose → approve → artifact → verify cycle in §3 is doing — every approval is a discernment act that revises the next description. If your sessions feel like a one-shot prompt followed by a long monologue from the agent, the loop has collapsed and the quality will reflect it.
28. Closing
When the agent can execute the pipeline, what becomes more valuable?
Your question. Your judgment. Your accountability.
The skills in this handbook do not make AI sound scholarly. They make AI leave behind inspectable scholarly artifacts. Inspectable artifacts are how scholarship survives the introduction of any new tool — printing press, statistical computing, or coding agent.
Now go open claude in a real project directory and run /scholar-init. The first 20 minutes is the most important investment you can make.
Code, scripts, and full project artifacts for the CFPS digital-divide example are at: Claude-Code-Skill/workshop/cfps-example/output/digital-divide-china-cfps/
Open Scholar Skills repository: github.com/joshzyj/open-scholar-skill
Workshop materials and updates: ZhangYGroup/VibeRes4SS/
PART V — APPENDICES: REAL ARTIFACTS IN FULL
These appendices contain the complete, unedited reports from the CFPS digital-divide pipeline run on May 4–5, 2026. Inline excerpts in Parts II–IV are drawn from these. Read them as forensic evidence of what an end-to-end agent-driven pipeline actually produces — including the typos, the rounding warnings, the deferred items, and the documented failure cases.
Appendix A — scholar-brainstorm Executive Summary (full)
File: output/digital-divide-china-cfps/ scholar-brainstorm- digital-divide-china-cfps-top5-summary-2026-05-05.md. Generated 2026-05-05.
Research Question Brainstorm - Executive Summary
Digital Divide in China Using CFPS Materials
Generated by /scholar-brainstorm on 2026-05-05 Operating mode: MATERIALS
Dataset Overview
The supplied materials are CFPS questionnaires and codebooks covering 2010-2020. CFPS is a nationally representative longitudinal survey of Chinese individuals, households, families, and communities, with rich modules on economic activity, education, family dynamics, migration, health, and internet use. This run did not include raw data files, so the ranking is based on measurement coverage, theory, and verified literature rather than empirical signal tests.
Top 5 RQs
####### #1: Access Convergence, Use Divergence
RQ: In China from 2010 to 2020, did the hukou, education, and cohort gaps in internet access narrow while gaps in productive use, use intensity, and use breadth persisted or widened?
Variables: U201, U202, U250M, U701-U705, hukou, education, cohort, gender, income, household composition.
Why strongest: Best flagship paper. It uses CFPS’s panel structure to separate first-level access from second-level productive use and can speak directly to stratification theory.
Method sketch: Panel models, wave/province controls, individual fixed effects where feasible, and decomposition of rural-hukou or cohort gaps.
####### #2: Remote-Work Divide During COVID-19
RQ: Did mobile-only internet access, computer internet access, and job-level computer requirements determine who could shift to remote work during the 2020 COVID shock, and did this protect workers from income loss?
Variables: U201, U202, U201A, U202A, G19, COVID5, COVID4, COVID601, COVID602, G11, G12.
Why strong: Turns the digital divide into a shock-resilience question. The 2020 work module gives a clear pandemic hook.
Method sketch: Employed 2020 respondents, occupation/industry/province controls, and income-loss models by device access and digital job compatibility.
####### #3: Online-Learning Outcome Divide
RQ: During COVID-19 school closures, did rural/hukou and parental-education differences in device access and online-learning intensity translate into unequal study time, tutoring, education spending, and aspirations?
Variables: COVID3, U94, tutoring participation/time/spending, education spending, study time, aspirations, parental education/income, hukou.
Why strong: CFPS can connect student online learning to household resources and education spending, which many school-only surveys cannot.
Method sketch: Student/child subsample, decomposition of rural-urban or parental-education gaps, and pre-2020 baseline controls where mergeable.
####### #4: Older-Adult Digital Health and Social-Connection Divide
RQ: Among adults aged 60+, does internet use improve self-rated health, mental health, happiness, and social connectedness, and are returns concentrated among urban, educated, or co-resident-with-younger-family older adults?
Variables: Internet access/use, U701, U703, U802, U11, health and mental-health items, M2016, M2011, household composition.
Why viable: CFPS supports panel health analysis, but the area is crowded. It needs a sharper mechanism, especially household digital transmission or type-of-use heterogeneity.
Method sketch: 2014-2020 older-adult panel, fixed effects, lagged internet use where possible, and heterogeneity by hukou/education/living arrangement.
####### #5: Information Trust, Privacy Concern, and Platform Dependence
RQ: Does dependence on WeChat, short video, and online news create unequal information trust and privacy/data-governance attitudes across age, education, and hukou groups?
Variables: U11, U111, U93, N202, U802, U13, U110, U121-U123, N1001.
Why distinctive: Moves beyond access and use into platform-mediated trust, misinformation risk, and privacy attitudes. Main constraint: some 2020 items are restricted data.
Method sketch: 2020 cross-sectional models, age/education/hukou interactions, and latent-class typology of platform dependence and privacy/trust attitudes.
Recommendation
Pursue RQ1 as the main paper. It has the strongest combination of data readiness, theoretical breadth, and publication fit because it uses CFPS’s central advantage: repeated individual-level observation during China’s access-saturation transition. RQ2 is the best alternative if the desired paper should be more timely and shock-oriented; it converts digital inequality into a labor-market resilience question during COVID-19. RQ5 is the most novel side project but should only be pursued if the restricted 2020 privacy and information-trust items are accessible.
RQ3 is feasible and policy-relevant, but the COVID online-learning literature is already crowded; the contribution must be household linkage, not simply another rural-urban learning-gap paper. RQ4 is substantively important, but multiple recent CFPS studies already examine internet use and older-adult health, so novelty depends on reframing around intra-household digital support, type of online use, or heterogeneous returns.
Verified anchors used for this ranking include the CFPS official introduction, ICPSR CFPS study page, Ren and Zhu’s 2024 age-based digital divide study, Yu et al.’s 2026 CFPS financial-vulnerability study, and He et al.’s 2019 WeChat rumor study.
Appendix B — scholar-brainstorm Long-Form Report (full)
File: output/digital-divide-china-cfps/ scholar-brainstorm- digital-divide-china-cfps-top5-2026-05-05.md. Generated 2026-05-05. Includes operating mode, material summary, variable inventory, thematic clusters, candidate RQs, scored shortlist, top-5 detail, evaluation panel, research program overview, and citation verification.
Scholar Brainstorm: Top 5 Research Questions on the Digital Divide in China
Generated by /scholar-brainstorm on 2026-05-05 Operating mode: MATERIALS
Operating Mode
Input path: materials/
Classification: MATERIALS mode. The directory contains CFPS questionnaires, technical reports, one cross-year codebook workbook, and one CFPS literature workbook. It does not contain raw analytic data files supplied for this invocation, so empirical signal tests were skipped.
Safety status: N/A - no raw data file was read into model context.
Material Summary
| Field | Value |
|---|---|
| Dataset family | China Family Panel Studies (CFPS) |
| Material type | Questionnaires plus codebook/literature workbook |
| Unit of analysis | Individual, household, family, and community |
| Temporal coverage in materials | 2010, 2012, 2014, 2016, 2018, 2020 |
| Design | Nationally representative longitudinal panel; CFPS is described by ISSS as a biennial longitudinal survey launched in 2010 |
| Sampling note | ICPSR describes 16,000 target households in 25 provincial-level regions, representing about 95% of China’s population, with individual, household, and community units |
| Codebook note | CFPS 2018 codebook.xlsx is CFPS2018crossyearid_202104, N = 74,130, 95 cross-year variables |
| Key limitation | This run used questionnaires/codebooks only; ranking is theory and measurement based, not based on estimated effects |
Sources verified: CFPS official introduction, ICPSR CFPS study page.
Variable Inventory
####### Digital Access and Use
- Mobile phone use and costs:
U1/U1M,U102,U102A. - Mobile internet and computer internet:
U201,U202; 2020 adds daily mobile and computer internet minutes,U201A,U202A. - General internet frequency and breadth:
U701learning,U702work,U703social,U704entertainment,U705commercial activity; 2018/2016 includeU250Mweekly leisure internet hours. - Digital consumption and leisure:
U7051online shopping expenditure,U91online games,U92online shopping,U93short video/live streaming,U94online learning. - Platform and information items:
U11WeChat use,U111WeChat Moments sharing,U13trust WeChat Moments vs official media when conflicting,U802internet as information channel,N202online political-news exposure. - Privacy and data governance:
U110privacy leakage concern,U121government personal-data collection acceptance,U122gene-company/law-enforcement data sharing,U123health-app data sharing. These 2020 items are marked in the questionnaire as general restricted data. - Labor-market digitalization:
G19computer required at work,COVID5remote work during Feb-Mar 2020,G603phone always-on requirement. - Education digitalization:
COVID3online learning time, school online-teaching adoption, online/offline tutoring indicators and spending.
####### Outcomes and Moderators
- Labor outcomes: employment, job class, work hours, work income
G11/G12/generatedIncome, job security, insurance, workplace. - Education outcomes: study time, tutoring participation/time/spending, education spending, aspirations, school type and education history.
- Health and well-being: self-rated health, mental health modules, sleep, health behavior, happiness
M2016, social relationsM2011. - Social capital and trust: contact frequency with kin, online-to-offline tie formation
U601-U603, generalized trustN1001, specific trust batteries. - Stratifiers: hukou
HK10-HK18and 2020A301, rural/urban residence, birth cohort, gender, education, income, household composition, co-resident children/young adults, province and community context.
Star variables:
U201plusU202- separates mobile-only access from computer-enabled access.U701-U705- separates productive use from leisure/social/commercial use.COVID5- captures an exogenous pandemic-period need for remote work.COVID3plus tutoring/spending items - captures school closure online-learning adaptation.U13,U110-U123- unusually strong measures for information trust, privacy concern, and data-governance attitudes.- CFPS panel identifiers and cross-wave hukou/education/employment variables - allow longitudinal stratification designs.
Thematic Clusters
| Cluster | Core variables | Main role |
|---|---|---|
| Access ladder | U201, U202, U201A, U202A | X/Y |
| Productive use | U701, U702, U705, U250M, G19 | X/M/Y |
| Digital leisure | U91, U93, U704 | X/M |
| Online education | COVID3, U94, tutoring and education-spending items | X/Y/M |
| Digital labor market | COVID5, G19, G11, G12, Income, G603 | X/Y |
| Social networks and trust | U11, U111, U601-U603, N1001, M2011 | X/M/Y |
| Information governance | U13, U110-U123, N202, U802 | X/Y |
| Stratification axes | hukou, rural/urban, cohort, gender, education, household composition | W/C |
Candidate Research Questions
| # | Candidate RQ | Strategy | Data readiness |
|---|---|---|---|
| 1 | As internet access expands, do hukou and cohort still stratify productive internet use and use intensity? | Temporal/change | High |
| 2 | Does mobile-only access versus computer access predict who could work remotely and avoid income loss during COVID-19? | Gap-driven | High |
| 3 | Did online learning during COVID-19 widen rural-urban and parental-education gaps in study time, tutoring, and educational aspirations? | Outcome-driven | High |
| 4 | Among older adults, does internet use improve health, happiness, and social connectedness, and for whom? | Mechanism | Medium-high |
| 5 | Does reliance on WeChat/short video/online news reshape information trust, privacy concern, and institutional trust differently by age, education, and hukou? | Gap-driven | Medium-high |
| 6 | Does commercial internet use and online shopping reduce household financial vulnerability or deepen consumption/credit risk? | Mechanism | Medium |
| 7 | Does social internet use substitute for or complement offline kin contact and friendship networks? | Mechanism | Medium |
| 8 | Does computer use at work generate wage returns independent of education and occupation? | X-first | Medium |
| 9 | Are women, rural residents, and older cohorts concentrated in low-return forms of digital use? | Heterogeneity | High |
| 10 | Does co-residence with digitally skilled children or young adults reduce older adults’ digital exclusion? | Mechanism | Medium |
| 11 | Does internet use for political information alter generalized trust or local-government trust? | Gap-driven | Medium |
| 12 | Does online dating or online spouse meeting change assortative mating patterns? | X-first | Medium |
| 13 | Is mobile-phone spending a financial burden among low-income households or a bridge to opportunity? | Decomposition | Medium |
| 14 | Do short-video and online-game use displace study/work time differently across youth social class? | Heterogeneity | Medium |
| 15 | Does online learning frequency predict adult skill upgrading and later labor-market mobility? | Temporal/change | Medium |
Empirical Signal Table
Skipped - MATERIALS mode. No raw data files were provided in this invocation. Ranking uses 5 criteria: novelty, data readiness, theoretical significance, identification strength, and publication potential.
Literature Scan
Local library search was attempted first through the scholar reference-manager layer, but the command stalled while repeatedly loading the knowledge graph and did not return a usable citation list. The command was interrupted with pkill -f scholar_search. The following anchor sources were then verified via primary publisher pages, PubMed/PMC metadata snippets, or official data pages:
- CFPS is suitable for longitudinal individual, household, and community analysis, with broad modules on economy, education, family, migration, and health: ISSS CFPS introduction, ICPSR CFPS page.
- Ren and Zhu’s 2024 Telecommunications Policy article uses CFPS 2010-2020 to study age-based digital divides in perceived importance, access, and learning-oriented use: ScienceDirect DOI page.
- Yu, Li, Guo, and He’s 2026 PLOS One article uses CFPS 2016, 2018, and 2020 to link internet use to household financial vulnerability and mechanisms through income, wealth, and risk management: PLOS One.
- Guo and Wan’s 2022 Technology in Society article and Zhao et al.’s 2022 Computers in Human Behavior article document digital divides in online learning during COVID-19 using student surveys, not CFPS: PMC metadata for Guo and Wan, PMC metadata for Zhao et al..
- Zhou, Bai, and Wang’s 2024 BMC Public Health article uses CFPS 2014-2020 to study internet use and older-adult health with fixed effects and IV approaches: BMC Public Health.
- Cui et al.’s 2024 BMC Public Health article uses 2020 CFPS to connect cultural capital, digital divide, cognitive ability, and older-adult health: BMC Public Health.
- He et al.’s 2019 Sage Open article studies WeChat use and online rumor transmission among younger and older Chinese adults: Sage Open.
Novelty assessment: RQ1 is already close to an existing project in this workspace but remains the strongest general article frame. RQ2 and RQ5 are more distinctive because the 2020 CFPS items provide pandemic remote-work and information-governance hooks that are less common in standard digital-divide papers. RQ3 is topical but faces heavier competition from COVID online-learning survey studies. RQ4 is viable but overlaps with several 2024 CFPS older-adult health papers, so it needs a sharper mechanism or subgroup contribution.
Top 5 Shortlist
| Rank | RQ short label | Novelty | Data ready | Theory | ID strength | Publication potential | Score |
|---|---|---|---|---|---|---|---|
| 1 | Access convergence, use divergence | 4.5 | 5.0 | 5.0 | 4.0 | 5.0 | 4.75 |
| 2 | Remote-work divide during COVID | 4.5 | 4.5 | 4.5 | 4.0 | 4.5 | 4.45 |
| 3 | Online-learning outcome divide | 3.8 | 4.5 | 4.5 | 3.8 | 4.5 | 4.22 |
| 4 | Older-adult digital health divide | 3.5 | 4.0 | 4.2 | 3.8 | 4.0 | 3.90 |
| 5 | Information trust and privacy divide | 4.2 | 3.8 | 4.2 | 3.2 | 4.0 | 3.88 |
Weights: novelty 25%, data readiness 25%, theoretical significance 20%, identification strength 15%, publication potential 15%.
Final Top 5 Research Questions
####### 1. Access Convergence, Use Divergence
RQ: In China from 2010 to 2020, did the hukou, education, and cohort gaps in internet access narrow while gaps in productive use, use intensity, and use breadth persisted or widened?
Variables: X = hukou, education, cohort, rural/urban residence, gender; Y = access (U201, U202 and wave equivalents), weekly use intensity (U250M/wave equivalents where comparable), use breadth (U701-U705); M = occupation/digital work exposure, co-resident young adults; C = income, province, household composition.
Theoretical puzzle: The first-level access gap can close without equalizing second-level uses. This is the cleanest CFPS contribution because the panel spans the access-saturation period and can distinguish access convergence from use-return stratification.
Identification strategy: Descriptive-explanatory panel models with wave fixed effects, province or province-by-wave controls, individual fixed effects for within-person change where feasible, and Oaxaca/Kitagawa decomposition of rural-hukou or cohort gaps.
Closest prior work: Ren and Zhu (2024) study age-based digital divides with CFPS; this RQ broadens the stratification axis to hukou and cohort and explicitly separates access from use intensity and breadth.
Verdict: PROCEED. Best all-purpose article frame.
####### 2. Remote-Work Divide During COVID-19
RQ: Did mobile-only internet access, computer internet access, and job-level computer requirements determine who could shift to remote work during the February-March 2020 COVID shock, and did this protect workers from income loss?
Variables: X = U201 mobile internet, U202 computer internet, U201A/U202A minutes, G19 computer required at work; M = COVID5 remote-work mode; Y = COVID4 work-time change, COVID601 income change, COVID602 income-change percentage, G11/G12 income; W = occupation, hukou, gender, education.
Theoretical puzzle: Remote work is not just a labor-market institution; it is a third-level digital-divide conversion problem. Those with better digital capital could convert access into resilience during a shock.
Identification strategy: Restrict to employed respondents in 2020; estimate remote-work uptake and income-loss models by device access and computer-required job, with occupation, industry, province, and pre-pandemic job controls where available. Avoid strong causal language unless pre-2020 digital-use histories are merged.
Closest prior work: Yu et al. (2026) link CFPS internet use to financial vulnerability; this RQ focuses on the pandemic labor-market shock and device/job compatibility rather than household finance overall.
Verdict: PROCEED. Strong and timely if 2020 work items are available in the analytic data.
####### 3. Online-Learning Outcome Divide
RQ: During the COVID-19 school closure period, did rural/hukou and parental-education differences in device access and online-learning intensity translate into unequal study time, tutoring participation, education spending, and educational aspirations?
Variables: X = household digital access, COVID3 online learning hours, U94 online learning, device access, parental education/income, hukou; Y = study time, tutoring participation/time/spending, education spending, educational aspirations; W = school level, rural/urban, grade, gender.
Theoretical puzzle: Online schooling can equalize instruction access in theory but widen learning outcomes when households differ in devices, parental support, and paid supplementary education.
Identification strategy: Student/child subsample, 2020 cross-sectional models plus pre-2020 baseline controls if linked; decompose rural-urban or parental-education gaps into device/online-learning exposure, tutoring, and household-resource components.
Closest prior work: Guo and Wan (2022) and Zhao et al. (2022) document online-learning digital divides with specialized student surveys. CFPS adds household, parent, and expenditure modules in a national panel setting.
Verdict: PROCEED with a narrow contribution statement. Competition is heavy, but CFPS household linkage is valuable.
####### 4. Older-Adult Digital Health and Social-Connection Divide
RQ: Among adults aged 60+, does internet use improve self-rated health, mental health, happiness, and social connectedness, and are benefits concentrated among urban, educated, or co-resident-with-younger-family older adults?
Variables: X = internet access/use frequency, U701 learning, U703 social use, U802 internet as information channel, U11 WeChat; M = health information acquisition, social contact, co-resident young adults; Y = self-rated health, mental health, happiness M2016, social relations M2011; W = education, hukou, gender, living arrangement.
Theoretical puzzle: Digital inclusion may be health-promoting for older adults, but third-level returns likely depend on cultural capital and family support.
Identification strategy: 2014-2020 older-adult panel with fixed effects, lagged internet use where possible, mechanism models for social interaction and health information, and heterogeneity by hukou/education/living arrangement.
Closest prior work: Zhou, Bai, and Wang (2024) and Cui et al. (2024) already use CFPS for older-adult health and digital divide. This RQ needs sharper novelty, for example family spillovers or type-of-use heterogeneity.
Verdict: REVISE before full paper. Promising, but not the most novel unless reframed around household digital transmission.
####### 5. Information Trust, Privacy Concern, and Platform Dependence
RQ: Does dependence on WeChat, short video, and online news create unequal information trust and privacy/data-governance attitudes across age, education, and hukou groups?
Variables: X = U11 WeChat use, U111 sharing frequency, U93 short video/live streaming, N202 online political-news days, U802 internet as information source; Y = U13 WeChat-vs-official-media trust, U110 privacy leakage concern, U121-U123 data-sharing acceptance, generalized trust N1001; W = age/cohort, education, hukou, gender.
Theoretical puzzle: Digital inequality is not only unequal access to tools; it is unequal exposure to platform-mediated authority, misinformation, and data-governance tradeoffs.
Identification strategy: 2020 cross-sectional models with rich controls; stratified models by age and education; latent-class or typology analysis of platform dependence and privacy/trust attitudes. Treat restricted-data access as a feasibility gate.
Closest prior work: He et al. (2019) show age differences in WeChat-rumor pathways; CFPS 2020 offers national social-survey measures of platform use, official-media trust, and privacy/data-governance attitudes.
Verdict: PROCEED as a distinctive side paper if restricted items can be accessed.
Evaluation Panel Summary
Because this environment’s sub-agent policy does not allow spawning evaluator agents unless the user explicitly requests delegation, I used a structured internal panel rubric rather than live parallel agents.
| RQ | Theorist | Methodologist | Domain fit | Editor | Devil’s advocate | Consensus |
|---|---|---|---|---|---|---|
| 1 | Strong | Strong | Strong | Strong | Viable | Best flagship |
| 2 | Strong | Adequate-strong | Strong | Strong | Viable | Best timely paper |
| 3 | Strong | Adequate | Adequate-strong | Adequate | At risk: crowded field | Viable if household linkage is foregrounded |
| 4 | Adequate | Adequate | Adequate | Adequate | At risk: CFPS overlap | Needs sharper mechanism |
| 5 | Strong | Adequate | Strong | Adequate-strong | At risk: restricted variables and cross-section | Distinctive but data-access dependent |
Cross-cutting risks:
- Do not call cross-sectional associations causal without pre-treatment or panel leverage.
- Do not mix 2014/2016/2018
U250Mweekly hours with 2020 daily device minutes without a harmonization decision. - Treat 2020 privacy/trust variables as restricted-data items.
- For online learning, clearly separate student outcomes from household-resource mechanisms.
Research Program Overview
The strongest program is a three-paper sequence:
- Flagship stratification paper: access convergence versus productive-use divergence by hukou/cohort.
- Shock paper: remote-work conversion of digital capital during COVID-19.
- Platform-trust paper: information trust and privacy concern in the mature mobile-platform environment.
| Category | RQs | Rationale |
|---|---|---|
| Quick wins | 1, 2 | Clear variable hooks and strong sociological framing |
| Medium projects | 3, 5 | Need careful sample restrictions or restricted-data access |
| Deep investment | 4 | Valuable but crowded; needs a novel mechanism such as household digital transmission |
Recommended next step: develop RQ1 as the main paper, keep RQ2 as the strongest alternative if the user wants a COVID-labor angle, and reserve RQ5 for a high-novelty side project if restricted 2020 items are accessible.
Citation Verification
Verification level: STANDARD workaround. Local library search was attempted first but did not complete. All named references in this report are linked to publisher, official, ICPSR, PubMed/PMC, or open journal pages. No unverified named citation is used as evidentiary support.
Appendix C — scholar-idea Memo (full)
File: output/digital-divide-china-cfps/ scholar-idea- digital-divide-china-cfps-2026-05-04.md. Generated 2026-05-04.
Scholar Idea — Determinants of the Digital Divide in China (CFPS)
- Date: 2026-05-04
- Project slug: digital-divide-china-cfps
- Target journal: Social Forces
- Method orientation: quantitative; longitudinal panel
- Data: China Family Panel Studies (CFPS) waves 2010, 2012, 2014, 2016, 2018, 2020
Step 1 — The Puzzle
China entered 2024 with the world’s largest internet user base (1.07 billion CNNIC) and a rapidly maturing mobile-payment, super-app ecosystem. Yet the country remains a textbook case of layered digital inequality. The first-order access gap (Have-Have Not internet) has narrowed sharply since 2015, but second-order (skill, autonomy of use) and third-order (returns to use) gaps appear to have widened — particularly along hukou (urban-rural household registration), generational, gender, and educational lines. Existing accounts treat these gaps as residuals of broader stratification (Wei and Zhang 2008; Cheng et al. 2021). What is missing is a longitudinal, mechanism-decomposed account that asks how changing socioeconomic, household, and institutional conditions translate into changing digital engagement across an unusually heterogeneous population. CFPS — the only nationally representative longitudinal social-survey panel in China — is the appropriate instrument because it tracks the same individuals across the access-saturation transition (2010 ≈ 34 % internet penetration; 2020 ≈ 70 %).
The puzzle for Social Forces: the population-level access gap appears to converge while individual-level use intensity and use breadth — what we treat as the second-level divide — diverge. We need a stratification account that can carry both moments simultaneously. Standard cross-sectional ladder-of-internet-use frameworks (van Deursen and Helsper 2015) cannot.
Step 2 — Candidate Angles
| # | Framing | Mechanism | Rival explanation | Data hook |
|---|---|---|---|---|
| A | Hukou as a durable digital-stratification axis even after access converges | Institutional sorting → differential infrastructure, education, occupational exposure | Pure SES (income/education) absorbs hukou | CFPS hukou + city-level access controls |
| B | Cohort-as-cause: the digital divide tracks generational replacement, not learning | Birth-cohort socialization fixes a “digital lifeworld” | Period (year) effects from infrastructure dominate | CFPS 2010-2020 + APC decomposition |
| C | The household as a digital-skill production unit: intra-household spillovers | Co-resident young adults / children mediate older members’ use | Selection (digital households form together) | CFPS family-conf links + intra-household FE |
| D | Gender × age intersection: the elderly-rural-female “triple penalty” | Compounding of lifecourse, residence, and gender norms | Additive (no interaction) | CFPS interaction tests + decomposition |
| E | Returns to digital engagement (third-level) — does use translate to wages, networks, well-being differently by SES? | Capital-conversion (Bourdieu): digital use must convert into other capitals | Equal returns; gap is just “more use” | CFPS income, social-network, mental-health modules |
Angles A, B, and D are most tractable in CFPS. Angle E is appealing but introduces a second causal claim beyond the orchestrator’s scope (digital → outcomes); we therefore route it to robustness/discussion rather than the focal RQ.
Step 3 — Selected Research Question
Focal RQ. In China between 2010 and 2020, what are the structural, institutional, and household-level determinants of the digital divide, and to what extent do (i) hukou and (ii) cohort persist as independent stratifying axes after socioeconomic resources, household composition, and regional infrastructure are accounted for?
The focal question subsumes Angles A and B and folds D into a moderation test. We treat the digital divide as a two-level construct following van Deursen, Helsper, and Eynon (2016):
- Access (Y1): any internet use in the wave (binary).
- Use intensity (Y2): weekly hours of internet use, conditional on access. We additionally examine breadth (Y3): count of distinct activity domains (study, work, entertainment, social, commerce) in waves where the variable is consistently asked.
Step 4 — Variable Map
| Role | Concept | CFPS operationalization |
|---|---|---|
| Y1 | Internet access | qu701 / kn401 / wave-equivalent any-use indicator |
| Y2 | Use intensity | weekly hours of leisure + study + work internet use |
| Y3 | Use breadth | count of activity-domain “yes” indicators (where collected) |
| X1 | Hukou type | agricultural / non-agricultural / change-status |
| X2 | Cohort | birth-year, banded to 5 cohorts |
| X3 | Education | completed years of schooling |
| X4 | Income (log per-capita household) | family-level income / household size |
| X5 | Gender | male / female |
| M1 | Household composition | presence of co-resident young adult (16–35) |
| M2 | Occupation exposure | non-manual / digital-intensive vs. manual / agricultural |
| W (region) | Province + urbanicity | province FE, urban/rural classification |
| W (period) | Wave year | year FE / linear trend interactions |
| C (controls) | Marital status, household size, health (SF-12 short) | direct CFPS items |
Step 5 — Hypotheses
- H1 (hukou persistence). Net of X3, X4, and regional infrastructure, agricultural-hukou status reduces the probability of access (Y1) and weekly use hours (Y2). The hukou effect on Y1 narrows across waves (access convergence) but the hukou effect on Y2 does not (skill-use divergence).
- H2 (cohort layering). Birth cohorts post-1985 show systematically higher Y1 and Y2 net of period and age. Within cohort, the age trajectory of Y2 is flat — i.e., the divide tracks cohort replacement, not within-person learning.
- H3 (intersectional triple penalty). A three-way interaction (rural-hukou × female × born ≤ 1965) yields a use-intensity penalty larger than the sum of the three additive marginal effects. The Oaxaca-style decomposition identifies endowments vs. coefficients sources of this gap.
- H4 (household spillover, secondary). Co-residence with at least one digital-native (born ≥ 1990) is associated with higher Y1 and Y2 for older members; the spillover is stronger for women and rural residents (consistent with intra-household compensatory transmission).
Step 6 — Feasibility / Novelty Screen
| Dimension | Assessment | Notes |
|---|---|---|
| Theoretical | STRONG | Adds longitudinal evidence to the layered-divide literature (van Dijk 2020; Hargittai 2002; Helsper 2012) and to the Chinese stratification debate over hukou’s “durability” (Cheng & Selden 1994; Wu & Treiman 2004; Xie & Jin 2015). |
| Data | STRONG | CFPS is the canonical instrument; six waves cover the access-saturation transition. |
| Identification | MODERATE | Causal claims are limited; we lean on within-person FE for X3/income, age × period × cohort decomposition, and rich controls. The paper is descriptive-explanatory rather than causal — appropriate for Social Forces. |
| Publication fit | STRONG | Social Forces welcomes Chinese-context stratification papers (e.g., Xie & Jin 2015, Cheng et al. 2021) and accepts descriptive-decomposition contributions when theoretical stakes are high. |
| Risk | MODERATE | Survey-mode change (CAPI vs. PAPI) and item-wording shifts across waves require careful harmonization. The 2014/2016 Internet module is the cleanest core. |
Step 7 — Bottom Line
We carry forward Angles A + B + D as a single integrated paper: a six-wave panel description + decomposition of the digital divide in China, with (i) hukou and (ii) cohort as the focal stratification axes and an explicit two-level (access × intensity) outcome structure.
Provenance
- Generated under
/scholar-full-paperorchestration, Phase 0. - Phase 0-PRE excused (user provided clear RQ).
- Local library, scholar-knowledge graph, and CrossRef will be queried in Phase 2 (lit review). All citations above are placeholders to be verified at that stage and are marked
[CITATION NEEDED — verify]if unresolved.
[CITATION NEEDED — verify] Wei & Zhang 2008; Cheng et al. 2021; van Deursen & Helsper 2015; van Deursen, Helsper & Eynon 2016; van Dijk 2020; Hargittai 2002; Helsper 2012; Cheng & Selden 1994; Wu & Treiman 2004; Xie & Jin 2015.
Appendix D — scholar-design Blueprint (full)
File: output/digital-divide-china-cfps/ design/ design-blueprint-digital-divide-china-cfps-2026-05-04.md. Generated 2026-05-04. Locks the focal outcome, model ladder, hypotheses, IPW strategy, and pre-analysis plan.
Design Blueprint — Determinants of the Digital Divide in China (CFPS)
- Project slug: digital-divide-china-cfps
- Date: 2026-05-04
- Phase: 3 (Identification + Design)
- Target journal: Social Forces
- Design family: descriptive / decomposition (longitudinal panel)
- Data: China Family Panel Studies (CFPS) waves 2010, 2012, 2014, 2016, 2018, 2020
- Inputs read:
idea/scholar-idea-digital-divide-china-cfps-2026-05-04.md;drafts/scholar-lrh-digital-divide-china-cfps-2026-05-04.md;design/project-brief.md;logs/project-state.mdoutcome_mechanism_alignment: prevalence-stock
The outcomes are population-level stock measures of digital engagement in the wave (Y1: any internet use; Y2: weekly hours of use; Y3: breadth of activity domains) rather than transitions into a state, exits, or multi-state spells. The mechanism inventory (institutional sorting via hukou; cohort socialization via adolescent digital lifeworld; resource and household mediators) targets the prevalence of digital engagement at each wave, and the focal estimands are gap magnitudes, gap trajectories across waves, and decomposition shares of those stocks.
0. Headline finding (focal-outcome commitment, locked at Phase 3.5)
In response to the Phase 3.5 senior-reviewer pre-mortem, this design commits to Y2 (weekly hours of internet use among users) as the focal outcome for the headline table and abstract sentence. Y1 (access) and Y3 (breadth) are reported alongside but secondary. The pre-registered abstract-target sentence is:
Net of education, income, occupation, household composition, and province × wave fixed effects, the rural-hukou penalty on weekly internet hours among Chinese adults who use the internet (Y2, observed in CFPS 2014–2018) is no smaller at the end of the Y2 observation window than at the start, even as the binary access gap (Y1, observed across CFPS 2010–2020) closed from approximately 40 to 15 percentage points; bounded age–period–cohort decomposition attributes the population-level rise in use intensity principally to cohort replacement rather than within-person learning; and the joint penalty for the rural × female × pre-1965 cell exceeds the additive sum of its three marginal components, with both endowment and coefficient-residual sources non-zero.
The focal table is Table 2: M3 (Y2) with hukou × wave interactions; the focal robustness is R5 (three-way interaction). H1, H2, and H3 each contribute one clause to the abstract. H4 (household spillover) is demoted to a discussion-section pointer.
1. Identification Strategy
This is an explicitly descriptive-decomposition design, not a causal RCT. The hypotheses (H1–H4) make population-level claims about the structure of variation in digital outcomes — gap magnitudes, gap trajectories, decomposition shares, intersectional excess — rather than counterfactual treatment effects on a single intervention. We follow the Social Forces tradition in which descriptive contributions earn publication when (a) the descriptive object is theoretically novel, (b) rival mechanism accounts are operationalized as competing specifications, and (c) the identifying restrictions for any model with non-trivial identification problems (here APC) are explicit and tested for sensitivity.
####### 1.1 Estimation strategies in correspondence with hypotheses
| H | Substantive claim | Estimator | Identifying assumption |
|---|---|---|---|
| H1 (hukou persistence; access vs. intensity divergence) | Hukou coefficient on Y1 narrows across waves; coefficient on Y2 does not. | Pooled cross-sectional logit (Y1) and OLS with province × wave fixed effects on Y2 conditional on Y1=1 (focal), with Tobit MLE as cross-check; hukou-by-wave interaction tested for monotonicity. | Conditional independence of hukou and unmeasured infrastructure within province × wave cell, given controls. |
| H2 (cohort layering, not within-person learning) | Y2 increase across waves is carried by cohort replacement, not within-person change. | (a) Person fixed-effects within-changes for X3 (education) and X4 (income) and for the within-person age trajectory of Y2 — exploits within-person variation; (b) Hierarchical APC (Yang & Land 2006, 2013) with cohort and period as random effects and age as fixed-effect polynomial; (c) Deaton–Paxson identifying restriction (Deaton 1997: period effects sum to zero and orthogonal to time trend) reported as bounds. | HAPC: cohort and period random effects are exchangeable conditional on age. Deaton–Paxson: period effects average to zero over the observation window. We report both as bounds on the cohort share rather than a point estimate. |
| H3 (intersectional triple penalty) | Joint condition (rural × female × born ≤ 1965) yields a Y2 penalty exceeding the additive sum of three marginal effects, with both endowment and coefficient components. | (a) Three-way interaction term in the M3 spec; (b) Threefold Oaxaca–Blinder decomposition of the rural-urban Y2 gap (endowments / coefficients / interaction), separately for the focal subgroup and pooled. | Common support of the covariate distributions across groups (verified in EDA); linearity of the conditional expectation function within group. |
| H4 (household spillover) | Co-residence with a digital-native (born ≥ 1990) raises Y1 and Y2 of older co-residents, more for women and rural residents. | Person FE on the subset who experience within-person change in co-residence status across waves. | Within-person co-residence change is not driven by a third unmeasured time-varying confounder of digital use (e.g., simultaneous purchase of a smartphone). Sensitivity: lagged co-residence; balance check on observed time-varying covariates. |
####### 1.2 Sensitivity to inverse-probability-of-attrition weights (IPW)
Panel attrition in CFPS is selective on age, urbanicity, and (potentially) digital adoption itself. We construct Wooldridge (2007) inverse-probability-of-attrition weights by estimating, at each wave t > 2010, a logit of the indicator for non-attrition at t against wave-(t−1) covariates including baseline Y1, hukou, age, education, income, province, household size, and self-rated health. Reciprocal predicted probabilities are multiplied across waves to yield cumulative attrition weights, and combined with the CFPS design weights for a final analytic weight. We report focal models unweighted, design-weighted, and IPW × design-weighted side-by-side; substantive divergence between specifications is flagged and discussed.
####### 1.3 What we explicitly do NOT claim
- No causal interpretation of hukou: hukou status is largely assigned at birth and rarely changed; we cannot run a hukou “treatment” design. We claim only that net of resource and household mechanisms, hukou marks a durable structuring axis of digital outcomes.
- No causal interpretation of cohort: APC is non-identified without restriction; we use HAPC and Deaton–Paxson as bounds.
- No third-level (returns) claim: the third-level digital divide (Angle E in the idea file) is held in robustness/discussion only.
2. DAG
The DAG below shows the assumed causal structure among the key variables. Solid arrows mark associations we estimate or decompose; dashed arrows mark covariate-controlled paths held constant in the focal specs. Cohort and hukou are exogenous in the model: hukou is assigned at birth and seldom changes, cohort is birth year. Province × wave fixed effects sweep regional infrastructure (W) and period shocks.
flowchart LR
C[Cohort / birth year]
H[Hukou X1]
E[Education X3]
I[Income X4]
G[Gender X5]
HH[Household composition M1]
O[Occupation M2]
W[Province x Wave FE / infrastructure]
Y1[Y1 Internet access]
Y2[Y2 Use intensity]
Y3[Y3 Use breadth]
C ==> Y1
C ==> Y2
C ==> Y3
H ==> Y1
H ==> Y2
H ==> Y3
H --> E
H --> I
H --> O
C --> E
E ==> Y2
I ==> Y2
O ==> Y2
G --> Y1
G --> Y2
G -.-> HH
HH ==> Y2
W -.-> Y1
W -.-> Y2
Y1 --> Y2
Y1 --> Y3
Reading the DAG.
- Bold double-arrows (
==>) are the focal estimands: cohort → Y, hukou → Y (H1, H2); HH → Y2 (H4); and the SES mechanisms (E, I, O → Y2) that compete with the institutional account. - Single arrows from H to {E, I, O} encode the institutional-sorting chain that motivates why we report both the unconditional and the SES-conditioned hukou coefficients: the unconditional captures total association; the conditioned captures the residual institutional component net of resource mediators (a “net effect of hukou” interpretation, Wu & Treiman 2004).
- Dashed arrows (
-.->) are covariate adjustments absorbed by province × wave FE (for W) or held as controls (for HH in the M1/M2 → M3 ladder). - The Y1 → Y2 / Y3 arrows make explicit that intensity and breadth are observed only conditional on access; we handle this with OLS+FE (focal) plus a Tobit MLE cross-check for Y2 and zero-inflated specifications for Y3 (rather than naive listwise deletion), and report sample-selection sensitivity (Heckman with hukou × wave as exclusion candidate).
3. Spec Ladder
Three core specs per outcome (M1–M3), plus six robustness specs (R1–R6). The full ladder will be encoded in design/spec-registry.csv at Phase 5.
####### 3.1 Core ladder (per outcome Y1, Y2, Y3)
| Spec ID | Name | RHS | FE | Estimator | Purpose |
|---|---|---|---|---|---|
| M1 | Demographics-only | hukou + cohort + age + age² + gender | wave FE | logit (Y1) / OLS+FE (Y2, Tobit cross-check) / NB (Y3) | Baseline gap magnitudes; total association of hukou and cohort. |
| M2 | + SES | M1 + education years + log per-capita household income + occupation (3-cat) | wave FE | logit / OLS+FE (Tobit cross-check) / NB | Resource-mechanism control; tests whether SES absorbs hukou and cohort coefficients (rival to institutional account). |
| M3 (focal) | + Household + Province×Wave FE | M2 + household size + co-resident young adult (16–35) + marital status + self-rated health | province × wave FE | logit / OLS+FE (Tobit cross-check) / NB | The headline specification reported in the main text; institutional-sorting test (H1); supports H4 via co-residence term. |
####### 3.2 Robustness ladder
| Spec ID | Name | Difference from M3 | Hypothesis served |
|---|---|---|---|
| R1 | Person FE | Add individual fixed effects; identifies X3, X4, HH, age trajectory off within-person variation | H2 within-person trajectory; H4 spillover identification |
| R2 | IPW × design weights | M3 with cumulative inverse-probability-of-attrition × CFPS design weights | All — robustness to selective attrition |
| R3 | HAPC | Hierarchical APC: age FE, cohort & period as random effects | H2 (cohort vs period decomposition) |
| R4a | Deaton–Paxson APC | M3 with Deaton–Paxson identifying restriction on period effects | H2 (cohort share lower bound) |
| R4b | Threefold Oaxaca–Blinder | Decomposition of rural-urban Y2 gap into endowments / coefficients / interaction | H3 (intersectional decomposition) |
| R5 | Gender × hukou × cohort interaction | M3 with three-way interaction term | H3 (triple-penalty supra-additivity) |
| R6 | 2014–2020 stable-core sub-period | M3 restricted to waves with harmonized internet module | All — item-wording-shift sensitivity |
Focal spec IDs (registered for Phase 5 design-promise audit): Y1.M3, Y2.M3, Y3.M3, Y2.R1 (person FE), Y2.R3 (HAPC), Y2.R4b (Oaxaca), Y2.R5 (three-way interaction), Y1.R6 and Y2.R6 (stable-core sensitivity).
4. Power / Minimum-Detectable-Effect Note
CFPS adult sample sizes are roughly 30,000–50,000 person-waves per wave; pooled across six waves the analytic file approaches 200,000 person-waves (≈ 30,000 unique respondents observed multiply). Trivial power exists for main effects and two-way interactions: at α = 0.05 and 80% power, OLS+FE on Y2 (and its Tobit MLE cross-check) with N ≈ 200,000 detects standardized coefficients on the order of β ≈ 0.01–0.02.
The binding power case is H3’s three-way interaction (rural × female × born ≤ 1965). The implied cell — rural-hukou, female, born on or before 1965 — represents roughly 7–9 % of person-waves (rural ≈ 50%, female ≈ 50%, pre-1965 cohort ≈ 30–40% conditional on adult sampling), i.e. n ≈ 14,000–18,000 person-waves. Conservatively assuming clustering at the household level inflates standard errors by a design effect of ≈ 1.5, the MDE for the three-way interaction term on Y2 (weekly hours) is approximately 0.6–0.9 hours/week, or about a 10–15% departure from the additive prediction. This is well within the magnitudes reported in adjacent literature (Friemel 2016; Ma et al. 2024). For Y1 (probability of access), the same cell yields an MDE of approximately 2–3 percentage points on the interaction.
We will recompute these MDEs against the realized sample after Phase 4 (data plan) and Phase 5 (EDA), and report them in the Methods section.
5. Promised Analyses Checklist (for Phase 5 design-promise audit)
The following analyses are promised and will be checked against by design-promise-check.sh at Phase 5:
- M1 (demographics only) for each of Y1, Y2, Y3 — main + table.
- M2 (+ SES) for each of Y1, Y2, Y3 — main + table.
- M3 (+ household + province × wave FE) for each of Y1, Y2, Y3 — main + table; focal specification.
- Hukou × wave interaction term in M3 for Y1 and Y2, with monotonicity test for H1 access-intensity divergence.
- R1 (person FE) for Y2 — identifies within-person trajectory of use intensity.
- R2 (IPW × design weights) for Y1.M3 and Y2.M3 — attrition robustness.
- R3 (HAPC) for Y2 — cohort vs. period decomposition.
- R4a (Deaton–Paxson) for Y2 — bounds on cohort share.
- R4b (threefold Oaxaca–Blinder decomposition) of the rural-urban Y2 gap — endowments / coefficients / interaction.
- R5 (three-way rural × female × pre-1965 interaction) on Y2 — supra-additivity test for H3.
- R6 (2014–2020 stable-core sub-period) for Y1.M3 and Y2.M3 — item-wording-shift robustness.
- H4 secondary test: co-resident digital-native term in M3 and R1 for Y2; gender × co-residence and rural × co-residence interactions reported.
- Multiple-testing correction: Benjamini–Hochberg FDR control across the focal hypothesis-test family (H1a/H1b, H2, H3, H4) at q = 0.05.
- Power / MDE table re-computed against realized analytic sample.
- Sample-selection sensitivity: Heckman two-step for Y2 conditional on Y1.
6. Limitations and Threats to Validity
- APC identifiability. The age-period-cohort identification problem is fundamental. We mitigate with HAPC + Deaton–Paxson as bounds rather than a point estimate; we report the cohort share of variation in Y2 as an interval.
- Item / mode-shift bias. The internet-use battery changes across waves (CAPI/PAPI in 2014; new app-domain breadth items in 2016); R6 (stable-core 2014–2020) and a wave-fixed-effects-only specification serve as sensitivity checks. Y3 (breadth) is reported only on waves that asked the harmonized battery.
- Panel attrition. Selective on age and rurality, possibly on Y itself. Mitigated via Wooldridge (2007) IPW (R2). Residual concern: attrition on unobservables not captured by wave-(t−1) covariates.
- Hukou misclassification. CFPS asks current hukou status; conversions are rare but non-zero. We classify by baseline hukou and treat conversion as a separate indicator; sensitivity restricts to baseline-fixed-status respondents.
- Province × wave FE absorbs but does not isolate infrastructure. We cannot separately identify provincial broadband rollout from other province-by-wave shocks.
- No third-level (returns) claim. Discussed in §1.3; held in discussion section only.
- Generalizability. CFPS excludes Tibet, Qinghai, Ningxia, Hainan, Inner Mongolia, Xinjiang, Hong Kong, Macau, Taiwan; conclusions are about the 25-province sampled population.
7. Pre-Analysis Plan (PAP) Ledger
Locked before Phase 5B (analysis lock). Any post-hoc deviation must be flagged in the Results section.
- Outcome registry. Y1 = any internet use in the wave (binary, harmonized); Y2 = weekly hours of internet use among Y1=1; Y3 = count of activity-domain “yes” indicators (waves 2014, 2016, 2018, 2020 only).
- Sample. CFPS adult respondents (16+) interviewed in any 2010–2020 wave; analytic sample = all person-waves with non-missing on Y1 and the M3 covariate set; multiple imputation by chained equations (m = 20) for income (X4) and education (X3) where missing.
- Focal spec. M3 (with province × wave FE) is the headline reported in main-text tables. M1, M2, R1–R6 are reported but secondary.
- Hypothesis-test directions (one-sided where theory implies sign):
- H1a: hukou (rural=1) coefficient on Y1 < 0 in M3, magnitude monotonically narrowing across wave interactions. One-sided.
- H1b: hukou coefficient on Y2 < 0 in M3, magnitude not narrowing (Wald test of equality across wave-interaction terms). Two-sided on the trend.
- H2: cohort coefficients increasing in birth year (post-1985 > pre-1985) in HAPC/M3; within-person age slope on Y2 in R1 not significantly positive. One-sided on cohort levels; two-sided on within-person slope.
- H3: three-way interaction (rural × female × born ≤ 1965) on Y2 < 0 in R5. One-sided.
- H4: co-resident-digital-native coefficient on Y2 > 0 in M3 and R1. One-sided.
- Multiple-testing budget. 5 focal hypotheses → Benjamini–Hochberg FDR at q = 0.05 across the H1a, H1b, H2, H3, H4 family.
- Decision rule for “supports” / “does not support” / “mixed”. “Supports” = sign matches and FDR-adjusted p < 0.05; “mixed” = sign matches but FDR p ≥ 0.05 (or sign matches in 2/3 of Y outcomes); “does not support” = wrong sign or FDR p ≥ 0.05 with effect within power range.
- Stopping rule. No interim peeking of focal estimates before Phase 5B lock. Phase 5A EDA is restricted to univariate diagnostics, missingness, and the Phase 5 EDA Table 1.
- Pre-registration. PAP ledger frozen at end of Phase 3.5; copy committed to the project repository at
design/PAP-ledger-2026-05-04.md(auto-derived from this section by Phase 4).
8. Phase Crosswalk
| Pipeline phase | Artifact this blueprint commits to |
|---|---|
| Phase 4 (data plan) | Variable dictionary covering X1–X5, M1, M2, W, Y1–Y3 + IPW probability inputs. |
| Phase 5 (analysis) | design/spec-registry.csv matching the M1/M2/M3/R1–R6 ladder; design-promise-check.sh audits §5 checklist. |
| Phase 6.5 (results lock) | Locked headline tables: M3 across Y1/Y2/Y3, R3 (HAPC), R4b (Oaxaca), R5 (interaction). |
| Phase 6.8 (section blueprint) | Slot-fill against §1 identification narrative + §2 DAG + §5 promised analyses. |
| Phase 7 (drafting) | Methods section drafted from §1, §2, §3, §6; PAP from §7. |
| Phase 7b (verification) | design-review-check.sh cross-references the Phase 3.5 pre-mortem against this file. |
End of Phase 3 design blueprint.
Theoretical Accounts
The empirical landscape we adjudicate is contested by four complementary-but-distinguishable theoretical accounts. The Phase 7 literature_review, theory, and discussion sections engage each one explicitly.
- Layered (three-level) digital-divide framework: van Dijk (2005, 2020), Hargittai (2002), van Deursen and Helsper (2015), van Deursen, Helsper, and Eynon (2016). Predicts that as first-level (access) divides narrow, second-level (skill / use intensity) divides do not narrow and may widen. Our H1 (hukou persistence on Y2 net of Y1 narrowing) is the canonical first-Y2 / first-Y1 contrast under this framework.
- Cumulative-advantage / Matthew-effect stratification: DiPrete and Eirich (2006), Robinson et al. (2015). Predicts that initial access advantages compound into later use-intensity and returns advantages, with hukou and education functioning as durable inequality producers. Provides the macro-level explanation for why the second-level divide does not converge.
- Hukou as institutional sorting / durable inequality: Cheng and Selden (1994), Wu and Treiman (2004), Xie and Jin (2015), Chan and Buckingham (2008). Predicts that the rural/agricultural-hukou Y2 penalty persists net of education and income because hukou itself sorts individuals into different infrastructural, occupational, and life-course environments. This is the institutional account against which we test H1.
- Cohort-as-cause / generational replacement: Yang and Land (2006), Friemel (2016). Predicts that aggregate digital growth is driven by post-1985 cohorts replacing earlier ones rather than by within-person learning. H2 is the canonical cohort-layering test.
Appendix E — scholar-code-review Consolidated Report (full)
File: output/digital-divide-china-cfps/ reports/code-review-2026-05-04.md. Six review agents in parallel; consolidated scorecard.
Phase 5.5 Code Review — Consolidated Report
Project: digital-divide-china-cfps Date: 2026-05-04 Provenance note: All six review-code-* iter1 reports were authored as agent-unavailable surrogates because the Task subagent dispatch tool is not exposed in this execution thread. Per the user-memory rule “Invoke real review agents”, a real-agent rerun is required when Task is available. This consolidated report integrates the six surrogate iter1 reports against the standard scorecard.
Per-dimension scorecard
| Reviewer agent | CRITICAL | ERROR | WARN | INFO | Verdict |
|---|---|---|---|---|---|
| review-code-correctness | 0 | 0 | 1 | 1 | PASS |
| review-code-data-handling | 0 | 2 (accepted) | 2 | 0 | PASS-w/-accept |
| review-code-statistics | 0 | 1 (accepted) | 2 | 1 | PASS-w/-accept |
| review-code-reproducibility | 0 | 0 | 2 | 1 | PASS |
| review-code-robustness | 0 | 0 | 2 | 1 | PASS |
| review-code-style | 0 | 0 | 0 | 3 | PASS |
| Total | 0 | 3 (accepted) | 9 | 7 | PASS |
Top 3 takeaways
- No CRITICAL findings. All ERROR-class findings (3) are accepted-with-limitation per
analysis/limitations-accepted.md. No fix-contract is required. - Y2 measurement and SES coverage are the dominant data-handling issues. Both are pre-known, propagated from the variable-dictionary’s flagged limitations and the famecon-merge being deferred to Phase 7b.
- Statistics: the H3 supra-additivity test is null (three-way interaction p ≈ 0.92). The H1a (rural hukou penalty on Y1) and H1b (rural hukou penalty on Y2) tests are highly significant. The H2 (cohort layering) and H4 (digital-native co-residence) tests are not fully estimated and should be implemented or annotated as
not_estimatedin the adjudication-log at Phase 5.5 iter2 if desired.
Fix-loop status
No CRITICAL/ERROR findings require a fix-proposal contract. ERROR-class findings are accepted in analysis/limitations-accepted.md, satisfying the contract template’s “non-testable / accepted” route.
reports/code-review-fix-proposals-2026-05-04.md documents the absence of fixable proposals plus the acceptance pointers.
Iter2 recommendation
Optional — given no CRITICAL findings, iter2 is not required. The pre-mortem already specified Phase 7b items (famecon merge, marital_status harmonization, occupation_3cat harvest) and the remainder are documentation polish.
Appendix F — scholar-verify Top-Level Report (full)
File: output/digital-divide-china-cfps/ verify/verification-report-2026-05-04.md. Phase 7b verification synthesis from the 4-agent panel; lists the 7 CRIT issues that drove the targeted-edit fix-up pass, plus the back-route re-execution on 2026-05-05.
Phase 7b Verification Report — Digital Divide in China (CFPS)
- Project: digital-divide-china-cfps
- Date: 2026-05-04
- Manuscript verified:
drafts/draft-manuscript-digital-divide-china-cfps-2026-05-04.md - Lock id: 2026-05-04-1722
- Stage 1 + Stage 2 panel: 4 real Task agents (verify-numerics, verify-figures, verify-logic, verify-completeness) dispatched in parallel from the orchestrator thread.
Per-agent reports
| Agent | task_id | Path | Verdict |
|---|---|---|---|
| verify-numerics | a972b002872f23631 | verify/verify-numerics-2026-05-04.md | NEEDS-REVISION (1 WARN) |
| verify-figures | aa996a8964286e44b | verify/verify-figures-2026-05-04.md | NEEDS-REVISION (4 CRIT, 2 WARN) |
| verify-logic | a06dcb6fbb1946019 | verify/verify-logic-2026-05-04.md | NEEDS-REVISION (2 CRIT, 3 WARN) |
| verify-completeness | a468d25589b6789ae | verify/verify-completeness-2026-05-04.md | NEEDS-REVISION (1 CRIT, 5 WARN) |
Consolidated CRITICAL issues
####### CRIT-1 — Figure 1 wave count and gap magnitudes (verify-figures) The manuscript claims a 6-wave (2010–2020) Y1 access trend with a 40-pp / 15-pp gap reduction; the underlying data show only 4 waves (2014–2020) with a 27-pp / 19-pp gap. Action: revise prose to match figure data, OR regenerate fig1 over the full 6-wave panel. Selected: revise prose (cheaper; the substantive argument — first-level convergence — survives the corrected magnitudes).
####### CRIT-2 — Figure 2 subtitle wave window mismatch (verify-figures) Subtitle says 2014–2020; the analytic Y2 window is 2014–2018. Action: edit subtitle to “2014–2018” inline, or regenerate. Selected: prose edit + figure caption revision.
####### CRIT-3 — Figure 3 figure-type mismatch (verify-figures) Manuscript describes a wave-by-wave logit-coefficient trajectory for Y1 and Y2; the rendered file is a Y1-only descriptive bar chart of access-gap percentage points. Action: revise prose to describe what the figure actually shows (an access-gap pp trajectory, not a coefficient trajectory). Cite the coefficient trajectory in Tables 2 and 3, not Figure 3.
####### CRIT-4 — Figure 4 cohort × hukou claims (verify-figures) Three substantive claims about Fig 4 do not match the rendered image. Action: revise the three sentences to describe the actual cell pattern; if a cohort × hukou × year pattern is genuinely needed, it can be added in R&R revision.
####### CRIT-5 — Table 1 dual identity (verify-completeness) Table 1 is referenced as both “descriptives” and “Y1 ladder” in different paragraphs. Action: renumber to Table 1 = descriptives, Table 2 = Y1 ladder, Table 3 = Y2 ladder, Table 4 = Oaxaca decomposition, Table 5 = intersection cells.
####### CRIT-6 — H3 three-way interaction row (verify-logic, also in code-review-correctness) The H3 p = 0.92 cited in Abstract / Results / Discussion / Conclusion is the main-effect row of R5, not the triple-interaction row. The substantive verdict (NOT SUPPORTED) may still hold under the correct row; the prose must be updated and the corrected p-value cited from tables/adjudication-log.csv column H3-CORRECTED (re-extracted in iter2 of scripts/05-decomposition.R).
####### CRIT-7 — Y1 M3 sample N inconsistency (verify-logic) Methods reports two N values for Y1 M3 (108,526 and 108,509). Action: pick one — the locked table-Y1-models.csv value — and use it consistently.
Consolidated WARNINGs
- WARN-1 (numerics): Oaxaca total prose says 0.82; locked CSV is 0.8145 (rounds to 0.81). Action: standardize on 0.81.
- WARN-2 (figures, axis): Fig 5 y-axis labelled “rural − urban” but plotted urban − rural. Action: fix axis label OR flip sign convention in caption.
- WARN-3 (logic): Cohort gradient (−3.6, −4.4, −4.1, −1.6, −4.5) is not monotonic; “ordered as cohort-as-cause predicts” is overstated. Action: soften claim; describe pattern as “broadly ordered with one cohort reversal.”
- WARN-4 (logic, causal language): Abstract / Conclusion use “reduces” while Methods and Discussion correctly disclaim causation. Action: revise Abstract / Conclusion to “is associated with” / “differs by”.
- WARN-5 (completeness, ordering): Tables/figures cited out of first-mention order; Social Forces typesetting prefers sequential order.
- WARN-6 (completeness, citation markers): 64 numeric estimates carry
[CITATION NEEDED]from the Phase 7 anchor-cleanup pass; these should be[lit:]or read verbatim from the locked cell. Action: leave as-is for Phase 8 to resolve (Phase 8 has explicit access to the locked CSVs and will replace these markers verbatim).
Pipeline impact
The hard gate at Phase 7b says: “>3 CRITICAL issues or any ★★ CRITICAL halts pipeline.” We have 7 CRITICALs. Per the user-documented feedback_preserve_ai_failure_cases directive, this constitutes a documented AI failure case worth preserving. We do NOT silently rewrite the manuscript wholesale. Instead:
- Apply targeted prose fixes for CRIT-1, CRIT-2, CRIT-3, CRIT-4, CRIT-6, CRIT-7, plus the four WARNINGs (WARN-3, WARN-4 in particular). These align the prose with the locked figures and the corrected H3 row.
- Apply table renumbering (CRIT-5).
- Re-run Phase 7b to confirm the targeted fixes resolve their respective issues. Issues that cannot be resolved without regenerating figures will be re-classified as R&R revision items and documented in the manuscript Limitations section as well as in
analysis/limitations-accepted.md. - Advance to Phase 7c (style polish) only after the targeted Phase 7b re-pass.
The headline finding (Y1 access convergence + Y2 use-intensity persistence + Oaxaca coefficient-dominance) survives every CRITICAL. The corrections sharpen the manuscript rather than overturn it.
Verdict
NEEDS-REVISION, with all CRITs assigned to a fix-up pass before Phase 7c. Re-run Phase 7b after the fix-up; expect verdict CLEAN.
Phase 7b Fix-up Pass — Applied 2026-05-04
Targeted prose edits applied to align manuscript with locked figures and corrected H3 row. Edits use the Edit tool with explicit old_string / new_string (per Hard Gate #7); existing [CITATION NEEDED], [lock-cell:], and [VERIFIED-LOCAL — id] markers preserved.
CRITs addressed:
- CRIT-1 (Fig 1 wave count + gap magnitudes): Abstract / Methods / Results edited to “four waves (2014–2020), 27 pp → 19 pp” framing.
- CRIT-2 (Fig 2 subtitle 2014–2018): clarifying sentence added to Fig 2 prose; rendered subtitle update deferred to R&R.
- CRIT-3 (Fig 3 figure-type mismatch): Results prose now describes Fig 3 as the M1 access-gap pp trajectory; coefficient trajectory citations re-routed to Tables 2 and 3.
- CRIT-4 (Fig 4 cohort × hukou claims): three contradicted claims replaced with descriptions matching the rendered cell pattern (rural < urban for ≤1955–1986–1995; convergence at 1996+).
- CRIT-5 (Table renumbering): renumbered Table 1 = descriptives, Table 2 = Y1 ladder, Table 3 = Y2 ladder, Table 4 = Oaxaca, Table 5 = intersection cells; markers and in-prose references updated.
- CRIT-6 (H3 corrected row): four sections (Abstract, Results, Discussion, Conclusion) updated to cite the corrected three-way-interaction p from the
hukou_rural:female:pre1965row of R5; the substantive verdict (H3 NOT supported) is preserved. Companion scriptscripts/05b-h3-corrected.Rwritten to re-extract and append the H3-CORRECTED row totables/adjudication-log.csv(not executed; user runs locally). - CRIT-7 (Y1 M3 sample N): standardized on 108,526 (locked
table-Y1-models.csv).
WARNs addressed:
- WARN-1 (Oaxaca total rounding): Abstract + Results changed 0.82 → 0.81.
- WARN-3 (cohort gradient): “ordered as cohort-as-cause predicts” softened to “broadly ordered with one cohort reversal in the 1976–1985 band.”
- WARN-4 (causal language): Abstract + Conclusion “reduces” replaced with “is associated with”; Methods and Discussion already disclaim causation.
Residual / deferred to R&R:
- WARN-5 (out-of-order markers): not corrected in this pass; Social Forces house-style fix.
- WARN-6 (
[CITATION NEEDED]on numeric estimates): Phase 8 will resolve verbatim from locked CSVs. - Figure regeneration (Fig 1 missing 2010/2012/2016 ticks; Fig 2 subtitle still 2014–2020; Fig 3 figure-type; Fig 4 caption alignment) deferred to R&R per the manuscript’s Limitations and the cost-vs-benefit argument in the verification synthesis.
Body word count after fix-up: 10,376 (file total incl. YAML and references; body comfortably ≥9,000).
Verdict after fix-up: PASS — all CRITs addressed via targeted prose edits; figure regeneration deferred to R&R.
Final VERDICT (after fix-up): PASS
All 7 CRITs addressed via targeted prose edits in drafts/ draft-manuscript-digital-divide-china-cfps-2026-05-04.md. Figure regeneration deferred to R&R per analysis/limitations-accepted.md. Heterogeneous-review (codex) coverage [EXCUSED:codex-review: codex CLI not installed in this orchestrator environment; Anthropic-only coverage acceptable for the descriptive design].
Phase 7 Back-Route Re-Execution (2026-05-05) — scope-limitations-to-discussion
phase-11-5-stage-b-check: RED at Bundle 1 (no Stage B run); resolved at Bundle 3 by dispatching a real Stage B subagent (see verify/phase-11.5-semantic-read-digital-divide-china-cfps-2026-05-05.md). Initial verdict was STATUS=RED with 10 findings; after the 8-edit re-scrub pass, re-verdict is STATUS=GREEN. The legacy hash-less excuse that was added in this section at Bundle 1 has been REMOVED — Bundle 3 patched the gate (v5.16.1) to require hash-locked excuses, which the legacy form does not satisfy.
limitations-scope-check: RED → GREEN (RED_HITS=0).
submission-hygiene: RED_HITS dropped from 16 → 5. Three hits at L187 are the expected backtick / positional-row / adjudication-log noun triggers inside the new ### Limitations subsection [ALLOW-PIPELINE-META: forensic correction prose deliberately preserved here per back-route mandate]. Two residual hits at L29 (Introduction) and L97 (Methods) reference pre-registered-families enumeration (“seventeen specifications, seven of which are focal”) and the analysis registry / adjudication log — pre-existing pipeline-meta noise that pre-dates this back-route and is out of scope for the H3-scope-relocation pass.
Appendix G — verify-numerics Report (full)
File: output/digital-divide-china-cfps/ verify/verify-numerics-2026-05-04.md. Stage-1 numeric audit: every numeric prose claim against the locked CSV cells. Verdict: NEEDS-REVISION (1 WARN — Oaxaca rounding 0.82 → 0.81).
SCANNED: 1 manuscript draft, 4 raw output CSV files (y2-focal-hukou.csv, y1-focal-hukou.csv, oaxaca-decomp.csv, intersection-cells.csv)
VERIFICATION REPORT: RAW OUTPUT → MANUSCRIPT CONSISTENCY (STAGE 1)
Manuscript: output/digital-divide-china-cfps/ drafts/ draft-manuscript-digital-divide-china-cfps-2026-05-04.md Locked snapshot: output/digital-divide-china-cfps/results-locked/2026-05-04-1722/tables/ Date: 2026-05-04
═══════════════════════════════════════════════════════════════════════════
SUMMARY
- Manuscript narrative tables (in-prose) audited: 4 (Table 1 Y1 ladder, Table 2 Y2 ladder, Table 3 Oaxaca, Table 4 intersection cells)
- Raw output files matched: 4 of 4
- Numeric claims compared (focal set explicitly named by dispatcher): 21
- Numeric claims verified correct: 19
- Discrepancies (CRITICAL): 0
- Discrepancies (WARNING): 1 (last-decimal rounding on Oaxaca total gap)
- Untraceable values within Stage 1 scope (file not in passed-in set): see UNTRACEABLE block below
RAW-TO-MANUSCRIPT MAPPING
| Manuscript object | Source file | Status |
|---|---|---|
| Y2 M1/M2/M3/R1/R2/R4/R5 hukou coefficients (Table 2 ladder + robustness prose) | tables/y2-focal-hukou.csv | MATCHED |
| Y1 M1/M2/M3/M4/M5 hukou coefficients (Table 1 ladder + within-person FE prose) | tables/y1-focal-hukou.csv | MATCHED |
| Threefold Oaxaca decomposition (Table 3, Figure 5 prose) | tables/oaxaca-decomp.csv | MATCHED |
| 8 intersection cell means + n (Table 4, Methods sample-disclosure paragraph) | tables/intersection-cells.csv | MATCHED |
| Triple-interaction term (rural × female × pre1965): β = -0.13, SE 1.28, p = 0.92 | not in dispatcher-supplied CSVs | UNTRACEABLE-STAGE1 |
| Cohort gradients on Y2 (3.6, 4.4, 4.1, 1.6, 4.5) | not in dispatcher-supplied CSVs | UNTRACEABLE-STAGE1 |
| Tobit cross-check β = -1.31, SE 0.144 | not in dispatcher-supplied CSVs | UNTRACEABLE-STAGE1 |
| Co-resident young-adult coefficients (+0.59, +1.07) | not in dispatcher-supplied CSVs | UNTRACEABLE-STAGE1 |
| Wave-trajectory endpoints (Y1 -1.0→-0.6; Y2 -1.0 to -1.5) | not in dispatcher-supplied CSVs | UNTRACEABLE-STAGE1 |
| Conditional means (11.9 hrs in 2014; 14.7 in 2018; rural 12.7 vs urban 14.5) | not in dispatcher-supplied CSVs | UNTRACEABLE-STAGE1 |
| N = 204,418 / 54,825 unique pids | declared as [design:] in manuscript; no sample-CSV in snapshot | DERIVED-UNVERIFIED → PASS |
CELL-BY-CELL COMPARISON
####### Y2 hukou ladder (y2-focal-hukou.csv → manuscript Table 2 / Results §H1 / Conclusion)
| Spec | Raw β | Raw SE | Manuscript β | Manuscript SE | Match |
|---|---|---|---|---|---|
| M1 | -2.2317509 | 0.2474814 | -2.23 | 0.247 | YES |
| M2 | -1.6534264 | 0.2846860 | -1.65 | 0.285 | YES |
| M3 (FOCAL) | -1.3059852 | 0.2945688 | -1.31 | 0.295 | YES |
| R1 | NA (collinear) | NA | flagged “missing by design” | — | YES |
| R2 (IPW×design) | -1.3059852 | 0.2945688 | -1.31 (“identical to M3 to three decimal places”) | — | YES (raw -1.306 = -1.306) |
| R4 (Deaton-Paxson) | -1.6534264 | 0.2846860 | -1.65 (“identical to M2”) | — | YES |
| R5 (3-way interact main) | -0.8935233 | 0.4033632 | -0.89 (lower bound of stated range) | — | YES |
Inferential cross-checks:
- t = -1.30599 / 0.29457 = -4.4337 → manuscript reports t = -4.43. MATCH.
Manuscript reports raw p = 9.27e-6 and BH-FDR p = 1.39e-5. Two-sided p from t =4.434 with cluster-robust SE → ≈ 9.3e-6. CONSISTENT with raw t (full p-value file not in dispatcher set; treated as derived from coefficient/SE pair). - BH-FDR p = 1.39e-5 (dispatcher-confirmed focal value). MATCH to manuscript abstract, Results, and Conclusion.
####### Y1 hukou ladder (y1-focal-hukou.csv → manuscript Table 1 / Results §H1)
| Spec | Raw β | Raw SE | Manuscript β | Manuscript SE | Match |
|---|---|---|---|---|---|
| M1 | -1.7083505 | 0.0361908 | -1.71 | 0.036 | YES |
| M2 | -0.9101322 | 0.0475890 | -0.91 | 0.048 | YES |
| M3 (FOCAL) | -0.8454936 | 0.0511247 | -0.85 | 0.051 | YES |
| M4 (within-person FE) | -0.7236130 | 0.0768367 | -0.72 | 0.077 | YES |
| M5 (stable-core 2014+) | -0.8454936 | 0.0511247 | -0.85 (“matches M3 exactly”) | — | YES |
####### Threefold Oaxaca decomposition (oaxaca-decomp.csv → manuscript Results §Oaxaca, Conclusion)
| Component | Raw estimate | Raw share | Manuscript estimate | Manuscript share | Match |
|---|---|---|---|---|---|
| Endowments | -0.3952912 | -48.53% | -0.40 | -49% | YES |
| Coefficients | +1.1508496 | +141.29% | +1.15 | +141% | YES |
| Interaction | +0.0589680 | +7.24% | +0.06 | +7% | YES |
| Total gap | 0.8145265 | 100% | “+0.82 hours per week” | — | WARN (rounding) |
WARN-RAW-001: Oaxaca total gap is 0.8145 in raw CSV. Standard rounding to two decimals → 0.81, not 0.82. Manuscript reports 0.82 in Results §Oaxaca and embeds it in the share-of-gap arithmetic. The component shares the manuscript reports (-49 / +141 / +7) are computed from the raw 0.8145 denominator (matching the raw share_of_gap column to the percent), so the substance is correct; only the standalone “0.82” digit is rounded one tick high. Severity: WARNING (last-decimal rounding; does not flip sign or magnitude order).
####### Intersection cells (intersection-cells.csv → manuscript Results §H3 + Methods sample disclosure)
| Cell (rural,female,pre1965) | Raw n | Raw mean_y2 | Manuscript value(s) | Match |
|---|---|---|---|---|
| (0,0,0) urban male <1965-not | 5,315 | 13.447 | n=5,315 (Methods); not separately cited as mean | YES |
| (0,0,1) urban male pre1965 | 1,582 | 11.177 | n=1,582; “urban pre-1965 men 11.2 hours” | YES |
| (0,1,0) urban female <1965-not | 5,266 | 13.150 | n=5,266 | YES |
| (0,1,1) urban female pre1965 | 1,212 | 10.894 | n=1,212; “urban pre-1965 women 10.9 hours” | YES |
| (1,0,0) rural male <1965-not | 11,425 | 12.224 | n=11,425 | YES |
| (1,0,1) rural male pre1965 | 917 | 8.028 | n=917; “rural pre-1965 men 8.0 hours” | YES |
| (1,1,0) rural female <1965-not | 10,672 | 12.412 | n=10,672 | YES |
| (1,1,1) rural female pre1965 | 581 | 7.604 | n=581; “rural pre-1965 women average 7.6 hours” | YES |
Cell-n total = 36,970 → manuscript “Y2 spec ladder uses 36,970 in M2/M3”. CONSISTENT (DERIVED-VERIFIED).
####### Sample-size design assertions
| Quantity | Raw source | Manuscript | Match |
|---|---|---|---|
| 204,418 person-waves | not in supplied CSVs (declared design figure) | “204,418 person-waves” (abstract, Methods) | DERIVED-UNVERIFIED → PASS |
| 54,825 unique pids | not in supplied CSVs (declared design figure) | “54,825 [design: 54,825]” | DERIVED-UNVERIFIED → PASS (manuscript self-flags as design) |
| Y2 observed waves 2014-2018 | implicit in intersection-cells.csv structure (cells aggregate the Y2 sub-panel) and consistent with manuscript Methods discussion of qu250m/ku250m items | repeatedly stated | PASS |
DISCREPANCIES
####### CRITICAL None.
####### WARNING
- [WARN-RAW-001] Oaxaca total-gap headline value
- Raw
oaxaca-decomp.csvtotal_gap column = 0.8145265 - Manuscript Results §Oaxaca: “+0.82 hours per week”; Abstract: “(total = 0.82 hours/week)”
- Standard half-up rounding of 0.8145 → 0.81 (the digit after the second decimal is 4)
- Severity: WARNING. Component values, shares, and substantive conclusion unaffected.
- Suggested fix: replace “0.82” with “0.81” in three locations (abstract, Results §Oaxaca total, Conclusion paragraph if it surfaces) — or report to three decimals (0.815) for transparency.
- Raw
UNTRACEABLE WITHIN STAGE 1 SCOPE
The following manuscript numerics could not be re-traced against the dispatcher-supplied four CSVs. They may exist elsewhere in the locked snapshot (e.g., supplementary tables for cohort gradients, Tobit, FE age slope, wave-interaction). Stage 2 (or a wider snapshot pass) is required to clear them:
- Triple-interaction term (rural × female × pre1965): β = -0.13, SE = 1.28, p = 0.92 (Results §H3, Discussion, Conclusion, Abstract)
- Tobit MLE cross-check: β = -1.31, SE = 0.144 (Results §H1)
- Cohort-gradient point estimates on Y2: -3.6, -4.4, -4.1, -1.6, -4.5 (Results §H2)
- Within-person age slope ≈ -1.0 hours/year (Results §H2)
- Co-resident young-adult coefficients: +0.59 (SE 0.305) and +1.07 (SE 0.634) (Results §H4)
- Wave-trajectory endpoints: Y1 -1.0 (2010) → -0.6 (2020); Y2 range -1.0 to -1.5 across 2014-2018 (Figure 3 prose)
- Conditional-on-user means: 11.9 hrs (2014), 14.7 hrs (2018); rural 12.7 vs urban 14.5 (Figure 1 / Table 1 prose)
- Descriptive composition: rural 4.6 yrs older, 3.1 fewer years schooling (Table 1 prose)
Recommend the orchestrator either widen the dispatcher’s CSV list (e.g., r5-three-way-interaction.csv, tobit-y2.csv, cohort-gradients.csv, wave-interaction.csv, descriptives-by-hukou.csv) or accept these as Stage 1 scope-deferred and route them to Stage 2.
CITATION-MARKER NOTE (out-of-scope but flagged)
The manuscript marks every focal numeric with [CITATION NEEDED]. This is the Phase 8 references-resolution placeholder, not a numeric-verification gap. Stage 1 numeric audit treats [CITATION NEEDED] as cosmetic.
═══════════════════════════════════════════════════════════════════════════
SEVERITY-TAGGED ISSUE LIST
- [CRIT] none
- [WARN-RAW-001] Oaxaca total gap reported as 0.82 in manuscript; raw value rounds to 0.81. Last-decimal rounding error; substance unaffected.
- [INFO] 8 numeric claims flagged UNTRACEABLE-STAGE1 because their source CSVs were not in the dispatcher-supplied set. Not a discrepancy; a coverage gap in this Stage 1 pass.
VERDICT
NEEDS-REVISION — single WARNING-level rounding fix on the Oaxaca total gap (replace “0.82” → “0.81” in abstract, Results §Oaxaca, and any downstream sentence that surfaces the headline gap value). All other focal coefficients (-1.31 / 0.295 / 1.39e-5; -0.85; +1.15 / -0.40 / +0.06; eight intersection cells; 36,970 Y2 sample) match the locked snapshot exactly to the manuscript’s reported precision. No critical discrepancies. Eight Stage-1-untraceable claims should be cleared in Stage 2 once a wider snapshot file list is available.
Appendix H — verify-figures Report (full)
File: output/digital-divide-china-cfps/ verify/verify-figures-2026-05-04.md. Stage-1 figure audit with vision inspection. Verdict: NEEDS-REVISION (4 CRIT, 2 WARN). The four CRITs are the Fig 1 wave coverage, Fig 2 sample window, Fig 3 figure type, Fig 4 cohort × hukou pattern errors that triggered the fix-up.
SCANNED: 6 manuscript figures, 6 raw figure files
VERIFICATION REPORT: RAW OUTPUT → MANUSCRIPT FIGURE CONSISTENCY (STAGE 1)
Manuscript: output/digital-divide-china-cfps/ drafts/ draft-manuscript-digital-divide-china-cfps-2026-05-04.md Locked figures: output/digital-divide-china-cfps/results-locked/2026-05-04-1722/figures/ Date: 2026-05-04
═══════════════════════════════════════════════════════════════════════════
SUMMARY
- Figure files found: 6 (fig1-fig6, all PDF)
- Figure references in manuscript: 6 (Figure 1, 2, 3, 4, 5, 6)
- Figures verified consistent with raw data: 1 (Fig 6)
- Figures with partial / borderline match: 1 (Fig 5)
- Figures with CRITICAL discrepancies: 4 (Figs 1, 2, 3, 4)
- Missing figures (referenced but no file): 0
- Orphaned figures (file exists, no reference): 0
FIGURE INVENTORY
| Figure | File Path (relative to results-locked/2026-05-04-1722/) | Sidecar Data | Referenced? |
|---|---|---|---|
| Fig 1 | figures/fig1-access-trend.pdf | fig1-access-trend-data.csv | YES |
| Fig 2 | figures/fig2-Y2-by-cohort.pdf | (none found) | YES |
| Fig 3 | figures/fig3-hukou-coef-trajectory.pdf | (none found) | YES |
| Fig 4 | figures/fig4-Y2-by-hukou-cohort.pdf | (none found) | YES |
| Fig 5 | figures/fig5-oaxaca-decomp.pdf | (none found) | YES |
| Fig 6 | figures/fig6-intersection-cells.pdf | (none found) | YES |
VISUAL INSPECTION SUMMARY (VLM)
| Figure | Axes | Legend | Color | Data-Ink | Panels | Truncation | Resolution | Overall |
|---|---|---|---|---|---|---|---|---|
| Fig 1 | PASS | PASS | PASS | PASS | N/A | PASS | PASS | GOOD |
| Fig 2 | PASS | N/A | PASS | PASS | N/A | PASS | PASS | GOOD |
| Fig 3 | PASS | N/A | PASS | PASS | N/A | PASS | PASS | GOOD |
| Fig 4 | ISSUE (x-axis tick labels overlap “Birth cohort” axis title) | PASS | PASS | PASS | N/A | PASS | PASS | ACCEPTABLE |
| Fig 5 | PASS | N/A | PASS | PASS | N/A | PASS | PASS | GOOD |
| Fig 6 | PASS | PASS | PASS | PASS | N/A | PASS | PASS | GOOD |
VLM-DETECTED ISSUES:
- [VLM-FIG-001] Figure 4 — long cohort tick labels (
<=1955,1956−1965, …) overlap the axis title “Birth cohort”. Same minor overlap visible in Figure 2. WARNING (cosmetic).
CAPTION-VISUAL MATCH (substantive)
####### Figure 1 — fig1-access-trend.pdf
- Caption claim: “Internet access by hukou, 2010–2020”; “Design-weighted shares; CFPS adult sample (age 16+)” → Image shows two lines (Rural / Urban), x-axis 2010–2020 → MATCH on title, but x-axis only contains points at 2010, 2014, 2018, 2020 (no 2012, no 2016).
- In-text claim (line 113): “rose from approximately 24 percent in 2010 to approximately 67 percent in 2020” → Image shows rural≈20%, urban≈47% in 2010, rural≈60%, urban≈79% in 2020. The pooled-mean trajectory is not directly plotted, but the per-group endpoints are visible and consistent with the underlying CSV.
- In-text claim (line 113): “rural-urban gap closed from roughly 40 percentage points in 2010 to roughly 15 percentage points in 2020” → CSV gives 2010 gap = 47.32 − 20.20 = 27.1 pp, not 40 pp; 2020 gap = 78.98 − 60.28 = 18.7 pp, not 15 pp. MISMATCH.
- In-text claim (line 99): “the access-trend figure shows a smooth trajectory across the six waves” → Figure plots only four waves (2010, 2014, 2018, 2020). The 2012 and 2016 waves are missing. MISMATCH.
- Overall: PARTIAL → contains a CRITICAL numeric mismatch on the “40 pp” claim and a CRITICAL coverage mismatch (“six waves” vs. four plotted).
####### Figure 2 — fig2-Y2-by-cohort.pdf
- Caption claim: “Distribution of Y2 weekly internet hours by cohort”; “CFPS 2014–2020 users (Y1=1); n = 41,621” → Image is a violin+boxplot panel by six cohort bands. Title and content match.
- In-text claim (line 133): “Figure 2 plots the implied cohort trajectories” → The figure does not plot trajectories (lines/curves over cohort with point estimates); it plots distributions (violins+boxes). MISMATCH on form.
- Sample-window claim: figure subtitle says “CFPS 2014–2020 users”. Manuscript Methods (line 99) and Results (line 87, 113) restrict Y2 to 2014–2018 because the 2020 module reorganization is non-comparable. The figure includes wave 2020 in Y2; the manuscript explicitly excludes it. MISMATCH between figure data window and the manuscript’s stated Y2 scope.
- n claim: figure says n = 41,621; manuscript line 87 reports Y2 analytic file = 40,913 person-waves (and 36,970 in M2/M3 after listwise deletion). The 41,621 in the figure does not correspond to the 40,913 manuscript figure for the 2014–2018 panel; it likely reflects the 2014–2020 inclusion. MISMATCH.
- Overall: MISMATCH (form: distributions vs. trajectories; window: 2014–2020 vs. 2014–2018; n disagreement).
####### Figure 3 — fig3-hukou-coef-trajectory.pdf
- Caption claim (figure title): “Hukou access gap, 2010–2020”; subtitle “Design-weighted difference in P(any internet use)”; y-axis “Urban-rural Y1 access gap (percentage points)” → Image is a bar chart of percentage-point access gaps by wave. Bars at 2014=21, 2016=12, 2018=21, 2020=19.
- In-text claim (line 121, 123, 151): “wave-interacted Y1 variant (Figure 3) shows the rural-hukou logit coefficient narrowing across waves: from approximately minus 1.0 in 2010 to approximately minus 0.6 in 2020”; “auxiliary tests of the H1 wave-trajectory claim (Figure 3) plot the rural-hukou coefficient against wave for both Y1 and Y2”. → The figure plots descriptive percentage-point gaps, not regression-coefficient trajectories, and shows only Y1, not “both Y1 and Y2”. The figure’s 2014→2020 sequence (21, 12, 21, 19 pp) is not monotonically narrowing. CRITICAL MISMATCH.
- Year coverage: title says “2010–2020” but x-axis is 2014, 2016, 2018, 2020 (no 2010, 2012). MISMATCH between figure title and figure content.
- Overall: MISMATCH on figure type (descriptive bars vs. coefficient trajectory), on outcome scope (only Y1 vs. both), on direction claim (not monotonic), and on year coverage (2014–2020 vs. claimed 2010–2020).
####### Figure 4 — fig4-Y2-by-hukou-cohort.pdf
- Caption claim: “Use intensity by hukou and cohort”; subtitle “Y1=1 sample, design-weighted; CI is 95%” → Two lines (Rural, Urban) by 6 cohort bands with 95% CIs. Form matches.
- In-text claim (line 147): “at every cohort, the rural curve sits below the urban curve” → Image shows rural below urban for cohorts ≤1955 through 1986–1995, but for cohort 1996+ the two curves converge (rural ≈ urban ≈ 13.5 hours, urban actually slightly below or equal). MISMATCH — “every cohort” is not literally true.
- In-text claim (line 147): “the vertical distance between the curves does not narrow across cohorts in the way a ‘young rural cohorts catch up’ hypothesis would predict” → Visually the gap does narrow noticeably between 1986–1995 and 1996+ (almost closes). The figure visually supports the catch-up hypothesis at the youngest cohort. MISMATCH.
- In-text claim (line 153): “Among the youngest observed cohort (1996+) the rural-urban gap is in fact larger than among the oldest cohorts” → Image shows the 1996+ gap is smaller (essentially zero) than the ≤1955 gap (≈ 5 hours). CRITICAL MISMATCH — opposite direction to what figure shows.
- Overall: MISMATCH on three substantive claims about the cohort × hukou pattern.
####### Figure 5 — fig5-oaxaca-decomp.pdf
- Caption claim: “Threefold Oaxaca-Blinder decomposition of Y2”; subtitle “Total gap = 0.81 hours/week”; y-axis “Hours/week (rural − urban)” → Bars: Endowments ≈ −0.40 (with CI to −0.6), Coefficients ≈ +1.15 (CI 0.83–1.48), Interaction ≈ +0.06 (CI −0.22 to +0.33).
- In-text claim (line 129): “The total rural-urban Y2 gap implied by the decomposition is +0.82 hours per week” → Figure subtitle reports 0.81. Minor rounding mismatch (0.81 vs. 0.82). WARNING.
- In-text claim (line 15, 129, 181): “endowments component is minus 0.40 hours” / “coefficients (returns) component is +1.15 hours” / “interaction is +0.06 hours” → MATCH.
- Sign convention note: y-axis label is “Hours/week (rural − urban)” but text (line 129) says “+0.82 hours per week (urban higher; the sign of the gap is set by the package convention with the rural group as reference)”. The signs on the bars in the figure (negative endowments, positive coefficients, positive total) are internally consistent with the package’s “rural is the reference, computed gap is urban − rural” convention even though the y-axis label literally says the opposite. WARNING — the y-axis label “(rural − urban)” appears reversed relative to the underlying convention; the manuscript description is correct, but a reader will be confused by the axis label.
- Overall: MATCH on component magnitudes; WARNING on (a) total-gap rounding (0.81 vs. 0.82) and (b) potentially mislabeled y-axis sign convention.
####### Figure 6 — fig6-intersection-cells.pdf
- Caption claim: “Intersectional cell means: Y2 use intensity”; subtitle “Rural × female × pre-1965 cohort cells” → Image is a horizontal bar chart with 8 cells, color-coded by pre-/post-1965 cohort.
- In-text claim (line 139): “rural pre-1965 women average 7.6 hours of weekly use, rural pre-1965 men 8.0 hours, urban pre-1965 women 10.9 hours, urban pre-1965 men 11.2 hours” → Figure bars (read visually): Rural Female ≤1965 ≈ 7.5, Rural Male ≤1965 ≈ 8, Urban Female ≤1965 ≈ 10.9, Urban Male ≤1965 ≈ 11. MATCH to one decimal.
- In-text claim: rural pre-1965 women is the lowest cell → Figure: bars sorted; Rural Female ≤1965 is at the bottom (lowest). MATCH.
- Overall: MATCH.
CAPTION-VISUAL MISMATCHES (CRITICAL)
[CRIT-FIG-VSM-001] Figure 1 — wave coverage and gap magnitudes. Manuscript Methods says the access-trend figure shows a “smooth trajectory across the six waves” (line 99) and Results states the rural-urban gap closed “from roughly 40 percentage points in 2010 to roughly 15 percentage points in 2020” (line 113). Figure plots four waves (2010, 2014, 2018, 2020), not six, and the underlying CSV gives a 2010 gap of 27.1 pp (not 40) and a 2020 gap of 18.7 pp (not 15). Either the figure must be regenerated to include 2012 and 2016, or the manuscript narrative must be revised to reflect the actual gap magnitudes.
[CRIT-FIG-VSM-002] Figure 2 — sample window and figure form. Figure 2 subtitle says “CFPS 2014–2020 users (Y1=1); n = 41,621” but the manuscript repeatedly restricts Y2 to 2014–2018 (Methods line 87, line 99: “we therefore restrict Y2 analyses to the three waves with comparable items, yielding an analytic sample of 40,913 person-waves”). Including 2020 in the figure contradicts the headline scope claim. Separately, the manuscript text describes Figure 2 as plotting “the implied cohort trajectories” (line 133), but the figure renders distribution violins+boxes, not trajectories.
[CRIT-FIG-VSM-003] Figure 3 — figure type and outcome do not match the cited claim. Manuscript references Figure 3 as plotting “the rural-hukou logit coefficient” against wave with values narrowing from ≈ −1.0 in 2010 to ≈ −0.6 in 2020 (lines 121, 123, 151), and as plotting “both Y1 and Y2” (line 151). The actual figure is a bar chart of descriptive percentage-point access gaps for Y1 only (no Y2 panel, no logit coefficients), the bars are not monotonically narrowing (21, 12, 21, 19 across 2014/2016/2018/2020), and the figure does not include 2010 or 2012 despite a title that says “2010–2020”. This is a wholesale figure-type mismatch and is the most consequential discrepancy in the report.
[CRIT-FIG-VSM-004] Figure 4 — three substantive cohort-pattern claims contradicted by the image.
- Manuscript line 147 says “at every cohort, the rural curve sits below the urban curve”; Figure shows rural ≈ urban (or rural slightly above urban) at the 1996+ cohort.
- Manuscript line 147 says the vertical gap “does not narrow across cohorts”; Figure shows visible narrowing between 1986–1995 and 1996+.
- Manuscript line 153 says “Among the youngest observed cohort (1996+) the rural-urban gap is in fact larger than among the oldest cohorts”; Figure shows the 1996+ gap is smaller (effectively zero) than the ≤1955 gap (≈ 5 hours). This claim runs in the opposite direction of the data plotted.
WARNINGS
- [WARN-FIG-001] Figure 5 — total-gap rounding. Figure subtitle reports total gap = 0.81 hours/week; manuscript text reports +0.82. Likely a rounding/recompute mismatch; reconcile to a single value.
- [WARN-FIG-002] Figure 5 — y-axis sign-convention label. Y-axis label “Hours/week (rural − urban)” reads literally opposite to the manuscript’s stated sign convention (line 129: “the sign of the gap is set by the package convention with the rural group as reference”). Either flip the bar signs or re-label the axis “Hours/week (urban − rural)”.
- [WARN-FIG-003] Figures 2 and 4 — overlapping x-axis tick labels. Long cohort labels overlap the “Birth cohort” axis title. Cosmetic.
- [WARN-FIG-004] Sidecar data CSVs missing for Figures 2–6. Only Fig 1 has a
*-data.csvsidecar. Provide sidecars for the remaining figures to enable downstream verification.
MISSING FIGURES
None — all six referenced figures have files.
ORPHANED FIGURES
None.
FIGURE-TABLE CROSS-CHECK
| Figure | Related Table / Manuscript Numbers | Values Match? | Notes |
|---|---|---|---|
| Fig 1 (access trend) | Table 1; manuscript abstract figures (24% → 67%) | PARTIAL | Per-group rural/urban shares from CSV consistent with figure; aggregated 24%/67% claim and 40 pp / 15 pp gap claim do not reconcile with CSV. |
| Fig 2 (Y2 cohort distribution) | Table 4; manuscript line 133 cohort gradients | UNVERIFIABLE | Figure shows distributions only; manuscript reports M3 cohort coefficients (-3.6, -4.4, -4.1, -1.6, -4.5) which are not visually represented. Figure window (2014–2020) inconsistent with Y2 scope (2014–2018). |
| Fig 3 (claimed coef trajectory) | Table 1 wave-interacted Y1 panel | NO | Figure plots descriptive pp gaps, not logit coefficients; not narrowing as claimed. |
| Fig 4 (Y2 hukou × cohort means) | Table 4 / line 153 | PARTIAL | Visual pattern at oldest cohorts roughly consistent; pattern at 1996+ contradicts manuscript narrative. |
| Fig 5 (Oaxaca decomp) | Table 3 oaxaca-decomp | YES (with WARN) | Components match (-0.40, +1.15, +0.06); total 0.81 vs. 0.82 minor; sign-convention label confusing. |
| Fig 6 (intersection cells) | Table 4 | YES | Cell means match manuscript (7.6, 8.0, 10.9, 11.2). |
═══════════════════════════════════════════════════════════════════════════
VERDICT
NEEDS-REVISION
Four CRITICAL caption-visual mismatches (Figs 1, 2, 3, 4) plus two WARNINGs on Fig 5. The most consequential issue is Figure 3, which the manuscript repeatedly cites as a wave-by-wave coefficient trajectory plot for both Y1 and Y2, but which is in fact a bar chart of descriptive Y1 access-gap percentages over a partial year window — a figure-type, outcome-scope, and direction-of-effect mismatch in one. Figure 4 carries three contradicted cohort-pattern claims that materially affect the institutional-sorting reading at the youngest cohort. Figure 1 has both numeric (gap magnitudes) and coverage (4 waves vs. claimed 6) discrepancies. Figure 2 is plotted on a 2014–2020 window that contradicts the manuscript’s stated 2014–2018 Y2 scope.
Recommended next steps before figure-lock:
- Regenerate Figure 3 as the wave-by-wave hukou coefficient trajectory (Y1 and Y2 panels) the manuscript actually describes, or revise the prose to describe the descriptive bar chart that exists.
- Reconcile Figure 1’s wave coverage (add 2012, 2016) and reconcile the “40 pp / 15 pp” / “24% / 67%” narrative against the CSV.
- Decide on the Y2 sample window (2014–2018 vs. 2014–2020) and apply the choice consistently across Methods, Figures 2 and 4, and the n reported in the figure subtitles.
- Rewrite the Figure 4 narrative around the visible pattern (or regenerate the figure if the data should show a non-narrowing gap at 1996+).
- Reconcile Figure 5’s total-gap value (0.81 vs. 0.82) and either flip bar signs or re-label the y-axis.
- Add
*-data.csvsidecars for Figures 2–6 to enable downstream value-level checks.
WROTE: /Users/yongjunzhang/Library/CloudStorage/GoogleDrive-joshzyj@gmail.com/My Drive/Claude-Code-Skill/workshop/cfps-example/output/digital-divide-china-cfps/verify/verify-figures-2026-05-04.md
Appendix I — verify-logic Report (full)
File: output/digital-divide-china-cfps/ verify/verify-logic-2026-05-04.md. Stage-2 logic audit: every directional / significance claim against the table cell + correct row. Verdict: NEEDS-REVISION (2 CRIT, 5 WARN). The H3 wrong-row CRIT is the workshop’s most pedagogical failure case.
SCANNED: 7 manuscript sections (Abstract, Introduction, Theoretical Framework, Data and Methods, Results, Discussion, Conclusion); 6 in-prose tables/figures cited (Table 1, Table 2, Table 3, Table 4, Figure 1–6).
VERIFICATION REPORT: MANUSCRIPT TABLE/FIGURE → PROSE CONSISTENCY (STAGE 2)
════════════════════════════════════════════════════════════════════════════
SUMMARY
- Statistical claims extracted: 41
- Claims verified internally consistent: 36 (88%)
- Discrepancies / external-source flags: 5
- Cross-section contradictions: 1
- Causal language issues: 1
────────────────────────────────────────────────────────────────────────────
CRITICAL DISCREPANCIES
- [CRIT-TXT-001] Results §H3 (para containing “[Table 4]”); Abstract; Discussion §H3; Conclusion
- Text states (Results): “The three-way interaction term rural-hukou by female by pre-1965 in specification R5 returns a coefficient of minus 0.13 hours per week with a standard error of 1.28 (p = 0.92).”
- Text states (Abstract): “The intersectional triple-penalty hypothesis … is not supported: the three-way interaction is null (p = 0.92).”
- Text states (Discussion): “H3 is not supported. The three-way rural-by-female-by-pre-1965 interaction is statistically null (p = 0.92).”
- Text states (Conclusion): “p = 0.92”
- Source-document evidence (
analysis/limitations-accepted.md, “Late-caught CRITs,” entries CRIT-CORR-005 / CRIT-STAT-003): “scripts/05-decomposition.R lines 125–129 extracted the hukou_rural main-effect coefficient from R5 instead of the hukou_rural:female:pre1965 triple-interaction row. The reported H3 p = 0.92 is therefore the main-effect p, not the three-way-interaction p. Action: fixed in iter2 of the script … H3 verdict re-derived from the correct row, recorded as H3-CORRECTED in adjudication-log.csv.” - Problem: The four sections (Abstract, Results, Discussion, Conclusion) all attribute the value
p = 0.92to the triple-interaction row of R5, but per the recorded code-review CRIT, that p-value is the main-effect row. The triple-interaction p (the one the H3 hypothesis actually requires) is not reported anywhere in the manuscript prose. The H3-NOT-SUPPORTED verdict may still be correct under the corrected row, but the prose attributes the wrong row’s p-value to the H3 test, which is a number-mismatch between prose and the evidence the prose claims to be quoting. - Fix: (a) Replace
p = 0.92with the corrected triple-interaction row p-value fromadjudication-log.csv(H3-CORRECTED) in all four locations; (b) re-state the coefficient (currently −0.13) and SE (currently 1.28) from the correct row; (c) re-derive the H3 verdict from the corrected row and update Abstract/Results/Discussion/Conclusion adjudications accordingly. - Severity: CRITICAL — same value mis-cited in four sections; affects the central H3 adjudication.
- [CRIT-TXT-002] Methods §estimator + §robustness — Y2 focal estimator labeling
- Text states (Methods): “For Y2, the M3 estimator is OLS (linear hours) with the same SE structure and an MLE Tobit cross-check…”
- Text states (Results): “The Tobit MLE cross-check on the same specification returns minus 1.31 (SE 0.144), confirming the linear-feols magnitude under the alternative likelihood.”
- Source-document evidence (
limitations-accepted.md, CRIT-STAT-001): “focal Y2.M3 is feols (OLS with FE), not Tobit MLE… the manuscript Methods should describe Y2.M3 as OLS with FE plus a Tobit MLE robustness check.” - Status: The manuscript Methods text now correctly states M3 is OLS with Tobit as cross-check. The Abstract still says “logit, linear, and Tobit specifications” which is consistent if read as a list of estimators used somewhere in the paper, not as the focal estimator. Apparent agreement between Methods statement and corrected interpretation. Not a logic CRIT against current draft, but flagged to confirm Phase 7 fix landed.
- Severity: RESOLVED in current draft text; verify alignment when reviewing supplementary tables.
────────────────────────────────────────────────────────────────────────────
WARNINGS
- [WARN-TXT-001] Results §Oaxaca decomposition vs. Results §Table 1 raw gap
- Text states (Oaxaca para): “The total rural-urban Y2 gap implied by the decomposition is +0.82 hours per week.”
- Text states (Table 1 description, two paragraphs later): “the conditional-on-user weekly-hours mean is 12.7 hours per week (rural) versus 14.5 hours per week (urban), a raw 1.8-hour gap.”
- Issue: The manuscript reports two different “rural-urban Y2 gap” magnitudes (0.82 vs 1.8) without explicitly reconciling that the Oaxaca decomposition operates on a different analytic sub-sample / weighting than the Table 1 descriptive means. A careful reader will compute (1.8 − 1.31)/1.8 ≈ 27% absorbed (text says “approximately 30 percent”) which uses 1.8 as the gap, but the abstract claims 0.82 as “total.” Both are correct but are not the same quantity.
- Fix: Add one sentence in the Oaxaca paragraph clarifying: “The Oaxaca total of +0.82 hours differs from the Table 1 raw means difference of 1.8 hours because the decomposition is computed on the M3 estimation sample with covariate-adjusted urban means rather than on raw cell means.”
- Severity: WARNING — both numbers are individually defensible; the reader-facing inconsistency is a presentation issue.
- [WARN-TXT-002] Results §H4 — “partial support” with p = 0.054
- Text states: “Co-residence with a digital-native household member … is associated with +0.59 hours per week … (SE 0.305; p = 0.054) and +1.07 hours per week in the within-person fixed-effects specification (SE 0.634).”
- Text states (Discussion): “H4 receives modest support as a secondary mechanism finding.”
- Issue: p = 0.054 with the conventional 0.05 threshold normally would not support a positive verdict. Manuscript’s hedge (“partial / modest support”) is consistent across Results and Discussion, and the FE coefficient is much larger (+1.07), so the soft framing is defensible — but on the focal cross-sectional spec alone, calling this “support” is generous.
- Fix: Either tighten language to “marginal” / “borderline” or add an explicit sentence noting that the cross-sectional p exceeds the 0.05 threshold and that the verdict rests jointly on the FE estimate’s larger magnitude.
- Severity: WARNING.
- [WARN-TXT-003] Results §H2 cohort gradients — “ordered” claim
- Text states: “the M3 cohort gradients on Y2 are large and ordered as the cohort-as-cause account predicts: relative to the pre-1955 reference cohort, the 1956-1965 band sits 3.6 hours per week lower, 1966-1975 sits 4.4 hours per week lower, 1976-1985 sits 4.1 hours per week lower, 1986-1995 sits 1.6 hours per week lower, and 1996+ sits 4.5 hours per week lower (the apparent reversal at 1996+ is driven by a small in-school subsample…).”
- Issue: The numerical sequence (−3.6, −4.4, −4.1, −1.6, −4.5) is not monotonically ordered in either direction: the gradient becomes more negative from 1956-65 to 1966-75 (opposite of cohort-as-cause prediction), recovers between 1966-75 and 1986-95, then plunges again at 1996+. Manuscript flags only the 1996+ reversal as an artifact; the 1956-65 → 1966-75 → 1976-85 non-monotonicity is not addressed. The claim “ordered as the cohort-as-cause account predicts” is therefore overstated.
- Fix: Soften language to “broadly consistent with cohort gradients” and acknowledge the non-monotonic interior pattern, OR explain that the pre-1955 reference is itself a small/extreme cell that distorts the contrast.
- Severity: WARNING — non-monotonic pattern is partially explained (1996+) but not fully (interior).
- [WARN-TXT-004] Discussion / Conclusion magnitude rounding (“approximately 1.3”)
- Text states (Discussion): “agricultural-hukou status reduces weekly internet use among users by approximately 1.3 hours per week.”
- Text states (Results / Abstract): “minus 1.31 hours per week.”
- Issue: Rounding 1.31 → 1.3 is acceptable but technically each rounding compounds when discussed in compounded form (“a 1.31-hour residual … approximately 30 percent of the raw gap absorbed”). All within tolerance, but worth one consistent decimal-place convention.
- Fix: Adopt a uniform decimal-place convention across Abstract/Results/Discussion/Conclusion.
- Severity: WARNING (low).
- [WARN-TXT-005] Robustness range claim
- Text states (Results §robustness): “the rural-hukou coefficient on Y2 sits between minus 0.89 and minus 2.23”
- Issue: The manuscript reports M1 = −2.23, M2 = −1.65, M3 = −1.31, R2 (IPW) = −1.31, R4 (Deaton-Paxson) = −1.65. None of the in-prose specifications gives −0.89; the lower bound of the range is therefore from one of the unreported supplementary specifications (likely R6 stable-core or R5b wave-interacted). The reader cannot verify the −0.89 endpoint from in-prose tables.
- Fix: Cite the specific spec that yields −0.89 (e.g., “R5b 2018 wave-interacted estimate”) so the reader can locate the source.
- Severity: WARNING.
────────────────────────────────────────────────────────────────────────────
HYPOTHESIS ADJUDICATION TABLE
| Hypothesis | Prediction | Table/Spec | Result in Prose | Manuscript Verdict | Correct given current draft? |
|---|---|---|---|---|---|
| H1 (hukou persistence) | rural − on Y1 (narrowing); rural − on Y2 (stable) | Table 1 (Y1) M3; Table 2 (Y2) M3; Fig 3 wave-interaction | Y1: b=−0.85, BH-FDR p<1e-60; Y2: b=−1.31, BH-FDR p=1.39e-5; Y2 wave-interacted between −1.0 and −1.5 (flat); Y1 narrows ~−1.0 → ~−0.6 | SUPPORTED (both legs) | YES |
| H2 (cohort layering) | sharp cohort gradients; flat within-person age slope | M3 cohort coefs; R1 within-person FE | gradients large but non-monotonic; within-person age slope ≈ 0 | DESCRIPTIVELY SUPPORTED, formally DEFERRED (HAPC variance-share not run) | PARTIALLY — see WARN-TXT-003 on monotonicity |
| H3 (intersectional triple penalty) | rural × female × pre-1965 < 0, larger than additive sum | R5 three-way interaction; Table 4 cells; Fig 6 | b=−0.13, SE=1.28, p=0.92 (but per limitations-accepted, p=0.92 is the main-effect row, not the triple-interaction row) | NOT SUPPORTED | INCONCLUSIVE — see CRIT-TXT-001. The p-value cited is from the wrong R5 row; the corrected triple-interaction p (in adjudication-log.csv H3-CORRECTED) should replace 0.92 in prose. The verdict (NOT SUPPORTED) may stand under the corrected row but the cited evidence is wrong. |
| H4 (household spillover) | + effect of co-resident young adult on Y1, Y2 | M3 cross-section; FE variant | b=+0.59, p=0.054 (cross-section); b=+1.07 (FE) | PARTIAL / MODEST SUPPORT (secondary) | YES with caveat — see WARN-TXT-002 |
────────────────────────────────────────────────────────────────────────────
CROSS-SECTION CONTRADICTIONS
- [CONTRA-001] Oaxaca total gap (0.82) vs Table 1 raw gap (1.8)
- See WARN-TXT-001 above. Same finding described with two different “total gap” numbers in adjacent paragraphs without reconciling them.
(No other contradictions: Abstract numbers (−1.31, −0.85, +1.15, −0.40, p=0.92), Results numbers, Discussion numbers, and Conclusion numbers all match each other. Caveat: all four sections share the H3 row-extraction error documented in CRIT-TXT-001, so the consistency is “consistently wrong-rowed.”)
────────────────────────────────────────────────────────────────────────────
CAUSAL LANGUAGE AUDIT
| Location | Text | Design | Appropriate? |
|---|---|---|---|
| Abstract, Conclusion | “agricultural-hukou status reduces weekly use by 1.31 hours” | Observational logit/OLS with province-by-wave FE; current hukou (not birth hukou); no IV, no discontinuity | BORDERLINE — The Methods explicitly disclaims causal identification (“future research should … an instrument for hukou … CFPS does not supply”), and the Discussion frames hukou as institutional sorting rather than a manipulable cause. The verb “reduces” should be replaced with “is associated with X fewer hours” or “predicts X fewer hours” in the Abstract and Conclusion to match the design. |
| Results §Y2 ladder | “rural-hukou coefficient is minus 2.23 hours per week … indicating that rural-hukou users report on average 2.23 fewer weekly hours” | Same | OK — this phrasing is descriptive (“report on average”) |
| Discussion §implications | “the policy lever is not simply equalizing access … it runs through the institutional opportunity structure” | Same | OK — appropriately frames as structural rather than causal |
| Discussion §objection | Acknowledges that “Distinguishing these mechanisms cleanly would require an instrument for hukou or a discontinuity-design exploiting hukou-conversion thresholds, which CFPS does not supply” | Same | EXEMPLARY — explicit disclaimer present |
Single recommendation: replace “reduces” with “is associated with a reduction of” in Abstract and Conclusion to match the explicit causal-design disclaimer in the Discussion.
────────────────────────────────────────────────────────────────────────────
ABSTRACT ACCURACY
| Abstract Claim | Source in Manuscript | Verified? | Notes |
|---|---|---|---|
| “N = 204,418 person-waves; 54,825 unique respondents” | Methods §sample | YES | Matches |
| “Y2 rural-hukou coef = −1.31 (SE 0.295; BH-FDR p = 1.39e-5)” | Results Table 2 M3 | YES | Internally matches Results |
| “Y1 rural-hukou logit coef = −0.85 (BH-FDR p < 1e-60)” | Results Table 1 M3 | YES | Matches |
| “Total Oaxaca gap = 0.82 hours/week” | Results Oaxaca para | YES | Matches; differs from raw 1.8-hour gap (see WARN-TXT-001) |
| “Coefficients component = +1.15 hours” | Results Table 3 | YES | Matches; +141% of 0.82 ≈ correct |
| “Endowments component = −0.40 hours” | Results Table 3 | YES | Matches; −49% of 0.82 ≈ correct |
| “H3 three-way interaction is null (p = 0.92)” | Results §H3 | NO — see CRIT-TXT-001 | The 0.92 is the main-effect-row p in R5, not the triple-interaction-row p; the actual three-way-interaction p is recorded in adjudication-log.csv H3-CORRECTED row |
────────────────────────────────────────────────────────────────────────────
CLAIM VERIFICATION LOG (representative)
| # | Claim (abbreviated) | Source spec | Prose value | Match across sections? |
|---|---|---|---|---|
| 1 | Y2 M3 rural coef = −1.31 | T2 M3 | −1.31 (Abstract, Results, Discussion, Conclusion) | YES |
| 2 | Y2 M3 SE = 0.295 | T2 M3 | 0.295 (Abstract, Results) | YES |
| 3 | Y2 M3 BH-FDR p = 1.39e-5 | T2 M3 | 1.39e-5 (Abstract, Results, Conclusion) | YES |
| 4 | Y2 M1 rural coef = −2.23 | T2 M1 | −2.23 (Results) | YES |
| 5 | Y2 M2 rural coef = −1.65 | T2 M2 | −1.65 (Results) | YES |
| 6 | Tobit MLE Y2 coef = −1.31 (SE 0.144) | Robustness | −1.31 / 0.144 (Results) | YES |
| 7 | Y1 M3 rural coef = −0.85 | T1 M3 | −0.85 (Abstract, Results, Discussion, Conclusion) | YES |
| 8 | Y1 M3 SE = 0.051 | T1 M3 | 0.051 (Results) | YES |
| 9 | Y1 M1 rural coef = −1.71 | T1 M1 | −1.71 (Results) | YES |
| 10 | Y1 within-person FE coef = −0.72 (SE 0.077) | R1 | −0.72 / 0.077 (Results, robustness) | YES |
| 11 | Oaxaca total = +0.82 | T3 | +0.82 (Abstract, Results) | YES |
| 12 | Oaxaca endowments = −0.40 (−49%) | T3 | −0.40 / −49% (Abstract, Results, Conclusion) | YES |
| 13 | Oaxaca coefficients = +1.15 (+141%) | T3 | +1.15 / +141% (Abstract, Results, Conclusion) | YES |
| 14 | Oaxaca interaction = +0.06 (+7%) | T3 | +0.06 / +7% (Results) | YES |
| 15 | H3 three-way: b=−0.13, SE=1.28, p=0.92 | R5 | reported across 4 sections | NO — wrong R5 row per limitations-accepted CRIT-CORR-005 / CRIT-STAT-003 |
| 16 | H4 cross-section coef = +0.59, p=0.054 | M3 H4 | +0.59 / 0.054 (Results) | YES |
| 17 | H4 FE coef = +1.07, SE=0.634 | R1 H4 | +1.07 / 0.634 (Results) | YES |
| 18 | Y2 2014 mean = 11.9; 2018 mean = 14.7 | T1 wave means | 11.9, 14.7 (Abstract, Results) | YES |
| 19 | Y2 rural mean 2014-18 = 12.7; urban = 14.5 | T1 hukou means | 12.7, 14.5 (Results) | YES |
| 20 | Raw rural-urban Y2 gap = 1.8 hrs | derived | 1.8 (Results) | YES (but differs from Oaxaca total 0.82 — see CONTRA-001) |
| 21 | “30% absorbed by M3 / 70% persists” | derived (1.31/1.8) | matches arithmetic 27%/73% ≈ 30%/70% | YES |
| 22 | Cohort gradient 1956-65 = −3.6 | T2 M3 cohort coefs | −3.6 (Results) | YES |
| 23 | Cohort gradients ordered as predicted | claim | non-monotonic interior | NO — see WARN-TXT-003 |
| 24 | Y1 2010 wave-interacted ≈ −1.0; 2020 ≈ −0.6 | Fig 3 / R5b | −1.0 / −0.6 (Results, Discussion) | YES |
| 25 | Y2 wave-interacted between −1.0 and −1.5 (flat) | R5b | −1.0 to −1.5 (Results, Discussion) | YES |
| 26 | Robustness Y2 range: −0.89 to −2.23 | unspecified | endpoints don’t both appear in prose | PARTIAL — see WARN-TXT-005 |
| 27 | Y1 robustness range: −0.72 to −1.71 | various | both endpoints traceable | YES |
| 28 | Stable-core 2014+ M5 Y1 coef = −0.85 | M5 | −0.85 (Results) | YES (matches M3) |
| 29 | Deaton-Paxson R4 Y2 coef = −1.65 | R4 | −1.65 (Results) | YES (matches M2) |
| 30 | IPW R2 Y2 coef = −1.31 | R2 | −1.31 (Results) | YES (matches M3) |
| 31 | Hukou conversion < 2% of person-waves | Methods | < 2% | YES (used twice consistently) |
| 32 | Sample 119,259 rural / 35,762 urban / 49,397 missing | Methods | YES | YES |
| 33 | Wave-level Ns: 33,595 / 35,716 / 37,140 / 36,833 / 34,734 / 26,400 | Methods T1 | YES | YES |
| 34 | Y1 M3 sample = 108,526 person-waves | Methods | 108,526 (Methods); 108,509 (Abstract) | NEAR-MATCH — Abstract says “108,509”, Methods says “108,526”. Discrepancy of 17 person-waves. |
| 35 | “1.31-hour residual” in Discussion limitations | Discussion | matches Results | YES |
────────────────────────────────────────────────────────────────────────────
ADDITIONAL DISCREPANCY NOT IN MAIN TABLE
[CRIT-TXT-003] Y1 M3 sample size mismatch
- Abstract: “the focal Y2 model and reduces the log-odds of access by 0.85” — and elsewhere in opening “Y1 spec ladder uses 148,599 person-waves in M1 and 108,526 person-waves in M2/M3”
- Methods §sample-disclosure: “108,526 person-waves in M2/M3”
- Methods earlier paragraph: “the focal M3 specification, which conditions on the full set of M3 covariates, retains 108,509 person-waves”
- Problem: Two different Y1 M3 sample sizes given in Methods (108,526 vs 108,509). One must be the typo. 17-person-wave discrepancy.
- Fix: Reconcile against the locked snapshot model-fit object’s
nobs. - Severity: CRITICAL (small magnitude but contradiction inside Methods).
────────────────────────────────────────────────────────────────────────────
VERDICT
NEEDS-REVISION
Primary issues:
- CRIT-TXT-001 — H3 cited p-value (0.92) attributed to triple-interaction row but per
limitations-accepted.mdLate-caught CRITs is the main-effect row; replace with corrected p fromadjudication-log.csvH3-CORRECTEDand re-derive verdict (in 4 sections). - CRIT-TXT-003 — Y1 M3 sample size internal contradiction (108,526 vs 108,509) within Methods.
- WARN-TXT-001 — Reconcile Oaxaca total (0.82) vs raw gap (1.8) with one explanatory sentence.
- WARN-TXT-003 — Soften the “ordered as cohort-as-cause predicts” claim or explain the interior non-monotonicity (1956-65 → 1966-75 → 1976-85).
- WARN-TXT-002, WARN-TXT-005 — minor strengthening.
- Causal-language audit — replace “reduces” with “is associated with a reduction of” in Abstract and Conclusion.
Secondary observation: numerical consistency across Abstract, Results, Discussion, and Conclusion is otherwise excellent (35 of 35 cross-section number checks match), with the H3 row-extraction issue being the dominant load-bearing error.
Appendix J — verify-completeness Report (full)
File: output/digital-divide-china-cfps/ verify/verify-completeness-2026-05-04.md. Stage-2 completeness audit: artifact chain integrity, marker placement, orphan check, table renumbering recommendation. Verdict: NEEDS-REVISION (1 CRIT, 5 WARN).
SCANNED: 30 raw artifacts, 10 manuscript artifacts (4 tables + 6 figures), 23 in-text references
VERIFICATION REPORT: ARTIFACT COMPLETENESS & CROSS-REFERENCE INTEGRITY
Project: digital-divide-china-cfps Manuscript: drafts/draft-manuscript-digital-divide-china-cfps-2026-05-04.md Locked snapshot: results-locked/2026-05-04-1722/ Date: 2026-05-04
SUMMARY
- Raw output files in locked snapshot: 30 artifacts (21 table-side files, 7 figure-side files, 2 verify files)
- Distinct figure assets (PDF): 6 (fig1…fig6)
- Distinct table assets (Y1 ladder, Y2 ladder, descriptives, oaxaca, intersection): 5 primary + many supporting registries
- Manuscript figures referenced (Figures 1-6): 6
- Manuscript tables referenced (Tables 1-4): 4
- “[X about here]” markers: 10 (Figures 1,2,3,4,5,6 + Tables 1,2,3,4)
- Full chain verified (raw -> manuscript -> text): 9/10
- Broken chains: 1 (Table 1 has dual identity — see CRIT-REF-001)
FULL ARTIFACT CHAIN MAP
| # | Locked Raw Output | Manuscript Artifact | Marker Line | First Discussion | Chain Status |
|---|---|---|---|---|---|
| 1 | figures/fig1-access-trend.pdf (+fig1-access-trend-data.csv) | Figure 1 (access trend) | 111 | 113 | COMPLETE |
| 2 | figures/fig2-Y2-by-cohort.pdf | Figure 2 (cohort trajectories) | 131 | 133 | COMPLETE |
| 3 | figures/fig3-hukou-coef-trajectory.pdf | Figure 3 (Y1 wave coef) | 121 | 123, 151 | COMPLETE |
| 4 | figures/fig4-Y2-by-hukou-cohort.pdf | Figure 4 (Y2 by hukou*cohort) | 145 | 147, 153 | COMPLETE |
| 5 | figures/fig5-oaxaca-decomp.pdf | Figure 5 (Oaxaca) | 127 | 129 | COMPLETE |
| 6 | figures/fig6-intersection-cells.pdf | Figure 6 (intersection cells) | 137 | 139 | COMPLETE |
| 7 | tables/table1-descriptives.{csv,html} | Table 1 (descriptives) — see CRIT-REF-001 | 119 | 143 | DEGRADED |
| 8 | tables/table-Y1-models.{csv,html,tex} (+y1-focal-hukou.csv,spec-registry-Y1.csv) | Table (Y1 ladder, no clean number) | (none) | 123 (mislabeled “Table 1”) | BROKEN (no marker; mis-labeled) |
| 9 | tables/table-Y2-models.{csv,html,tex} (+y2-focal-hukou.csv,y2-ame.csv,spec-registry-Y2.csv) | Table 2 (Y2 ladder) | 115 | 117 | COMPLETE |
| 10 | tables/oaxaca-decomp.csv | Table 3 (Oaxaca) | 125 | 129 | COMPLETE |
| 11 | tables/intersection-cells.csv | Table 4 (intersection cells) | 135 | 139 | COMPLETE |
| 12 | tables/{spec-registry,results-registry,fdr-focal,curation-plan,adjudication-log,missing-by-wave}.csv | (none — supporting registries) | — | — | INFO (orphaned in locked snapshot, but expected; SI/audit assets) |
| 13 | verify/runtime-sanity-2026-05-04.md, verify/mt-correction-report.md | (none — audit notes) | — | — | INFO |
CRITICAL ISSUES
####### [CRIT-REF-001] Table 1 has dual identity / Y1 ladder lacks its own table number
The manuscript uses the label “Table 1” for two distinct artifacts:
- Line 119 marker
[Table 1 about here]followed (line 123) by prose:“The corresponding access (Y1) ladder (Table 1) shows the predicted convergence pattern. The M1 rural-hukou logit coefficient is minus 1.71…”
This refers to the Y1 model ladder (locked at
tables/table-Y1-models.{csv,html,tex}). - Line 143 prose:
“Table 1 reports the descriptive composition of the analytic sample by hukou status. The rural-hukou subsample is on average 4.6 years older…”
This refers to the descriptives table (locked at
tables/table1-descriptives.{csv,html}).
Both content blocks exist as locked raw outputs, but the manuscript collapses them under one number. This is a DUPLICATE NUMBER problem AND an UNREFERENCED ARTIFACT problem simultaneously:
- Two physically distinct tables share the label “Table 1”.
- The Y1 model ladder (
table-Y1-models.*, the primary Y1 result asset) has no unambiguous number, no caption, and no[Table N about here]marker assigned to it specifically. - The descriptives table has prose discussion (line 143) but no
[Table N about here]marker (the line-119 marker is consumed by the Y1 ladder discussion at line 123).
Action: renumber. Recommended fix: relabel descriptives as Table 1, Y1 ladder as Table 2, Y2 ladder as Table 3, Oaxaca as Table 4, intersection-cells as Table 5; insert separate [Table N about here] markers for each; rewrite line 119–123 so the Y1 ladder gets its own marker and its own anchor sentence; or keep the descriptives implicit in the text and number Y1 ladder as Table 1 throughout. Either fix is acceptable but the current state ships two artifacts under one label.
Severity: CRITICAL.
WARNINGS
####### [WARN-REF-001] Figure 3 referenced before its marker Line 121 inserts [Figure 3 about here] after Table 1 marker (line 119) but Figures 1 and 2 are intercalated with Table markers. The numbering is non-sequential by appearance:
- Marker order in prose: Fig 1 (111), Tab 2 (115), Tab 1 (119), Fig 3 (121), Tab 3 (125), Fig 5 (127), Fig 2 (131), Tab 4 (135), Fig 6 (137), Fig 4 (145).
- Reading order: Fig 1, Tab 2, Tab 1, Fig 3, Tab 3, Fig 5, Fig 2, Tab 4, Fig 6, Fig 4.
The “first mention rule” (artifacts referenced in numerical order) is violated. Tables: 2 before 1; Figures: 3 before 2, 5 before 4, 6 before 4. This will not block submission but copy-editors flag it.
Action: reorder markers/discussion or renumber figures and tables to match presentation order. Strongly recommended for Social Forces house style.
Severity: WARNING.
####### [WARN-REF-002] Figure 1 caption / Y2-trend reference uses “(Figure 1)” but data referenced not all in fig1 Line 113 attributes both the Y1 access trend AND the Y2 conditional-on-user means to “Figure 1”. The locked fig1-access-trend.pdf plots Y1 access trend (the supporting CSV fig1-access-trend-data.csv confirms this is the access-trend asset). The Y2 mean rises (11.9 -> 14.7 hours) cited in prose are not visualized in fig1 — they appear to be derived from tables/missing-by-wave.csv or y2-focal-hukou.csv rather than from a figure.
Action: either add the Y2 trend to Figure 1 (paneled), reference Table 1/Table 2 for the Y2 numbers in line 113, or split into Figure 1a/1b.
Severity: WARNING.
####### [WARN-REF-003] Multiple supporting CSVs orphaned in locked snapshot The locked snapshot contains supporting/registry CSVs not directly referenced by any manuscript figure or table number:
tables/spec-registry.csv(referenced obliquely line 97: “the registry, together with the spec-by-spec adjudication log and the FDR-focal table, is archived in the locked results snapshot”)tables/spec-registry-Y1.csv,tables/spec-registry-Y2.csvtables/results-registry.csvtables/fdr-focal.csvtables/curation-plan.jsontables/adjudication-log.csvtables/missing-by-wave.csvtables/y1-focal-hukou.csv,tables/y2-focal-hukou.csv,tables/y2-ame.csvfigures/fig1-access-trend-data.csv(data for Figure 1 — not orphaned, paired)
These appear to be SI / audit assets per line 97 (“archived in the locked results snapshot”). Recommend an explicit Supplementary Information appendix listing these so they are not silently orphaned.
Severity: WARNING.
####### [WARN-REF-004] No appendix / SI section in manuscript draft The Methods section refers to robustness checks “reported in the robustness section” (line 89), to “supplementary material” (lines 97, 99, 105, 169), and to deferred items (Y3, log_pc_income, HAPC variance test). The draft has no Appendix or Supplementary Information section that would house these — the paper ends at line 189 References placeholder.
If “supplementary material” is a separate file to be authored later, this is acceptable but should be flagged in Phase 8 / submission packaging. If supplementary content was supposed to be inline, several locked artifacts (spec-registry, fdr-focal, missing-by-wave) belong there.
Severity: WARNING.
####### [WARN-REF-005] [CITATION NEEDED] markers used as numeric placeholders The draft uses [CITATION NEEDED] after numerical estimates (e.g., line 117: “minus 1.31 [CITATION NEEDED] hours per week”) rather than as bibliographic citations. This is an unconventional use of the marker — the underlying numbers are present and locked in table-Y2-models.csv and y2-focal-hukou.csv, so the marker semantics are misleading. Phase 8 references resolution will not change these numerics.
Action: either drop the [CITATION NEEDED] from numeric estimates (numbers are sourced from locked tables, no citation required) or replace with [verified vs. table-Y2-models.csv] so Phase 8 does not waste effort. The References section placeholder at line 189 is correctly marked.
Severity: WARNING (cosmetic, but will confuse the Phase 8 reference resolver).
CONTENT COMPLETENESS
| Manuscript Artifact | Marker present? | Caption/Title in draft? | Discussion within 30 lines? | Notes/N/Fit Stats? | Status |
|---|---|---|---|---|---|
| Figure 1 | YES (line 111) | NO (no caption block) | YES (line 113) | N/A | WARN: no caption |
| Figure 2 | YES (line 131) | NO | YES (line 133) | N/A | WARN: no caption |
| Figure 3 | YES (line 121) | NO | YES (line 123, 151) | N/A | WARN: no caption |
| Figure 4 | YES (line 145) | NO | YES (line 147, 153) | N/A | WARN: no caption |
| Figure 5 | YES (line 127) | NO | YES (line 129) | N/A | WARN: no caption |
| Figure 6 | YES (line 137) | NO | YES (line 139) | N/A | WARN: no caption |
| Table 1 (descriptives) | NO (marker at 119 captured by Y1 ladder) | NO | YES (line 143, +24 lines from marker — within 30) | NO | CRIT-REF-001 |
| Table (Y1 ladder) | shares marker 119 | NO | YES (line 123) | NO | CRIT-REF-001 |
| Table 2 (Y2 ladder) | YES (line 115) | NO | YES (line 117) | NO | WARN: no caption/notes |
| Table 3 (Oaxaca) | YES (line 125) | NO | YES (line 129) | NO | WARN: no caption/notes |
| Table 4 (intersection) | YES (line 135) | NO | YES (line 139) | NO | WARN: no caption/notes |
Caption blocks (formal “Figure N. Title. Note: …” structures) are missing for ALL figures and tables in the draft. This is a Phase 7b/8 task but should be flagged.
“[X about here]” MARKER -> PROSE WITHIN 30 LINES CHECK
| Marker (line) | Marker text | First prose mention | Distance | OK? |
|---|---|---|---|---|
| 111 | [Figure 1 about here] | “(Figure 1)” line 113 | +2 | YES |
| 115 | [Table 2 about here] | “(Table 2)” line 117 | +2 | YES |
| 119 | [Table 1 about here] | “(Table 1)” line 123 | +4 | YES (but ambiguous artifact — see CRIT-REF-001) |
| 121 | [Figure 3 about here] | “Figure 3” line 123 (“wave-interacted Y1 variant (Figure 3)”) | +2 | YES |
| 125 | [Table 3 about here] | “(Table 3 on oaxaca-decomp…” line 129 | +4 | YES |
| 127 | [Figure 5 about here] | “Figure 5” line 129 | +2 | YES |
| 131 | [Figure 2 about here] | “Figure 2 plots…” line 133 | +2 | YES |
| 135 | [Table 4 about here] | “(Table 4…” line 139 | +4 | YES |
| 137 | [Figure 6 about here] | “Figure 6” line 139 | +2 | YES |
| 145 | [Figure 4 about here] | “Figure 4 plots…” line 147 | +2 | YES |
All 10 markers have associated discussion within 30 lines. This check passes.
REFERENCES SECTION
Line 187-189:
#### References
[CITATION NEEDED] — to be resolved in Phase 8 from `citations/refs.bib`.
This matches the user’s expected placeholder format. Phase 8 deferral is correctly flagged. PASS.
ORPHAN CHECK (locked artifacts not cited in prose)
Locked figures (PDF assets):
- fig1, fig2, fig3, fig4, fig5, fig6 — ALL CITED.
- No orphan figures.
Locked primary tables:
- table1-descriptives — cited (line 143)
- table-Y1-models — cited (line 123, mislabeled as “Table 1”; see CRIT-REF-001)
- table-Y2-models — cited (line 117 as “Table 2”)
- oaxaca-decomp — cited (line 129 as “Table 3”)
- intersection-cells — cited (line 139 as “Table 4”)
Locked supporting/registry artifacts (not numbered tables; SI candidates):
- spec-registry.csv, spec-registry-Y1.csv, spec-registry-Y2.csv, results-registry.csv, fdr-focal.csv, curation-plan.json, adjudication-log.csv, missing-by-wave.csv, y1-focal-hukou.csv, y2-focal-hukou.csv, y2-ame.csv, fig1-access-trend-data.csv
- These are referenced collectively at lines 97 and 99 (“archived in the locked results snapshot,” “we deferred Y3 from the headline and reserve it for a Phase 7b iteration”) but not individually as Tables.
No primary-asset orphans. The supporting registries are SI-bound, not orphans.
SCRIPT TRACEABILITY
Manifest does not include a scripts/ lock_dir; lock_dirs = [“tables”,”figures”,”eda”,”verify”]. Script-level traceability is not in scope for the locked snapshot at this lock_id and was not verified here. INFO only.
VERDICT
NEEDS-REVISION
Blocking issues (must fix before submission):
- CRIT-REF-001 — Table 1 dual identity. Resolution: renumber tables so the Y1 ladder and the descriptives table each have their own number, marker, and prose anchor. Recommended renumbering: Table 1 = descriptives, Table 2 = Y1 ladder, Table 3 = Y2 ladder, Table 4 = Oaxaca, Table 5 = intersection-cells (with corresponding Table-N-about-here marker reorder and in-text relabeling).
Non-blocking but recommended (can be deferred to Phase 7b/8):
- WARN-REF-001 — Reorder markers/numbering to follow first-mention sequence.
- WARN-REF-002 — Clarify what “Figure 1” depicts; the prose mixes Y1-trend (in fig1) and Y2-mean (not in fig1).
- WARN-REF-003 — Add SI/Appendix listing the locked registry CSVs.
- WARN-REF-004 — Decide whether SI is in-document or separate; if in-document, draft it.
- WARN-REF-005 — Strip
[CITATION NEEDED]markers attached to numeric estimates; they will confuse Phase 8. - Captions/notes for all figures and tables are missing in the draft body — add canonical “Figure N. Title. Note: data source, N, FE, SE structure” blocks.
The figure-side chain is fully clean (6/6 figures covered, all markers within 30 lines, no orphans). The table-side chain has one CRITICAL labeling collision that must be resolved before submission.
Appendix K — Windows setup walkthrough
This appendix exists because the §2 install instructions assume a Unix-like shell. Windows participants need three extra steps before any of those commands work:
- Enable WSL2 (Windows Subsystem for Linux 2) and install Ubuntu.
- Install Windows Terminal as the host shell.
- From inside the Ubuntu shell, run the §2 install commands exactly as written.
After step 3 you are on the same path as macOS and Linux users; nothing else in this handbook needs to be adjusted for Windows.
Do not use PowerShell,
cmd.exe, or Git-Bash as your primary shell. Claude Code and Codex both run on Windows natively, but the open-scholar-skill PreToolUse hook is a Bash script that callsjqandpython3with POSIX semantics. The hook fails closed on Windows-native shells. WSL2/Ubuntu gives you a real Linux kernel where every part of the stack —bash,jq,python3,git,R, the skill plugin’s symlinks — works without modification.
K.1 Requirements
- Windows 10 (version 2004 / build 19041 or later) or Windows 11.
- An account with Administrator privileges (one-time, only for the WSL2 install).
- ~10 GB free disk space (the Ubuntu image is ~2 GB; the rest is for R + Python + your data).
- Internet access during install.
K.2 Step 1 — Install WSL2 and Ubuntu
Open PowerShell as Administrator (right-click the Start menu → “Windows Terminal (Admin)” or “PowerShell (Admin)”) and run:
PS> wsl --install -d Ubuntu-22.04
This one command enables the WSL feature, downloads the WSL2 kernel, and installs Ubuntu 22.04 LTS. Reboot the machine when Windows asks. After the reboot, the Ubuntu installer will pop up automatically and prompt you to create a Linux username and password (these are separate from your Windows credentials — pick something simple; you will type the password whenever you sudo).
If wsl --install reports that WSL is already installed, run instead:
PS> wsl --set-default-version 2
PS> wsl --install -d Ubuntu-22.04
PS> wsl --set-default Ubuntu-22.04
Confirm:
PS> wsl -l -v
NAME STATE VERSION
* Ubuntu-22.04 Running 2
The VERSION column must say 2. If it says 1, run wsl --set-version Ubuntu-22.04 2 and wait a few minutes for the conversion.
K.3 Step 2 — Install Windows Terminal
If you are on Windows 11, Windows Terminal is preinstalled. On Windows 10, install it from the Microsoft Store (search for “Windows Terminal”) or run from an Admin PowerShell:
PS> winget install --id Microsoft.WindowsTerminal
Open Windows Terminal and click the dropdown arrow next to the new-tab +. You should see Ubuntu-22.04 in the list. Click it. You are now inside a real Linux shell with a prompt like:
yourname@DESKTOP-XYZ:~$
Set Ubuntu as the default profile so new tabs open into Linux automatically: Settings → Startup → Default profile → Ubuntu-22.04.
K.4 Step 3 — Initial Ubuntu hardening
Run these once inside the Ubuntu shell (they are the same as on any fresh Ubuntu box):
$ sudo apt update && sudo apt -y upgrade
$ sudo apt -y install build-essential curl wget unzip ca-certificates \
software-properties-common gnupg lsb-release \
jq python3 python3-pip python3-venv git
$ git --version && jq --version && python3 --version
That gives you the bare minimum the §2 install needs. Everything else — Node.js, Claude Code, Codex, the open-scholar-skill plugin, R, the social-science packages — comes from §2 and §2.7 unchanged.
K.5 Where your files live
This is the most common source of Windows-user confusion. You have two filesystems:
- Windows side:
C:\Users\yourname\...(visible in File Explorer). - WSL2 / Ubuntu side:
/home/yourname/...(the Linux home; invisible to File Explorer by default).
The rules:
- Keep your project directories on the Linux side (
/home/yourname/projects/digital-divide-china-cfps). I/O is 5–20× faster there than on/mnt/c/Users/..., and the PreToolUse hook works correctly only on a Linux filesystem. - To access your Linux files from Windows File Explorer, type
\\wsl$\Ubuntu-22.04\home\yournamein the address bar (or just\\wsl.localhost\Ubuntu-22.04\...on Windows 11). Drag-and-drop and copy-paste work normally. - To access your Windows files from Ubuntu (e.g., a dataset you downloaded to
C:\Downloads), they appear under/mnt/c/Users/yourname/Downloads/. Use this only for one-off copies (cp /mnt/c/.../data.zip ~/projects/...) — do not run analyses against/mnt/c.
K.6 Editor integration (VS Code)
Most Windows participants want VS Code as the editor for files that live inside WSL2:
- Install VS Code for Windows from https://code.visualstudio.com.
- Install the “WSL” extension (publisher: Microsoft; ID
ms-vscode-remote.remote-wsl). - From the Ubuntu shell inside your project directory, run
code .. VS Code opens in a WSL-attached window — the bottom-left corner says “WSL: Ubuntu-22.04”. Every terminal pane in that window is already inside Ubuntu.
Do not open the same project from the Windows-native VS Code window via \\wsl$\...; line endings and file watchers get confused.
K.7 Then continue with §2.7
You are now indistinguishable from a macOS or Linux participant. Go back to §2.7 — “Let the agent install your research toolchain” and run the four prompts there. The agent will detect Ubuntu and use apt-based commands.
When §2.7.2 prompt (1) asks you to print your public key, paste it into GitHub from inside Windows Terminal — clip.exe is on PATH thanks to WSL2’s interop, so:
$ cat ~/.ssh/id_ed25519.pub | clip.exe
…copies the key straight to the Windows clipboard, ready to paste into github.com.
K.8 Native Windows install (not recommended, but supported)
If your IT policy forbids WSL2, you can run Claude Code and Codex on Windows natively. The constraints:
- Install Node.js LTS from https://nodejs.org (the
.msiinstaller also addsnpmto PATH). npm install -g @anthropic-ai/claude-codeandnpm install -g @openai/codexboth work.- Use Windows Terminal + PowerShell 7+ (not the legacy
cmd.exe). - Install Git for Windows from https://git-scm.com/download/win. During install, choose “Use Git from the Windows Command Prompt” and “Checkout as-is, commit Unix-style line endings.”
- Install Python via https://www.python.org/downloads/windows/ (tick “Add Python to PATH”). For R, use the official CRAN installer from https://cran.r-project.org/bin/windows/base/ plus RTools.
- Install
jqwithwinget install jqlang.jq(the open-scholar-skill PreToolUse hook needs it). - The PreToolUse hook script in
open-scholar-skill/scripts/gates/pretooluse-data-guard.shis Bash. Either (a) install Git-Bash and configure Claude Code’s hooks to invoke it underbash.exe, or (b) accept that data-safety guarding will not work on Windows-native installs and never read sensitive data with this setup.
The native path saves disk space but loses you the PreToolUse hook and a uniform shell. If you are doing research on real participant data, use WSL2.
K.9 Common Windows-only pitfalls
| Symptom | Cause | Fix |
|---|---|---|
claude not found after npm install -g ... inside WSL2 | npm installed binaries are under ~/.npm-global/bin and that’s not on PATH | echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc && exec bash |
bash: jq: command not found when running setup.sh | jq not installed on Ubuntu side | sudo apt install jq |
Slow file I/O when working in /mnt/c/... | Cross-filesystem boundary | Move the project under /home/yourname/projects/ |
| PreToolUse hook always blocks files | Project lives on /mnt/c/...; path canonicalization mismatches .claude/safety-status.json entries | Move project to /home/yourname/... and re-run /scholar-init |
RStudio won’t launch from inside WSL2 | RStudio is a GUI; WSL2 GUI support is OK on Win11, fragile on Win10 | Install RStudio for Windows natively; point it at the R that lives inside WSL2 only if you know what you’re doing, otherwise install a separate R on Windows |
Line endings cause git diff noise | Windows CRLF vs. Unix LF | Run git config --global core.autocrlf input once |
K.10 Verify the Windows setup
A successful Windows install ends with this exact handshake, run from inside Windows Terminal → Ubuntu-22.04 tab → your project directory:
$ wsl -l -v # (run this one in PowerShell) — VERSION must be 2
$ uname -a # Linux DESKTOP-... 5.x.x ... GNU/Linux
$ node --version # v20.x.x
$ claude --version # 2.x.y (current as of 2026-05 is in the 2.1.x range)
$ codex --version # codex-cli 0.130.0 or later
$ jq --version # jq-1.6 or later
$ pwd # /home/yourname/projects/...
If all seven commands return clean output, return to §2.4 and install the open-scholar-skill plugin. From there, Windows users follow the rest of the handbook unchanged.
Appendix L — Built-in command reference: Claude Code and Codex
Both tools carry a large set of built-in commands that the workshop never has time to walk through. This appendix lists them A–Z, with what each one does, so you can find the command you half-remember.
Verified 2026-08-04 against the official command reference (
code.claude.com/docs/en/commands) and, for Codex, extracted directly from the installedcodex-cli 0.145.0binary. This is the fastest-moving surface in either tool — commands appear, get renamed, and disappear between releases. Type/in either TUI to see what your build actually offers, and treat this appendix as a map rather than a contract. Availability also varies by platform, plan, and account.
L.1 Claude Code — built-in slash commands, A–Z
| Command | What it does |
|---|---|
/add-dir <path> | Add another working directory for file access in this session |
/advisor [model\|off] | Consult a second model for guidance; toggle the advisor tool |
/agents | Manage subagent configurations |
/background [prompt] | Detach the session to run as a background agent, freeing the terminal |
/branch [name] | Branch the conversation to try a different direction |
/btw [question] | Ask a quick side question without adding it to the conversation |
/cd <path> | Move this session to a new working directory |
/chrome | Configure Claude in Chrome settings |
/clear [name] | Start a new conversation with empty context (aliases /reset, /new) |
/color [color\|default] | Set the prompt-bar colour for this session |
/compact [instructions] | Free context by summarizing the conversation so far |
/config [key=value …] | Open the settings interface, or set settings directly (alias /settings) |
/context [all] | Visualize current context usage as a coloured grid |
/copy [N] | Copy the last assistant response to the clipboard |
/cost | Alias for /usage |
/desktop | Continue this session in the Claude Code desktop app (alias /app) |
/diff | Open an interactive viewer for uncommitted changes |
/exit | Exit the CLI (alias /quit) |
/export [filename] | Export the conversation as plain text |
/fast [on\|off] | Toggle fast mode |
/feedback [report] | Send product feedback |
/focus | Toggle the focus view |
/fork [prompt] | Copy this conversation into a new background session |
/goal [condition\|clear] | Keep working until a stated condition is met |
/heapdump | Write a JS heap snapshot for diagnosing memory use |
/help | Show help and available commands |
/hooks | View hook configurations for tool events (§5A, §6.4) |
/ide | Manage IDE integrations and show status |
/init | Initialize the project with a CLAUDE.md guide (§3.3) |
/insights | Generate a report analysing your Claude Code sessions |
/install-github-app | Install the Claude GitHub App for a repository |
/install-slack-app | Install the Claude Slack app |
/keybindings | Open your keyboard-shortcuts file |
/login · /logout | Sign in to / out of your Anthropic account |
/mcp [reconnect <server>\|enable\|disable] | Manage MCP servers and OAuth (§3.6) |
/memory | Edit CLAUDE.md memory files, or manage auto-memory |
/mobile | Show a QR code to download the mobile app (aliases /ios, /android) |
/model [model] | Switch model and save it as your default (§3.5) |
/passes | Share a free week of Claude Code |
/permissions | Manage allow / ask / deny rules (alias /allowed-tools; §3.1) |
/plan [description] | Enter plan mode directly from the prompt |
/remote-control | Continue this local session from another device |
/resume [name] | Return to an earlier conversation or checkpoint |
/rewind [target] | Roll code and conversation back to a checkpoint |
/sandbox | Open the sandbox panel — tabs, modes, and defaults in §5A |
/security-review [--fix] [target] | Check the diff for security vulnerabilities |
/simplify [--fix] [target] | Simplify the diff without changing behaviour |
/status | Show session status and settings |
/subtask <prompt> | Hand a side task to a subagent that reports back here |
/tasks | List background work for this session |
/teleport | Pull a web session into this terminal |
/test | Run tests and capture output |
/upgrade | Upgrade to Claude Code Pro |
/usage | Token usage and costs for this session |
/verify [--fix] [target] | Verify that code changes are correct |
/web [url] | Add a web page to the conversation |
L.2 Claude Code — bundled skills and workflows
These ship with Claude Code and are invoked the same way, but are skills rather than core commands:
| Command | What it does |
|---|---|
/autofix-pr [prompt] | Spawn a session that watches this branch’s PR and pushes fixes |
/batch <instruction> | Orchestrate large-scale changes across a codebase in parallel |
/claude-api [migrate\|managed-agents-onboard] | Load Claude API / Managed Agents reference material |
/code-review [low…max\|ultra] [--fix] [--comment] | Review the current diff (this is ultrareview at ultra) |
/dataviz [request] | Design guidance for charts, graphs, and dashboards |
/debug [description] | Enable debug logging and troubleshoot |
/deep-research <question> | Fan out web searches, cross-check sources, synthesize a cited report |
/design-login · /design-sync [hint] | Authorize and sync a React design system to Claude Design |
/doctor | Setup checkup that diagnoses and can fix issues (alias /checkup) |
/fewer-permission-prompts | Scan transcripts and propose an allowlist to cut prompts |
/loop [interval] [prompt] | Run a prompt repeatedly while the session stays open (alias /proactive) |
/review [pr#] | Fast single-pass read-only review of a GitHub pull request |
Two Claude Code commands are run from the shell, not the session: claude doctor (read-only install diagnostics without starting a session) and claude agents (monitor background sessions).
L.3 Codex — slash commands, A–Z
Extracted from the shipped codex-cli 0.145.0 binary, so this is what the workshop’s install actually offers. Note that the published Codex documentation currently describes a different command set from the released binary — where they disagree, believe your own / menu.
| Command | What it does |
|---|---|
/agent | Switch the active agent thread (also /subagents) |
/app | Continue this session in the Desktop app |
/apps | Manage apps (connectors) |
/approve | Approve one retry of a recent auto-review denial |
/archive | Archive this session and exit |
/clear | Clear the terminal and start a new chat |
/compact | Summarize the conversation to avoid hitting the context limit |
/copy | Copy the last response as markdown |
/debug-config | Show config layers and requirement sources, for debugging |
/delete | Permanently delete this session and exit |
/diff | Show the git diff, including untracked files |
/experimental | Toggle experimental features |
/feedback | Send logs to the maintainers |
/fork | Fork the current chat |
/goal | Set or view the goal for a long-running task |
/hooks | View and manage lifecycle hooks |
/ide | Include current selection, open files, and other IDE context |
/import | Import setup, this project, and recent chats from Claude Code |
/init | Create an AGENTS.md file with instructions for Codex |
/keymap | Remap TUI shortcuts |
/logout | Log out of Codex |
/mcp | List configured MCP tools (/mcp verbose for detail) |
/memories | Configure memory use and generation |
/mention | Attach / mention a file |
/model | Choose model and reasoning effort |
/new | Start a new chat mid-conversation |
/permissions | Choose what Codex is allowed to do (the approval policy) |
/pets | Choose or hide the terminal pet |
/plan | Switch to Plan mode |
/plugins | Browse plugins |
/ps · /stop | List background terminals · stop all of them |
/quit | Exit Codex |
/rename | Rename the current thread |
/resume | Resume a saved chat |
/review | Review my current changes and find issues |
/rollout | Print the rollout (session transcript) file path |
/sandbox-add-read-dir <abs path> | Let the sandbox read one extra directory (Windows) |
/setup-default-sandbox | Set up the elevated agent sandbox (Windows) |
/side · /btw | Start a side conversation in an ephemeral fork |
/skills | Use skills to improve how Codex performs specific tasks |
/statusline | Configure which items appear in the status line |
/status | Show session configuration and token usage |
/usage | View account usage, or a usage-limit reset |
/vim | Toggle Vim mode for the composer |
The binary also carries a syntax-highlighting theme picker, a terminal-title configurator, a communication-style picker, and a raw-scrollback toggle for copy-friendly selection; their exact invocation names could not be pinned from the binary, so check your / menu. test-approval, debug-m-drop, and debug-m-update are internal test hooks marked “DO NOT USE”.
L.4 Codex — shell subcommands
Unlike Claude Code, Codex puts substantial functionality in shell subcommands (codex-cli 0.145.0, codex --help):
| Subcommand | What it does |
|---|---|
exec (alias e) | Run Codex non-interactively — the form §23 uses for external review |
review | Run a code review non-interactively |
apply (alias a) | Apply Codex’s latest diff to the working tree via git apply |
resume / fork | Resume or fork a previous interactive session (--last for the most recent) |
archive / unarchive / delete | Manage saved sessions by id or name |
sandbox | Run commands inside a Codex-provided sandbox |
mcp / mcp-server | Manage external MCP servers · run Codex itself as an MCP server |
plugin | Manage Codex plugins |
login / logout | Manage authentication |
doctor | Diagnose install, config, auth, and runtime health |
update | Update Codex |
completion | Generate shell-completion scripts |
cloud | (experimental) Browse Codex Cloud tasks and apply changes locally |
app / app-server / remote-control | Desktop app and app-server tooling |
debug / features | Debugging tools · inspect feature flags |
Two flags matter for everything in this handbook: -c key=value overrides any ~/.codex/config.toml value (-c model="gpt-5.2-codex"), and --enable / --disable toggle named features.