skilldrop-cli 1.11.1 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +1 -1
  2. package/bin/skilldrop.js +46 -3
  3. package/catalogue.json +2 -1
  4. package/model-routing.json +4 -0
  5. package/package.json +1 -1
  6. package/packs/ai-engineering/skills/agent-config-review/evals/files/1/dot.gitignore +5 -0
  7. package/packs/ai-engineering/skills/agent-config-review/examples/inputs/tidewater-ingest/dot.gitignore +3 -0
  8. package/packs/ai-engineering/skills/agent-config-review/examples/python-repo-tighten.md +3 -3
  9. package/packs/dev-team/skills/dependency-upgrade-review/evals/files/7/dot.npmrc +3 -0
  10. package/packs/experience-design/skills/locale-check/SKILL.md +1 -1
  11. package/packs/experience-design/skills/locale-check/manifest.json +2 -2
  12. package/packs/frontend/skills/bundle-size-review/evals/files/9/dot.gitignore +5 -0
  13. package/packs/research/skills/manuscript-check/SKILL.md +121 -0
  14. package/packs/research/skills/manuscript-check/evals/eval_queries.json +30 -0
  15. package/packs/research/skills/manuscript-check/evals/evals.json +73 -0
  16. package/packs/research/skills/manuscript-check/evals/files/1/paper.md +56 -0
  17. package/packs/research/skills/manuscript-check/evals/files/2/paper.md +118 -0
  18. package/packs/research/skills/manuscript-check/evals/files/3/report.md +115 -0
  19. package/packs/research/skills/manuscript-check/evals/files/4/paper.md +79 -0
  20. package/packs/research/skills/manuscript-check/evals/files/5/chapter3.md +65 -0
  21. package/packs/research/skills/manuscript-check/examples/inputs/paper.md +56 -0
  22. package/packs/research/skills/manuscript-check/examples/retention-paper.md +48 -0
  23. package/packs/research/skills/manuscript-check/manifest.json +36 -0
  24. package/packs/research/skills/manuscript-check/scripts/manuscript_check.py +355 -0
  25. /package/packs/ai-engineering/skills/agent-config-review/evals/files/1/{.claude → dot.claude}/agents/db-migrator.md +0 -0
  26. /package/packs/ai-engineering/skills/agent-config-review/evals/files/1/{.claude → dot.claude}/agents/reviewer.md +0 -0
  27. /package/packs/ai-engineering/skills/agent-config-review/evals/files/1/{.claude → dot.claude}/settings.json +0 -0
  28. /package/packs/ai-engineering/skills/agent-config-review/evals/files/1/{.claude → dot.claude}/settings.local.json +0 -0
  29. /package/packs/ai-engineering/skills/agent-config-review/evals/files/1/{.mcp.json → dot.mcp.json} +0 -0
  30. /package/packs/ai-engineering/skills/agent-config-review/evals/files/2/{.cursor → dot.cursor}/mcp.json +0 -0
  31. /package/packs/ai-engineering/skills/agent-config-review/evals/files/4/quillstack/{.claude → dot.claude}/agents/release-notes.md +0 -0
  32. /package/packs/ai-engineering/skills/agent-config-review/evals/files/4/quillstack/{.claude → dot.claude}/settings.json +0 -0
  33. /package/packs/ai-engineering/skills/agent-config-review/evals/files/4/quillstack/{.mcp.json → dot.mcp.json} +0 -0
  34. /package/packs/ai-engineering/skills/agent-config-review/evals/files/5/{.github → dot.github}/workflows/codex-triage.yml.fixture +0 -0
  35. /package/packs/ai-engineering/skills/agent-config-review/examples/inputs/tidewater-ingest/{.claude → dot.claude}/settings.json +0 -0
  36. /package/packs/ai-engineering/skills/agent-config-review/examples/inputs/tidewater-ingest/{.mcp.json → dot.mcp.json} +0 -0
  37. /package/packs/ai-engineering/skills/agent-incident-response/evals/files/6/{.mcp.json → dot.mcp.json} +0 -0
  38. /package/packs/ai-engineering/skills/agent-incident-response/evals/files/7/{.github → dot.github}/workflows/ci.yml.fixture +0 -0
  39. /package/packs/ai-engineering/skills/mcp-pairing/evals/files/4/{.mcp.json → dot.mcp.json} +0 -0
  40. /package/packs/api-builder/skills/eval-harness-generator/evals/files/1/{SKILL.md → SKILL.md.fixture} +0 -0
  41. /package/packs/api-builder/skills/eval-harness-generator/evals/files/2/{SKILL.md → SKILL.md.fixture} +0 -0
  42. /package/packs/core/skills/context-graph/evals/files/9/{.env.example → dot.env.example} +0 -0
  43. /package/packs/dev-team/skills/agents-md-generator/evals/files/1/{.github → dot.github}/workflows/ci.yml.fixture +0 -0
  44. /package/packs/dev-team/skills/agents-md-generator/evals/files/5/{.github → dot.github}/workflows/ci.yml.fixture +0 -0
  45. /package/packs/dev-team/skills/codebase-tour/evals/files/1/{.github → dot.github}/workflows/ci.yml.fixture +0 -0
  46. /package/packs/dev-team/skills/codebase-tour/evals/files/2/{.github → dot.github}/workflows/ci.yml.fixture +0 -0
  47. /package/packs/dev-team/skills/codebase-tour/evals/files/3/{.github → dot.github}/workflows/ci.yml.fixture +0 -0
  48. /package/packs/dev-team/skills/codebase-tour/evals/files/4/{.env.example → dot.env.example} +0 -0
  49. /package/packs/dev-team/skills/codebase-tour/evals/files/4/{.github → dot.github}/workflows/ci.yml.fixture +0 -0
  50. /package/packs/dev-team/skills/codebase-tour/evals/files/5/{.env.example → dot.env.example} +0 -0
  51. /package/packs/dev-team/skills/codebase-tour/evals/files/5/{.github → dot.github}/workflows/ci.yml.fixture +0 -0
  52. /package/packs/dev-team/skills/dependency-upgrade-review/evals/files/1/{.github → dot.github}/workflows/ci.yml.fixture +0 -0
  53. /package/packs/dev-team/skills/dependency-upgrade-review/evals/files/2/{.github → dot.github}/workflows/ci.yml.fixture +0 -0
  54. /package/packs/dev-team/skills/dependency-upgrade-review/evals/files/2/{.github → dot.github}/workflows/release.yml.fixture +0 -0
  55. /package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/{.github → dot.github}/workflows/ci.yml.fixture +0 -0
  56. /package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/{.github → dot.github}/workflows/ci.yml.fixture +0 -0
  57. /package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/{.github → dot.github}/workflows/release.yml.fixture +0 -0
  58. /package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/{.nvmrc → dot.nvmrc} +0 -0
  59. /package/packs/dev-team/skills/dependency-upgrade-review/evals/files/6/{.github → dot.github}/workflows/ci.yml.fixture +0 -0
  60. /package/packs/dev-team/skills/dependency-upgrade-review/evals/files/6/{.github → dot.github}/workflows/integration.yml.fixture +0 -0
  61. /package/packs/dev-team/skills/dependency-upgrade-review/evals/files/7/{.github → dot.github}/workflows/ci.yml.fixture +0 -0
  62. /package/packs/dev-team/skills/dependency-upgrade-review/evals/files/7/{.lintwright.json → dot.lintwright.json} +0 -0
  63. /package/packs/dev-team/skills/dependency-upgrade-review/evals/files/7/{.nvmrc → dot.nvmrc} +0 -0
  64. /package/packs/dev-team/skills/sonar-onboard/evals/files/2/{.github → dot.github}/workflows/ci.yml.fixture +0 -0
  65. /package/packs/dev-team/skills/sonar-onboard/evals/files/2/{.gitlab-ci.yml → dot.gitlab-ci.yml} +0 -0
  66. /package/packs/frontend/skills/bundle-size-review/evals/files/5/{.browserslistrc → dot.browserslistrc} +0 -0
  67. /package/packs/frontend/skills/bundle-size-review/evals/files/6/{.browserslistrc → dot.browserslistrc} +0 -0
  68. /package/packs/frontend/skills/bundle-size-review/evals/files/8/{.browserslistrc → dot.browserslistrc} +0 -0
  69. /package/packs/frontend/skills/bundle-size-review/evals/files/9/{.github → dot.github}/workflows/size.yml.fixture +0 -0
  70. /package/packs/skill-engineering/skills/skill-review/evals/files/1/skills/changelog-writer/{SKILL.md → SKILL.md.fixture} +0 -0
  71. /package/packs/skill-engineering/skills/skill-review/evals/files/1/skills/pr-summary/{SKILL.md → SKILL.md.fixture} +0 -0
  72. /package/packs/skill-engineering/skills/skill-review/evals/files/2/invoice-chaser/{SKILL.md → SKILL.md.fixture} +0 -0
package/README.md CHANGED
@@ -65,7 +65,7 @@ Install one pack. Every role pack also brings `core` (intake, critique, review c
65
65
  - **Building on the Claude API:** `api-builder` — prompt caching, token budgets, eval generation, tool schemas. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/api-builder/)
66
66
  - **Moving between formats:** `converters` — Markdown to Word, Excel and HTML, files back to Markdown, and Mermaid diagrams checked and rendered. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/converters/)
67
67
  - **Designing the experience:** `experience-design` — information architecture, UX writing, content design, component specs, service blueprints. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/experience-design/)
68
- - **Researching a question:** `research` — research plans, cited source synthesis, competing hypotheses. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/research/)
68
+ - **Researching a question:** `research` — research plans, cited source synthesis, competing hypotheses, and a manuscript's citations and cross-references checked before submission. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/research/)
69
69
  - **Keeping the tracker straight:** `trackers` — backlog triage, weekly status from tracker data, briefs turned into issues. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/trackers/)
70
70
  - **Data and analytics:** `data-analytics` — metric definitions, SQL review, dashboard specs. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/data-analytics/)
71
71
  - **Governance, risk and compliance:** `grc` — DPIAs, SOC 2 evidence maps, risk registers, security questionnaire answers. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/grc/)
package/bin/skilldrop.js CHANGED
@@ -133,6 +133,8 @@ Options:
133
133
  --json machine-readable output for list | info | packs | agents | outdated | doctor —
134
134
  one JSON object on stdout, nothing else (for agents, scripts, CI)
135
135
  --with-related also install each skill's related companions (one level)
136
+ --replace replace a skill installed from a different catalogue that has the same
137
+ name (install refuses otherwise); the old folder is removed first
136
138
  --with-hooks also wire any hooks a skill declares (RFC-0006) — git pre-commit
137
139
  reminders and Claude Code session-start context; degrades where the
138
140
  target has no hook mechanism. Off by default so installs never touch
@@ -189,6 +191,15 @@ function splitSource(source) {
189
191
  const i = source.lastIndexOf("#");
190
192
  return i > 0 ? [source.slice(0, i), source.slice(i + 1)] : [source, ""];
191
193
  }
194
+ /* Two catalogue sources are the same catalogue when they name the same place, whatever ref or
195
+ spelling: git+https://host/o/r.git#abc, https://host/o/r and https://host/o/r/ are one source. */
196
+ function sourceId(source) {
197
+ if (!source || source === BUNDLED) return BUNDLED;
198
+ let s = splitSource(String(source))[0].trim().replace(/^git\+/, "").replace(/\/+$/, "").replace(/\.git$/, "");
199
+ if (/^[a-z]+:\/\//i.test(s)) s = s.replace(/^([a-z]+:\/\/[^/]+)/i, (h) => h.toLowerCase());
200
+ else s = path.resolve(s);
201
+ return s;
202
+ }
192
203
  function isPinned(source) { return !!source && SHA_RE.test(splitSource(source)[1]); }
193
204
 
194
205
  function fetchCatalog(source) {
@@ -1471,11 +1482,15 @@ function installUnits(args) {
1471
1482
  const policy = enforcePolicy(args.flags, cat, names, "skill");
1472
1483
  const { dest, ide } = target(args.flags);
1473
1484
  const contain = containmentFor(args.flags, cat, names, dest, ide, policy);
1474
- if (args.flags["dry-run"]) { planInstall(cat, names, dest, ide, args.flags); if (contain) applyContainment(contain, true); return; }
1485
+ const clashes = sourceClashes(cat, names, dest);
1486
+ if (args.flags["dry-run"]) { planInstall(cat, names, dest, ide, args.flags, clashes); if (contain) applyContainment(contain, true); return; }
1487
+ if (clashes.length && !args.flags.replace) die(clashMessage(clashes, cat, dest));
1475
1488
  fs.mkdirSync(dest, { recursive: true });
1476
1489
  const l = ledger(dest);
1477
1490
  const pipDeps = [], suggestions = new Set(), notes = [];
1478
1491
  for (const s of names) {
1492
+ // A replaced skill's folder goes first, so no file of the other catalogue's skill is left mixed in.
1493
+ if (clashes.some((c) => c.name === s)) fs.rmSync(path.join(dest, s), { recursive: true, force: true });
1479
1494
  const m = copyOne(cat, s, dest, ide, l, notes);
1480
1495
  if (fs.existsSync(path.join(skillDir(cat, s), "requirements.txt"))) pipDeps.push(s);
1481
1496
  for (const r of m.related || []) if (!names.includes(r) && !l.data[r]) suggestions.add(r);
@@ -1537,14 +1552,39 @@ function installUnits(args) {
1537
1552
  if (pk && pk["first-value"]) console.log("\n" + firstValueLines(pk).join("\n"));
1538
1553
  }
1539
1554
 
1555
+ /* Two catalogues can each ship a skill with the same name, and they are different skills. Copying
1556
+ one over the other would replace it silently and leave the first one's extra files mixed in, so
1557
+ install refuses unless asked (--replace), and says where each came from. */
1558
+ function sourceClashes(cat, names, dest) {
1559
+ const l = ledger(dest), out = [];
1560
+ for (const s of names) {
1561
+ const have = l.data[s];
1562
+ if (!have || isLoopEntry(have)) continue;
1563
+ if (sourceId(lsrc(have)) !== sourceId(cat.source)) out.push({ name: s, from: lsrc(have) });
1564
+ }
1565
+ return out;
1566
+ }
1567
+ function clashMessage(clashes, cat, dest) {
1568
+ const what = (src) => src === BUNDLED ? "skilldrop" : `'${src}'`;
1569
+ return clashes.map((c) => `'${c.name}' in ${dest} came from ${what(c.from)}; this install is from ${what(cat.source)}, a different skill with the same name.`).join("\n ") +
1570
+ "\n Nothing was installed. Keep the one you have, or replace it: rerun with --replace (the old folder is removed first)," +
1571
+ "\n or install into a separate folder with --dest <dir>.";
1572
+ }
1573
+
1540
1574
  /* install --dry-run: everything install would write, and nothing written. */
1541
- function planInstall(cat, names, dest, ide, flags) {
1575
+ function planInstall(cat, names, dest, ide, flags, clashes = []) {
1542
1576
  const l = ledger(dest);
1543
1577
  console.log(`dry run — nothing will be written. Target: ${dest} (${ide})\n`);
1544
1578
  for (const s of names) {
1545
1579
  const m = manifestOf(cat, s);
1546
1580
  const have = l.data[s];
1547
- const verb = !have ? "install" : lver(have) === m.version ? "reinstall" : `replace ${lver(have)} with`;
1581
+ const clash = clashes.find((c) => c.name === s);
1582
+ if (clash && !flags.replace) {
1583
+ console.log(`would refuse ${s}: installed from ${clash.from === BUNDLED ? "skilldrop" : clash.from}, a different catalogue (add --replace to replace it)`);
1584
+ continue;
1585
+ }
1586
+ const verb = clash ? `replace ${clash.from === BUNDLED ? "skilldrop" : clash.from}'s ${s} with` :
1587
+ !have ? "install" : lver(have) === m.version ? "reinstall" : `replace ${lver(have)} with`;
1548
1588
  const edits = editedFiles(dest, s, have);
1549
1589
  console.log(`would ${verb} ${s}@${m.version} -> ${path.join(dest, s)}`);
1550
1590
  if (edits.length) console.log(` overwrites your edits in: ${edits.join(", ")} (update keeps them; install does not)`);
@@ -1818,6 +1858,9 @@ function doctor(args) {
1818
1858
  for (const n of names) {
1819
1859
  const note = lsrc(data[n]) === BUNDLED && retiredNote(resolveCatalog(), n, isLoopEntry(data[n]));
1820
1860
  if (note) add("warn", note, `skilldrop uninstall ${n}${targetHint(args.flags)}, or keep it as it is; it will not update`);
1861
+ if (lsrc(data[n]) !== BUNDLED && !isLoopEntry(data[n]) && skillExists(resolveCatalog(), n))
1862
+ add("info", `${n} here came from '${lsrc(data[n])}'; skilldrop has its own ${n}, a different skill with the same name`,
1863
+ `keep it, or switch with: skilldrop install ${n} --replace${targetHint(args.flags)} (or install skilldrop's into another --dest)`);
1821
1864
  if (!fs.existsSync(path.join(dest, n))) add("error", `${n} is in the ledger but its folder is gone`, `skilldrop install ${n} (or uninstall ${n} to drop the record)`);
1822
1865
  else if (!data[n].file) {
1823
1866
  const loop = isLoopEntry(data[n]);
package/catalogue.json CHANGED
@@ -167,7 +167,8 @@
167
167
  "skills": [
168
168
  "hypothesis-comparison",
169
169
  "research-plan",
170
- "source-synthesis"
170
+ "source-synthesis",
171
+ "manuscript-check"
171
172
  ]
172
173
  },
173
174
  "define-and-trust-the-numbers": {
@@ -363,6 +363,10 @@
363
363
  "tier": "light",
364
364
  "rationale": "Measured (RFC-0073): on its held-out evals the light tier met 71% and 71% of checks in two tier trials, against standard's 71% and heavy's 71% and 71%, within 5 points of the best both times."
365
365
  },
366
+ "manuscript-check": {
367
+ "tier": "standard",
368
+ "rationale": "Citation and cross-reference matching come from the script; reading the reference list for style consistency is bounded."
369
+ },
366
370
  "mcp-pairing": {
367
371
  "tier": "standard",
368
372
  "rationale": "Matching a loop's stages to the context each needs and the narrowest access that provides it is bounded judgment over a short checklist."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skilldrop-cli",
3
- "version": "1.11.1",
3
+ "version": "1.13.0",
4
4
  "description": "Portable AI-agent skills, measured against the agent without them. ADRs, PRDs, runbooks, decks and reviews, installable into Claude Code, Cursor, Kiro, and any IDE that takes custom instructions. One command per skill or per role-based pack.",
5
5
  "author": {
6
6
  "name": "Sanjay Ananthanarayan",
@@ -0,0 +1,5 @@
1
+ node_modules/
2
+ dist/
3
+ coverage/
4
+ .env
5
+ .env.*
@@ -0,0 +1,3 @@
1
+ .env
2
+ .claude/settings.local.json
3
+ __pycache__/
@@ -5,9 +5,9 @@
5
5
  > We're about to roll this Claude Code setup out to the whole data team for tidewater-ingest.
6
6
  > Anything we should change first?
7
7
 
8
- Files: [`inputs/tidewater-ingest/.claude/settings.json`](inputs/tidewater-ingest/.claude/settings.json),
9
- [`inputs/tidewater-ingest/.mcp.json`](inputs/tidewater-ingest/.mcp.json),
10
- [`inputs/tidewater-ingest/.gitignore`](inputs/tidewater-ingest/.gitignore).
8
+ Files: [`inputs/tidewater-ingest/dot.claude/settings.json`](inputs/tidewater-ingest/dot.claude/settings.json),
9
+ [`inputs/tidewater-ingest/.mcp.json`](inputs/tidewater-ingest/dot.mcp.json),
10
+ [`inputs/tidewater-ingest/.gitignore`](inputs/tidewater-ingest/dot.gitignore).
11
11
 
12
12
  ## What the scan listed (abridged, real output)
13
13
 
@@ -0,0 +1,3 @@
1
+ registry=https://registry.npmjs.org/
2
+ save-exact=true
3
+ engine-strict=true
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: locale-check
3
- description: Check a product's translations against the source strings before they ship — every key present, every placeholder ({name}, %s, %1$d, ICU plural and select) carried over intact, the plural forms each language needs, markup tags balanced, and strings over their character budget — with a script that reads JSON, ARB, gettext .po, Android strings.xml and iOS .strings, and lists each problem with its key and locale. Use when someone asks to "check the translations", "QA these locale files", "will the German fit", "why does the French build crash on this string", or hands over locale files before a release.
3
+ description: Check a product's translations against the source strings before they ship — every key present, every placeholder (named, %s, %1$d, ICU plural and select) carried over intact, the plural forms each language needs, markup tags balanced, and strings over their character budget — with a script that reads JSON, ARB, gettext .po, Android strings.xml and iOS .strings, and lists each problem with its key and locale. Use when someone asks to "check the translations", "QA these locale files", "will the German fit", "why does the French build crash on this string", or hands over locale files before a release.
4
4
  ---
5
5
 
6
6
  # locale-check
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "locale-check",
3
- "version": "0.1.0",
4
- "description": "Check a product's translations against the source strings before they ship — every key present, every placeholder ({name}, %s, %1$d, ICU plural and select) carried over intact, the plural forms each language needs, markup tags balanced, and strings over their character budget — with a script that reads JSON, ARB, gettext .po, Android strings.xml and iOS .strings, and lists each problem with its key and locale. Use when someone asks to \"check the translations\", \"QA these locale files\", \"will the German fit\", \"why does the French build crash on this string\", or hands over locale files before a release.",
3
+ "version": "0.1.1",
4
+ "description": "Check a product's translations against the source strings before they ship — every key present, every placeholder (named, %s, %1$d, ICU plural and select) carried over intact, the plural forms each language needs, markup tags balanced, and strings over their character budget — with a script that reads JSON, ARB, gettext .po, Android strings.xml and iOS .strings, and lists each problem with its key and locale. Use when someone asks to \"check the translations\", \"QA these locale files\", \"will the German fit\", \"why does the French build crash on this string\", or hands over locale files before a release.",
5
5
  "entrypoint": "SKILL.md",
6
6
  "deps": {
7
7
  "npm": [],
@@ -0,0 +1,5 @@
1
+ node_modules/
2
+ dist/
3
+ meta.json
4
+ # generated from the design team's emoji export, not committed
5
+ src/emoji/emoji-data.json
@@ -0,0 +1,121 @@
1
+ ---
2
+ name: manuscript-check
3
+ description: Check a paper, thesis chapter or report before it goes to a journal, a supervisor, examiners or a publisher — a script reads the manuscript and finds every citation with no reference (including near misses: the right author with another year, a misspelt name), references never cited, the same work listed twice, numbered references out of citation order, and Figure, Table and Section references to things that don't exist or are never mentioned, plus footnotes and the abstract's length — then reads the reference list for consistency of style. Use when someone asks to "check my references", "check my citations match the bibliography", "proofread my paper before submission", "check my figure and table numbering", "is my thesis chapter ready to send", or "check the cross-references in this report".
4
+ ---
5
+
6
+ # manuscript-check
7
+
8
+ Reviewers and examiners notice a citation with no reference, "see Figure 3" in a paper with two
9
+ figures, and the same source listed twice, and each one costs credibility. These faults come from
10
+ revising: a figure cut, a section renumbered, a reference updated to its published year in the
11
+ list but not in the text. A capable agent reads a manuscript fluently and misses them, because
12
+ it reads what the author meant. A script reads every citation against every reference both
13
+ ways, and every figure, table and section reference against what exists. The agent then reads
14
+ the reference list for what a script can't judge.
15
+
16
+ ## How to respond
17
+
18
+ **These rules come before the steps and outrank them:**
19
+
20
+ - **Lead with what a reviewer or examiner would catch, in plain words.** ✅ *"Six things to fix:
21
+ 'Kuh et al., 2009' is 2008 in your list; 'Yeager (2016)' is spelt Yeagar there; Rosenbaum and
22
+ Rubin (1983) is listed twice; the text refers to Section 6, Table 2 and Figure 3, which don't
23
+ exist."* Never mention a script, this skill's name, a path inside its folder or a temporary
24
+ path, and never call your work "the check" or "a tool".
25
+ - **Every citation and cross-reference finding comes from the manuscript,** with its line. Never
26
+ claim a reference is missing from a read alone.
27
+ - **Say which side is wrong when it's clear,** and when it isn't, give both fixes: a 2009
28
+ citation beside a 2008 entry is usually the citation, but a paper that went from preprint to
29
+ print can be the list. Never delete a reference unasked: an uncited entry may need a citation
30
+ added rather than removing.
31
+ - **Then read the manuscript for internal consistency, as a reviewer does:** every number in
32
+ the abstract and the text against the tables and results it comes from (a total, a mean, a
33
+ percentage, a sample size); every claim in the abstract present in the results; every
34
+ analysis in the results described in the methods; captions in one format. Work the
35
+ arithmetic where you can. One line each, with the line number and the correction.
36
+ - **Line numbers come from the check's output,** never counted by eye, and every fix in the reply
37
+ agrees with every other: no advice to cite a source in one item that another item says doesn't
38
+ support the claim.
39
+ - **When numbered references are out of citation order, give the whole renumbering** from the
40
+ check's old-to-new map, so the author can apply it in one pass.
41
+ - **Then read the reference list for consistency** in the style the manuscript uses (APA,
42
+ Harvard, Vancouver, IEEE, Chicago): author formats, "et al." thresholds, italics, missing
43
+ volumes, pages or DOIs, a preprint cited where the published version exists, in-text forms
44
+ that mix styles. One line each, with the corrected form for one example.
45
+ - **Their file is never overwritten.** A corrected copy goes beside it under a plain name
46
+ (`paper-corrected.docx`), only when asked, with every change listed. Working files go in a
47
+ private temporary folder (`mktemp -d`) and are deleted before replying.
48
+
49
+ 1. **Find the manuscript and its limits:** the target journal or the regulations (abstract
50
+ length, reference style), when the person names them. Ask at most once.
51
+
52
+ 2. **Run the check.** It reads Markdown, text and Word; for LaTeX or PDF, save as text first.
53
+
54
+ ```bash
55
+ # Claude Code
56
+ python3 "${CLAUDE_SKILL_DIR}/scripts/manuscript_check.py" ./paper.docx --abstract-limit 250
57
+ # Other IDEs (from the skill folder)
58
+ python3 scripts/manuscript_check.py ./chapter-3.md
59
+ ```
60
+
61
+ Exit 0 means no failures, 1 means a failure, 2 means the file can't be read. It finds the
62
+ reference list by its heading (References, Bibliography, Works Cited) and tells numbered from
63
+ author-year citations itself. It **fails** on a citation with no reference, the same work
64
+ listed twice, a reference to a figure, table or section that doesn't exist, a footnote used
65
+ but not defined, and an abstract over its limit. It **warns** on references never cited,
66
+ numbered references out of citation order, captions never referred to, numbering gaps, and
67
+ malformed DOIs.
68
+
69
+ 3. **Read the reference list** for style consistency, as in the rules above, and check each
70
+ near miss against the entry it points to.
71
+
72
+ 4. **Reply in this order:**
73
+ 1. **What to fix,** most serious first, each with its line and the correction.
74
+ 2. **Citations and references:** missing, near misses, never cited, duplicates.
75
+ 3. **Figures, tables and sections:** references that don't exist, captions never mentioned,
76
+ numbering, and the full renumbering when references are out of order.
77
+ 4. **Numbers and claims that don't agree** between the abstract, text, tables and methods.
78
+ 5. **Style consistency in the reference list,** one line each with one corrected example.
79
+ 6. **Corrected file,** when asked, with every change listed.
80
+
81
+ **Non-interactive runs** (subagent, CI, headless): with no reference list found, say so and
82
+ check the cross-references only. With no manuscript, emit `BLOCKED: need the manuscript (as
83
+ .docx, .md or .txt)`.
84
+
85
+ ## Useful references in this skill
86
+
87
+ - [`scripts/manuscript_check.py`](scripts/manuscript_check.py) — numbered and author-year citations both ways, near misses, duplicates, figure, table and section references, footnotes, DOIs, abstract length
88
+ - [`examples/retention-paper.md`](examples/retention-paper.md) — worked example: a paper with a misspelt citation, a wrong year, a duplicated reference and three references to things that were cut
89
+
90
+ ## Quality bar
91
+
92
+ - **Every citation is checked against the reference list, and every reference against the citations.**
93
+ - **A near miss names the entry it nearly matches,** so the fix is one edit.
94
+ - **Every Figure, Table and Section reference points at something that exists,** and every caption is mentioned.
95
+ - **The reply leads with what a reviewer would catch,** with lines, and no mention of scripts or files.
96
+ - **Nothing is deleted unasked,** and the likelier side of each mismatch is named.
97
+ - **Their file is never overwritten,** and every change in a corrected copy is listed.
98
+
99
+ ## When to use this skill
100
+
101
+ - ✅ A paper before journal submission, or a revision before resubmission
102
+ - ✅ A thesis chapter before it goes to a supervisor or examiners
103
+ - ✅ A report or white paper with numbered figures and a reference list
104
+ - ✅ After cutting or renumbering figures, tables or sections
105
+
106
+ ## When NOT to use this skill
107
+
108
+ - ❌ Whether a source supports the claim it's cited for: that is a reading of the sources (`source-synthesis` reads sources for a question)
109
+ - ❌ Writing a literature review: plan it with `research-plan` and draft it from the sources
110
+ - ❌ Plagiarism or similarity checking
111
+ - ❌ Copy-editing the prose itself
112
+
113
+ ## Anti-patterns to avoid
114
+
115
+ - ❌ **"The references look complete."** Check both ways: a list entry never cited is as visible to a reviewer as a missing one.
116
+ - ❌ **Deleting uncited references** without asking: some need a citation added instead.
117
+ - ❌ **Missing the near miss.** "Smith (2019)" against "Smith (2020)" in the list is one reference with the wrong year, not two problems.
118
+ - ❌ **Renumbering every figure** to fix one gap without listing what moved.
119
+ - ❌ **Reformatting the whole list into a different style** unasked.
120
+ - ❌ **"The script found…"** They want the list of fixes.
121
+ - ❌ **Checking the references and stopping.** A total in the text that disagrees with its table is the next thing a reviewer finds.
@@ -0,0 +1,30 @@
1
+ [
2
+ {
3
+ "query": "Check my citations match my bibliography",
4
+ "should_trigger": true
5
+ },
6
+ {
7
+ "query": "Proofread my paper's references and figure numbering before submission",
8
+ "should_trigger": true
9
+ },
10
+ {
11
+ "query": "Is my thesis chapter ready to send to my supervisor? Check the cross-references",
12
+ "should_trigger": true
13
+ },
14
+ {
15
+ "query": "Check every figure and table in this report is referred to",
16
+ "should_trigger": true
17
+ },
18
+ {
19
+ "query": "Synthesise these ten papers into a literature review",
20
+ "should_trigger": false
21
+ },
22
+ {
23
+ "query": "Plan a research study on remote work and wellbeing",
24
+ "should_trigger": false
25
+ },
26
+ {
27
+ "query": "Critique this design document's structure",
28
+ "should_trigger": false
29
+ }
30
+ ]
@@ -0,0 +1,73 @@
1
+ {
2
+ "skill_name": "manuscript-check",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "I'm submitting paper.md to the journal next week. Can you check my citations and cross-references? It's APA 7th and the abstract limit is 50 words.",
7
+ "assertions": [
8
+ "Flags 'Kuh et al., 2009' (line 34) against Kuh et al. 2008 in the list",
9
+ "Flags 'Yeager (2016)' against the list's spelling 'Yeagar'",
10
+ "Flags Rosenbaum and Rubin (1983) as listed twice",
11
+ "Flags references to Section 6, Table 2 and Figure 3, which don't exist, and Figure 2 never being referred to",
12
+ "Flags Pascarella and Terenzini (2005) as never cited without deleting it unasked",
13
+ "Does not mention a script or the skill's name, and does not invent references or errors not in the file"
14
+ ]
15
+ },
16
+ {
17
+ "id": 2,
18
+ "held_out": "2026-11-09",
19
+ "prompt": "Can you check my references and figure numbering before I send this to the journal? It's paper.md, APA style.",
20
+ "assertions": [
21
+ "Flags (Okonkwo-Varga, 2019) in the Introduction as not matching the list, which has Okonkwo-Varga, J. (2018), and treats it as a near miss whose likely fix is correcting the in-text year to 2018 (or confirming which year is right), not as a missing reference",
22
+ "Flags 'Lindqvst & Moreau, 2020' (cited twice, in the Introduction and the Discussion) as a misspelling of Lindqvist, E., & Moreau, C. (2020) in the reference list, and suggests correcting the in-text spelling",
23
+ "Flags (Tamberlane, 2021) in the Introduction as a citation with no matching entry in the reference list, and says a reference must be added or the citation removed",
24
+ "Flags Feroz, A. (2017) as listed in the references but never cited in the text",
25
+ "Flags the reference to Figure 3 in the Results as pointing to a figure that does not exist (only Figures 1 and 2 have captions)",
26
+ "Notes the reference-list style inconsistency in the Delacroix-Hume and Petrov (2021) entry: full first names ('Brigitte', 'Stefan') instead of initials, unlike every other entry",
27
+ "Does not invent faults or references that are not in paper.md - for example it does not report Table 1, Figure 1, Figure 2, Vasquez-Tolland (2020) or Haldane-Ruiz et al. (2016) as problems, and does not make up a full reference for Tamberlane"
28
+ ]
29
+ },
30
+ {
31
+ "id": 3,
32
+ "held_out": "2026-11-09",
33
+ "prompt": "This is my pilot report for the Fernhollow Farm Trust board (report.md). I'm also going to cut it down and send it to a small journal that uses Vancouver referencing, so I want the version I have now to be right first. Could you check that every citation matches the reference list and the references are numbered properly, that all the figure, table and section cross-references work, and anything else that would embarrass me in front of the board or an editor? Please tell me exactly where each problem is and what you'd change.",
34
+ "assertions": [
35
+ "Finds that the references are not numbered in order of first citation: reference [4] is first cited (Introduction, second paragraph) before reference [3], so in Vancouver style the two should be swapped and renumbered",
36
+ "Finds that reference 11 is a duplicate of reference 5 (Castellanos and Whitcombe, 2022, same title and journal), and says to delete 11 and cite [5] in section 4.1 instead, renumbering what follows",
37
+ "Finds that reference 9 (Okafor-Brandt, 2023) is never cited in the text, so it should be cited or removed",
38
+ "Finds that section 3.1 refers to 'Section 4.3', which does not exist (section 4 has only 4.1 and 4.2)",
39
+ "Finds that Figure 2 has a caption but is never referred to in the text, and suggests where to cite it (e.g. in section 3 or 4.2 on watering)",
40
+ "Notes that reference 7 (Delahaye and Strand) is written in APA style (comma-separated initials with full stops, '&', year in brackets after the authors, full journal name) unlike the Vancouver format of every other entry, and shows the Vancouver form",
41
+ "Does not invent problems that are not in report.md - for example it does not report Figure 1, Table 1 or references 1, 2, 6, 8, 10 or 12 as missing or uncited, and does not claim any citation lacks a reference entry"
42
+ ]
43
+ },
44
+ {
45
+ "id": 4,
46
+ "held_out": "2026-11-09",
47
+ "prompt": "Check paper.md before I send it to the journal - references and cross-references, please.",
48
+ "assertions": [
49
+ "Flags 'Halvorsen, 2017' (Introduction) as a near miss for the reference Halvorsen (2019), and says the likelier fix is to correct the in-text year to 2019",
50
+ "Flags 'Pemberton (2017)' (Introduction) as a near miss for the reference 'Pembleton, A. (2017)' and asks which spelling is right rather than treating it as two different works",
51
+ "Flags 'Varga, 2021' (Discussion) as cited with no entry in the reference list and asks for the details, without inventing a reference for it",
52
+ "Flags 'Lindqvist, E. (2016)' as listed in References but never cited, to be cited or removed",
53
+ "Flags the Results' reference to 'Figure 3': only Figures 1 and 2 exist (captions after Table 1), so either a figure is missing or the reference should point to Figure 2",
54
+ "Flags that the abstract's 'raised mean soil moisture by 23%' disagrees with Table 1: wood chip 15.1% vs bare soil 11.6% is a relative increase of (15.1 - 11.6) / 11.6 = 30.2% (3.5 percentage points)",
55
+ "Does not invent references, author details, figures, data or results not in the file"
56
+ ]
57
+ },
58
+ {
59
+ "id": 5,
60
+ "held_out": "2026-11-09",
61
+ "prompt": "This is chapter 3 of my PhD thesis (chapter3.md). My supervisor, Dr. Imelda Faraday-Nwosu, wants the full draft by Friday and she is strict about references. Department style is numbered references in order of first citation in the text. Could you check that every citation matches the reference list, that the references are numbered correctly, and that the figure, table and section cross-references all work? She also reads closely for whether the abstract and results hang together with the methods, so flag anything there too. Please tell me exactly what to change, including any renumbering.",
62
+ "assertions": [
63
+ "Flags that references are not numbered in order of first citation: the text cites [1], [2], [5], [3], [4] in that order, so the fix renumbers old 5 to 3, old 3 to 4 and old 4 to 5 (1, 2, 6, 7 and 8 keep their numbers), updating both the list and the in-text citations",
64
+ "Flags references 7 and 9 (Hargreaves & Nakamura 2024, Battery variability in light electric vehicle fleets) as the same work listed twice in different journal-name styles; the fix merges them so the [9] citation in Section 3.2.3 becomes [7], leaving an 8-entry list",
65
+ "Flags citation [11] in the Results as having no entry in the reference list (the list ends at 9) and asks for the source rather than inventing one; once supplied it becomes the next number in order of first citation (9 after the merge)",
66
+ "Flags the cross-reference to 'Section 3.2.4' in the Introduction: Methods has only 3.2.1-3.2.3, and the likelier target is 3.2.2 (Charging regimes); and flags that Figure 2 (monthly depot temperature) has a caption but is never referred to in the text",
67
+ "Flags that the abstract's fleet-wide mean fade of 7.9% disagrees with Table 1's 'All bikes' figure of 7.0% (consistent with (27 x 6.4 + 15 x 8.1) / 42 = 7.0%), so the abstract is likely a transposition and should read 7.0%",
68
+ "Flags that the Results report a Kaplan-Meier analysis of time to 80% capacity that the Methods (3.2.3) never describe, so it must be added to the methods or dropped",
69
+ "Does not invent references, bibliographic details, data, figures or analyses not in the file"
70
+ ]
71
+ }
72
+ ]
73
+ }
@@ -0,0 +1,56 @@
1
+ # Peer mentoring and first-year retention: a mixed-methods study
2
+
3
+ ## Abstract
4
+
5
+ We studied whether pairing first-year students with trained second-year mentors improves retention into the second year. Across three cohorts (n = 1,240), mentored students were retained at 91% against 84% for a matched comparison group. Interviews suggest the effect works through belonging rather than academic help.
6
+
7
+ ## 1. Introduction
8
+
9
+ Retention in the first year predicts degree completion (Tinto, 1993; Kuh et al., 2008). Peer mentoring is widely used but rarely evaluated with a comparison group (Crisp & Cruz, 2009). Walton and Cohen (2011) showed that a brief belonging intervention raised grades, and Yeager (2016) extended the finding to larger samples.
10
+
11
+ Section 4 sets out the analysis, and Section 6 discusses limits.
12
+
13
+ ## 2. Method
14
+
15
+ Students were matched on entry tariff and background (Rosenbaum & Rubin, 1983). Figure 1 shows the matching, and Table 1 summarises the cohorts.
16
+
17
+ ![matching diagram](fig1.png)
18
+ **Figure 1.** Propensity-score matching of mentored and comparison students.
19
+
20
+ **Table 1.** Cohort sizes and retention by group.
21
+
22
+ | Cohort | Mentored | Comparison |
23
+ |---|---|---|
24
+ | 2022 | 410 | 398 |
25
+
26
+ ## 3. Results
27
+
28
+ Mentored students were more likely to be retained (Table 2). Figure 3 shows the effect by cohort. The effect was strongest for first-generation students (Stephens et al., 2012).
29
+
30
+ **Figure 2.** Retention by cohort and group.
31
+
32
+ ## 4. Discussion
33
+
34
+ The pattern supports a belonging account (Walton & Cohen, 2011; Strayhorn, 2019) over an academic-support account (Kuh et al., 2009).
35
+
36
+ ## References
37
+
38
+ Crisp, G., & Cruz, I. (2009). Mentoring college students: A critical review of the literature between 1990 and 2007. *Research in Higher Education*, 50(6), 525–545. https://doi.org/10.1007/s11162-009-9130-2
39
+
40
+ Kuh, G. D., Cruce, T. M., Shoup, R., Kinzie, J., & Gonyea, R. M. (2008). Unmasking the effects of student engagement on first-year college grades and persistence. *The Journal of Higher Education*, 79(5), 540–563.
41
+
42
+ Rosenbaum, P. R., & Rubin, D. B. (1983). The central role of the propensity score in observational studies for causal effects. *Biometrika*, 70(1), 41–55. https://doi.org/10.1093/biomet/70.1.41
43
+
44
+ Stephens, N. M., Fryberg, S. A., Markus, H. R., Johnson, C. S., & Covarrubias, R. (2012). Unseen disadvantage: How American universities' focus on independence undermines the academic performance of first-generation college students. *Journal of Personality and Social Psychology*, 102(6), 1178–1197.
45
+
46
+ Strayhorn, T. L. (2019). *College students' sense of belonging* (2nd ed.). Routledge.
47
+
48
+ Tinto, V. (1993). *Leaving college: Rethinking the causes and cures of student attrition* (2nd ed.). University of Chicago Press.
49
+
50
+ Walton, G. M., & Cohen, G. L. (2011). A brief social-belonging intervention improves academic and health outcomes of minority students. *Science*, 331(6023), 1447–1451.
51
+
52
+ Yeagar, D. S. (2016). Teaching a lay theory before college narrows achievement gaps at scale. *PNAS*, 113(24), E3341–E3348.
53
+
54
+ Pascarella, E. T., & Terenzini, P. T. (2005). *How college affects students* (Vol. 2). Jossey-Bass.
55
+
56
+ Rosenbaum, P. R., & Rubin, D. B. (1983). The central role of the propensity score in observational studies for causal effects. *Biometrika*, 70(1), 41–55. doi:10.1093/biomet/70.1.41
@@ -0,0 +1,118 @@
1
+ # Rooftop Forb Plantings Increase Solitary Bee Nesting in a Mid-Sized City
2
+
3
+ Running head: ROOFTOP FORBS AND SOLITARY BEES
4
+
5
+ ## Abstract
6
+
7
+ Green roofs are often promoted as pollinator habitat, but most are planted with
8
+ sedum mats that offer little forage. We compared solitary bee nesting on 18 roofs in
9
+ Carrowmere: six sedum-only roofs, six mixed forb roofs and six bare control roofs.
10
+ Trap nests on forb roofs held three times as many brood cells as those on sedum roofs,
11
+ and nest occupancy rose with forb cover. We argue that planting choice, not roof
12
+ area, is the main lever for city planners.
13
+
14
+ ## Introduction
15
+
16
+ Cities can support a surprising diversity of wild bees when floral resources and
17
+ nesting sites are both available (Quillfeather & Arslan, 2015). Cavity-nesting
18
+ species in particular readily colonise artificial trap nests placed in urban
19
+ settings (Achterberg & Nwosu, 2019), which makes them a practical study group for
20
+ comparing habitat treatments.
21
+
22
+ Green roofs have been proposed as stepping stones that connect fragmented urban
23
+ habitat (Haldane-Ruiz et al., 2016). Most installed roofs, however, are extensive
24
+ systems planted with drought-tolerant sedum, chosen for low maintenance rather than
25
+ ecological value (Okonkwo-Varga, 2019). Sedum flowers briefly and attracts mainly
26
+ generalist visitors (Lindqvst & Moreau, 2020).
27
+
28
+ Forb-rich roofs can extend the flowering season, but they need deeper substrate and
29
+ more care, and city planners have little evidence that the extra cost pays off for
30
+ pollinators (Tamberlane, 2021). Earlier roof surveys counted foraging bees rather than
31
+ nests, so it remains unclear whether roofs support reproduction or only feeding
32
+ (Pemberton-Shah, 2022).
33
+
34
+ Here we ask whether forb plantings increase solitary bee nesting on roofs compared
35
+ with sedum plantings and bare control roofs.
36
+
37
+ ## Method
38
+
39
+ ### Study sites
40
+
41
+ We selected 18 flat roofs in central Carrowmere, all between four and six storeys
42
+ high and at least 300 m apart (Figure 1). Six were sedum-only extensive roofs, six
43
+ had been converted to mixed native forb plantings at least three years before the
44
+ study, and six were bare gravel roofs used as controls.
45
+
46
+ ### Trap nests
47
+
48
+ On each roof we placed four trap nests, each holding 40 reed and cardboard tubes of
49
+ three diameters, following the design of Vasquez-Tolland (2020). Nests were set out
50
+ in late March and collected in October.
51
+
52
+ ### Floral surveys
53
+
54
+ Each month from April to September we recorded percentage forb cover in ten 1 m2
55
+ quadrats per roof, using the protocol of Delacroix-Hume and Petrov (2021).
56
+
57
+ ### Analysis
58
+
59
+ We modelled brood cells per nest with a negative binomial mixed model, with roof type
60
+ and forb cover as fixed effects and roof as a random effect.
61
+
62
+ ## Results
63
+
64
+ Across all roofs we recorded 2,184 brood cells from nine species. Mean brood cells per
65
+ nest were 31.2 on forb roofs, 10.4 on sedum roofs and 2.1 on control roofs (Table 1).
66
+
67
+ Brood cell counts rose with forb cover on both planted roof types (Figure 2). The
68
+ relationship held after removing the two roofs closest to the city park.
69
+
70
+ Mason bees made up most of the cells on forb roofs, while leafcutter bees were
71
+ recorded only on forb roofs with more than 30% cover (Figure 3).
72
+
73
+ Table 1
74
+ Mean brood cells per trap nest by roof type
75
+
76
+ | Roof type | Roofs | Mean brood cells per nest | SD |
77
+ |---|---|---|---|
78
+ | Mixed forb | 6 | 31.2 | 8.7 |
79
+ | Sedum | 6 | 10.4 | 4.1 |
80
+ | Control | 6 | 2.1 | 1.6 |
81
+
82
+ Figure 1. Locations of the 18 study roofs in central Carrowmere.
83
+
84
+ Figure 2. Brood cells per nest against mean forb cover, by roof type.
85
+
86
+ ## Discussion
87
+
88
+ Our results suggest that roofs can support solitary bee reproduction, not just
89
+ foraging, provided they are planted with forbs. This agrees with ground-level work
90
+ showing that nesting responds to floral cover within a few hundred metres
91
+ (Quillfeather & Arslan, 2015; Achterberg & Nwosu, 2019).
92
+
93
+ The low counts on sedum roofs match the view that sedum offers a short, narrow
94
+ flowering window (Lindqvst & Moreau, 2020). Planners weighing the higher cost of forb
95
+ roofs should set it against this difference in nesting (Pemberton-Shah, 2022).
96
+
97
+ Our study covered one season in one city. Longer studies should track whether
98
+ nesting on forb roofs persists as plantings age (Haldane-Ruiz et al., 2016).
99
+
100
+ ## References
101
+
102
+ Achterberg, L., & Nwosu, P. (2019). Trap-nest colonisation by cavity-nesting bees along an urban gradient. *Journal of Rooftop Ecology*, 7(2), 44-58.
103
+
104
+ Delacroix-Hume, Brigitte, & Petrov, Stefan (2021). A quadrat protocol for flowering cover on extensive roofs. *Pollinator Habitat Review*, 12(1), 3-17.
105
+
106
+ Feroz, A. (2017). Substrate depth and forb survival on extensive green roofs. *Built Environment Biology*, 3(1), 12-29.
107
+
108
+ Haldane-Ruiz, M., Ostrowski, K., & Bell, T. (2016). Green roofs as stepping stones for urban insects. *Journal of Rooftop Ecology*, 4(3), 101-119.
109
+
110
+ Lindqvist, E., & Moreau, C. (2020). Flowering phenology and visitor networks on sedum roofs. *Pollinator Habitat Review*, 11(4), 210-226.
111
+
112
+ Okonkwo-Varga, J. (2018). Why cities plant sedum: Maintenance, cost and the green roof market. *Built Environment Biology*, 4(2), 55-71.
113
+
114
+ Pemberton-Shah, R. (2022). Foraging bees on city roofs: A five-city survey. *Carrowmere Naturalist*, 88(1), 9-24.
115
+
116
+ Quillfeather, N., & Arslan, D. (2015). Floral resources and nest sites limit wild bees in cities. *Journal of Rooftop Ecology*, 3(1), 1-15.
117
+
118
+ Vasquez-Tolland, H. (2020). A low-cost trap nest for monitoring solitary bees. *Carrowmere Naturalist*, 86(2), 77-85.