flonat-research 0.1.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 (285) hide show
  1. package/.claude/agents/domain-reviewer.md +336 -0
  2. package/.claude/agents/fixer.md +226 -0
  3. package/.claude/agents/paper-critic.md +370 -0
  4. package/.claude/agents/peer-reviewer.md +289 -0
  5. package/.claude/agents/proposal-reviewer.md +215 -0
  6. package/.claude/agents/referee2-reviewer.md +367 -0
  7. package/.claude/agents/references/journal-referee-profiles.md +354 -0
  8. package/.claude/agents/references/paper-critic/council-personas.md +77 -0
  9. package/.claude/agents/references/paper-critic/council-prompts.md +198 -0
  10. package/.claude/agents/references/peer-reviewer/report-template.md +199 -0
  11. package/.claude/agents/references/peer-reviewer/sa-prompts.md +260 -0
  12. package/.claude/agents/references/peer-reviewer/security-scan.md +188 -0
  13. package/.claude/agents/references/proposal-reviewer/report-template.md +144 -0
  14. package/.claude/agents/references/proposal-reviewer/sa-prompts.md +149 -0
  15. package/.claude/agents/references/referee-config.md +114 -0
  16. package/.claude/agents/references/referee2-reviewer/audit-checklists.md +287 -0
  17. package/.claude/agents/references/referee2-reviewer/report-template.md +334 -0
  18. package/.claude/rules/design-before-results.md +52 -0
  19. package/.claude/rules/ignore-agents-md.md +17 -0
  20. package/.claude/rules/ignore-gemini-md.md +17 -0
  21. package/.claude/rules/lean-claude-md.md +45 -0
  22. package/.claude/rules/learn-tags.md +99 -0
  23. package/.claude/rules/overleaf-separation.md +67 -0
  24. package/.claude/rules/plan-first.md +175 -0
  25. package/.claude/rules/read-docs-first.md +50 -0
  26. package/.claude/rules/scope-discipline.md +28 -0
  27. package/.claude/settings.json +125 -0
  28. package/.context/current-focus.md +33 -0
  29. package/.context/preferences/priorities.md +36 -0
  30. package/.context/preferences/task-naming.md +28 -0
  31. package/.context/profile.md +29 -0
  32. package/.context/projects/_index.md +41 -0
  33. package/.context/projects/papers/nudge-exp.md +22 -0
  34. package/.context/projects/papers/uncertainty.md +31 -0
  35. package/.context/resources/claude-scientific-writer-review.md +48 -0
  36. package/.context/resources/cunningham-multi-analyst-agents.md +104 -0
  37. package/.context/resources/cunningham-multilang-code-audit.md +62 -0
  38. package/.context/resources/google-ai-co-scientist-review.md +72 -0
  39. package/.context/resources/karpathy-llm-council-review.md +58 -0
  40. package/.context/resources/multi-coder-reliability-protocol.md +175 -0
  41. package/.context/resources/pedro-santanna-takeaways.md +96 -0
  42. package/.context/resources/venue-rankings/abs_ajg_2024.csv +1823 -0
  43. package/.context/resources/venue-rankings/abs_ajg_2024_econ.csv +356 -0
  44. package/.context/resources/venue-rankings/cabs_4_4star_theory.csv +40 -0
  45. package/.context/resources/venue-rankings/core_2026.csv +801 -0
  46. package/.context/resources/venue-rankings.md +147 -0
  47. package/.context/workflows/README.md +69 -0
  48. package/.context/workflows/daily-review.md +91 -0
  49. package/.context/workflows/meeting-actions.md +108 -0
  50. package/.context/workflows/replication-protocol.md +155 -0
  51. package/.context/workflows/weekly-review.md +113 -0
  52. package/.mcp-server-biblio/formatters.py +158 -0
  53. package/.mcp-server-biblio/pyproject.toml +11 -0
  54. package/.mcp-server-biblio/server.py +678 -0
  55. package/.mcp-server-biblio/sources/__init__.py +14 -0
  56. package/.mcp-server-biblio/sources/base.py +73 -0
  57. package/.mcp-server-biblio/sources/formatters.py +83 -0
  58. package/.mcp-server-biblio/sources/models.py +22 -0
  59. package/.mcp-server-biblio/sources/multi_source.py +243 -0
  60. package/.mcp-server-biblio/sources/openalex_source.py +183 -0
  61. package/.mcp-server-biblio/sources/scopus_source.py +309 -0
  62. package/.mcp-server-biblio/sources/wos_source.py +508 -0
  63. package/.mcp-server-biblio/uv.lock +896 -0
  64. package/.scripts/README.md +161 -0
  65. package/.scripts/ai_pattern_density.py +446 -0
  66. package/.scripts/conf +445 -0
  67. package/.scripts/config.py +122 -0
  68. package/.scripts/count_inventory.py +275 -0
  69. package/.scripts/daily_digest.py +288 -0
  70. package/.scripts/done +177 -0
  71. package/.scripts/extract_meeting_actions.py +223 -0
  72. package/.scripts/focus +176 -0
  73. package/.scripts/generate-codex-agents-md.py +217 -0
  74. package/.scripts/inbox +194 -0
  75. package/.scripts/notion_helpers.py +325 -0
  76. package/.scripts/openalex/query_helpers.py +306 -0
  77. package/.scripts/papers +227 -0
  78. package/.scripts/query +223 -0
  79. package/.scripts/session-history.py +201 -0
  80. package/.scripts/skill-health.py +516 -0
  81. package/.scripts/skill-log-miner.py +273 -0
  82. package/.scripts/sync-to-codex.sh +252 -0
  83. package/.scripts/task +213 -0
  84. package/.scripts/tasks +190 -0
  85. package/.scripts/week +206 -0
  86. package/CLAUDE.md +197 -0
  87. package/LICENSE +21 -0
  88. package/MEMORY.md +38 -0
  89. package/README.md +269 -0
  90. package/docs/agents.md +44 -0
  91. package/docs/bibliography-setup.md +55 -0
  92. package/docs/council-mode.md +36 -0
  93. package/docs/getting-started.md +245 -0
  94. package/docs/hooks.md +38 -0
  95. package/docs/mcp-servers.md +82 -0
  96. package/docs/notion-setup.md +109 -0
  97. package/docs/rules.md +33 -0
  98. package/docs/scripts.md +303 -0
  99. package/docs/setup-overview/setup-overview.pdf +0 -0
  100. package/docs/skills.md +70 -0
  101. package/docs/system.md +159 -0
  102. package/hooks/block-destructive-git.sh +66 -0
  103. package/hooks/context-monitor.py +114 -0
  104. package/hooks/postcompact-restore.py +157 -0
  105. package/hooks/precompact-autosave.py +181 -0
  106. package/hooks/promise-checker.sh +124 -0
  107. package/hooks/protect-source-files.sh +81 -0
  108. package/hooks/resume-context-loader.sh +53 -0
  109. package/hooks/startup-context-loader.sh +102 -0
  110. package/package.json +51 -0
  111. package/packages/cli-council/.github/workflows/claude-code-review.yml +44 -0
  112. package/packages/cli-council/.github/workflows/claude.yml +50 -0
  113. package/packages/cli-council/README.md +100 -0
  114. package/packages/cli-council/pyproject.toml +43 -0
  115. package/packages/cli-council/src/cli_council/__init__.py +19 -0
  116. package/packages/cli-council/src/cli_council/__main__.py +185 -0
  117. package/packages/cli-council/src/cli_council/backends/__init__.py +8 -0
  118. package/packages/cli-council/src/cli_council/backends/base.py +81 -0
  119. package/packages/cli-council/src/cli_council/backends/claude.py +25 -0
  120. package/packages/cli-council/src/cli_council/backends/codex.py +27 -0
  121. package/packages/cli-council/src/cli_council/backends/gemini.py +26 -0
  122. package/packages/cli-council/src/cli_council/checkpoint.py +212 -0
  123. package/packages/cli-council/src/cli_council/config.py +51 -0
  124. package/packages/cli-council/src/cli_council/council.py +391 -0
  125. package/packages/cli-council/src/cli_council/models.py +46 -0
  126. package/packages/llm-council/.github/workflows/claude-code-review.yml +44 -0
  127. package/packages/llm-council/.github/workflows/claude.yml +50 -0
  128. package/packages/llm-council/README.md +453 -0
  129. package/packages/llm-council/pyproject.toml +42 -0
  130. package/packages/llm-council/src/llm_council/__init__.py +23 -0
  131. package/packages/llm-council/src/llm_council/__main__.py +259 -0
  132. package/packages/llm-council/src/llm_council/checkpoint.py +193 -0
  133. package/packages/llm-council/src/llm_council/client.py +253 -0
  134. package/packages/llm-council/src/llm_council/config.py +232 -0
  135. package/packages/llm-council/src/llm_council/council.py +482 -0
  136. package/packages/llm-council/src/llm_council/models.py +46 -0
  137. package/packages/mcp-bibliography/MEMORY.md +31 -0
  138. package/packages/mcp-bibliography/_app.py +226 -0
  139. package/packages/mcp-bibliography/formatters.py +158 -0
  140. package/packages/mcp-bibliography/log/2026-03-13-2100.md +35 -0
  141. package/packages/mcp-bibliography/pyproject.toml +15 -0
  142. package/packages/mcp-bibliography/run.sh +20 -0
  143. package/packages/mcp-bibliography/scholarly_formatters.py +83 -0
  144. package/packages/mcp-bibliography/server.py +1857 -0
  145. package/packages/mcp-bibliography/tools/__init__.py +28 -0
  146. package/packages/mcp-bibliography/tools/_registry.py +19 -0
  147. package/packages/mcp-bibliography/tools/altmetric.py +107 -0
  148. package/packages/mcp-bibliography/tools/core.py +92 -0
  149. package/packages/mcp-bibliography/tools/dblp.py +52 -0
  150. package/packages/mcp-bibliography/tools/openalex.py +296 -0
  151. package/packages/mcp-bibliography/tools/opencitations.py +102 -0
  152. package/packages/mcp-bibliography/tools/openreview.py +179 -0
  153. package/packages/mcp-bibliography/tools/orcid.py +131 -0
  154. package/packages/mcp-bibliography/tools/scholarly.py +575 -0
  155. package/packages/mcp-bibliography/tools/unpaywall.py +63 -0
  156. package/packages/mcp-bibliography/tools/zenodo.py +123 -0
  157. package/packages/mcp-bibliography/uv.lock +711 -0
  158. package/scripts/setup.sh +143 -0
  159. package/skills/beamer-deck/SKILL.md +199 -0
  160. package/skills/beamer-deck/references/quality-rubric.md +54 -0
  161. package/skills/beamer-deck/references/review-prompts.md +106 -0
  162. package/skills/bib-validate/SKILL.md +261 -0
  163. package/skills/bib-validate/references/council-mode.md +34 -0
  164. package/skills/bib-validate/references/deep-verify.md +79 -0
  165. package/skills/bib-validate/references/fix-mode.md +36 -0
  166. package/skills/bib-validate/references/openalex-verification.md +45 -0
  167. package/skills/bib-validate/references/preprint-check.md +31 -0
  168. package/skills/bib-validate/references/ref-manager-crossref.md +41 -0
  169. package/skills/bib-validate/references/report-template.md +82 -0
  170. package/skills/code-archaeology/SKILL.md +141 -0
  171. package/skills/code-review/SKILL.md +265 -0
  172. package/skills/code-review/references/quality-rubric.md +67 -0
  173. package/skills/consolidate-memory/SKILL.md +208 -0
  174. package/skills/context-status/SKILL.md +126 -0
  175. package/skills/creation-guard/SKILL.md +230 -0
  176. package/skills/devils-advocate/SKILL.md +130 -0
  177. package/skills/devils-advocate/references/competing-hypotheses.md +83 -0
  178. package/skills/init-project/SKILL.md +115 -0
  179. package/skills/init-project-course/references/memory-and-settings.md +92 -0
  180. package/skills/init-project-course/references/organise-templates.md +94 -0
  181. package/skills/init-project-course/skill.md +147 -0
  182. package/skills/init-project-light/skill.md +139 -0
  183. package/skills/init-project-research/SKILL.md +368 -0
  184. package/skills/init-project-research/references/atlas-pipeline-sync.md +70 -0
  185. package/skills/init-project-research/references/atlas-schema.md +81 -0
  186. package/skills/init-project-research/references/confirmation-report.md +39 -0
  187. package/skills/init-project-research/references/domain-profile-template.md +104 -0
  188. package/skills/init-project-research/references/interview-round3.md +34 -0
  189. package/skills/init-project-research/references/literature-discovery.md +43 -0
  190. package/skills/init-project-research/references/scaffold-details.md +197 -0
  191. package/skills/init-project-research/templates/field-calibration.md +60 -0
  192. package/skills/init-project-research/templates/pipeline-manifest.md +63 -0
  193. package/skills/init-project-research/templates/run-all.sh +116 -0
  194. package/skills/init-project-research/templates/seed-files.md +337 -0
  195. package/skills/insights-deck/SKILL.md +151 -0
  196. package/skills/interview-me/SKILL.md +157 -0
  197. package/skills/latex/SKILL.md +141 -0
  198. package/skills/latex/references/latex-configs.md +183 -0
  199. package/skills/latex-autofix/SKILL.md +230 -0
  200. package/skills/latex-autofix/references/known-errors.md +183 -0
  201. package/skills/latex-autofix/references/quality-rubric.md +50 -0
  202. package/skills/latex-health-check/SKILL.md +161 -0
  203. package/skills/learn/SKILL.md +220 -0
  204. package/skills/learn/scripts/validate_skill.py +265 -0
  205. package/skills/lessons-learned/SKILL.md +201 -0
  206. package/skills/literature/SKILL.md +335 -0
  207. package/skills/literature/references/agent-templates.md +393 -0
  208. package/skills/literature/references/bibliometric-apis.md +44 -0
  209. package/skills/literature/references/cli-council-search.md +79 -0
  210. package/skills/literature/references/openalex-api-guide.md +371 -0
  211. package/skills/literature/references/openalex-common-queries.md +381 -0
  212. package/skills/literature/references/openalex-workflows.md +248 -0
  213. package/skills/literature/references/reference-manager-sync.md +36 -0
  214. package/skills/literature/references/scopus-api-guide.md +208 -0
  215. package/skills/literature/references/wos-api-guide.md +308 -0
  216. package/skills/multi-perspective/SKILL.md +311 -0
  217. package/skills/multi-perspective/references/computational-many-analysts.md +77 -0
  218. package/skills/pipeline-manifest/SKILL.md +226 -0
  219. package/skills/pre-submission-report/SKILL.md +153 -0
  220. package/skills/process-reviews/SKILL.md +244 -0
  221. package/skills/process-reviews/references/rr-routing.md +101 -0
  222. package/skills/project-deck/SKILL.md +87 -0
  223. package/skills/project-safety/SKILL.md +135 -0
  224. package/skills/proofread/SKILL.md +254 -0
  225. package/skills/proofread/references/quality-rubric.md +104 -0
  226. package/skills/python-env/SKILL.md +57 -0
  227. package/skills/quarto-deck/SKILL.md +226 -0
  228. package/skills/quarto-deck/references/markdown-format.md +143 -0
  229. package/skills/quarto-deck/references/quality-rubric.md +54 -0
  230. package/skills/save-context/SKILL.md +174 -0
  231. package/skills/session-log/SKILL.md +98 -0
  232. package/skills/shared/concept-validation-gate.md +161 -0
  233. package/skills/shared/council-protocol.md +265 -0
  234. package/skills/shared/distribution-diagnostics.md +164 -0
  235. package/skills/shared/engagement-stratified-sampling.md +218 -0
  236. package/skills/shared/escalation-protocol.md +74 -0
  237. package/skills/shared/external-audit-protocol.md +205 -0
  238. package/skills/shared/intercoder-reliability.md +256 -0
  239. package/skills/shared/mcp-degradation.md +81 -0
  240. package/skills/shared/method-probing-questions.md +163 -0
  241. package/skills/shared/multi-language-conventions.md +143 -0
  242. package/skills/shared/paid-api-safety.md +174 -0
  243. package/skills/shared/palettes.md +90 -0
  244. package/skills/shared/progressive-disclosure.md +92 -0
  245. package/skills/shared/project-documentation-content.md +443 -0
  246. package/skills/shared/project-documentation-format.md +281 -0
  247. package/skills/shared/project-documentation.md +100 -0
  248. package/skills/shared/publication-output.md +138 -0
  249. package/skills/shared/quality-scoring.md +70 -0
  250. package/skills/shared/reference-resolution.md +77 -0
  251. package/skills/shared/research-quality-rubric.md +165 -0
  252. package/skills/shared/rhetoric-principles.md +54 -0
  253. package/skills/shared/skill-design-patterns.md +272 -0
  254. package/skills/shared/skill-index.md +240 -0
  255. package/skills/shared/system-documentation.md +334 -0
  256. package/skills/shared/tikz-rules.md +402 -0
  257. package/skills/shared/validation-tiers.md +121 -0
  258. package/skills/shared/venue-guides/README.md +46 -0
  259. package/skills/shared/venue-guides/cell_press_style.md +483 -0
  260. package/skills/shared/venue-guides/conferences_formatting.md +564 -0
  261. package/skills/shared/venue-guides/cs_conference_style.md +463 -0
  262. package/skills/shared/venue-guides/examples/cell_summary_example.md +247 -0
  263. package/skills/shared/venue-guides/examples/medical_structured_abstract.md +313 -0
  264. package/skills/shared/venue-guides/examples/nature_abstract_examples.md +213 -0
  265. package/skills/shared/venue-guides/examples/neurips_introduction_example.md +245 -0
  266. package/skills/shared/venue-guides/journals_formatting.md +486 -0
  267. package/skills/shared/venue-guides/medical_journal_styles.md +535 -0
  268. package/skills/shared/venue-guides/ml_conference_style.md +556 -0
  269. package/skills/shared/venue-guides/nature_science_style.md +405 -0
  270. package/skills/shared/venue-guides/reviewer_expectations.md +417 -0
  271. package/skills/shared/venue-guides/venue_writing_styles.md +321 -0
  272. package/skills/split-pdf/SKILL.md +172 -0
  273. package/skills/split-pdf/methodology.md +48 -0
  274. package/skills/sync-notion/SKILL.md +93 -0
  275. package/skills/system-audit/SKILL.md +157 -0
  276. package/skills/system-audit/references/sub-agent-prompts.md +294 -0
  277. package/skills/task-management/SKILL.md +131 -0
  278. package/skills/update-focus/SKILL.md +204 -0
  279. package/skills/update-project-doc/SKILL.md +194 -0
  280. package/skills/validate-bib/SKILL.md +242 -0
  281. package/skills/validate-bib/references/council-mode.md +34 -0
  282. package/skills/validate-bib/references/deep-verify.md +71 -0
  283. package/skills/validate-bib/references/openalex-verification.md +45 -0
  284. package/skills/validate-bib/references/preprint-check.md +31 -0
  285. package/skills/validate-bib/references/report-template.md +62 -0
@@ -0,0 +1,217 @@
1
+ #!/usr/bin/env python3
2
+ """Generate ~/.codex/AGENTS.md from Claude Code agents and rules.
3
+
4
+ Reads agent definitions (.claude/agents/*.md) and rule files
5
+ (.claude/rules/*.md), then produces a single AGENTS.md for Codex CLI.
6
+
7
+ Usage:
8
+ uv run python .scripts/generate-codex-agents-md.py \
9
+ --agents-dir ~/.claude/agents \
10
+ --rules-dir ~/.claude/rules \
11
+ --output ~/.codex/AGENTS.md
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import argparse
17
+ import re
18
+ from pathlib import Path
19
+
20
+
21
+ def parse_frontmatter(text: str) -> tuple[dict[str, str], str]:
22
+ """Extract YAML frontmatter and body from markdown."""
23
+ if not text.startswith("---"):
24
+ return {}, text
25
+ end = text.find("---", 3)
26
+ if end == -1:
27
+ return {}, text
28
+ fm_text = text[3:end].strip()
29
+ body = text[end + 3 :].strip()
30
+ meta: dict[str, str] = {}
31
+ for line in fm_text.splitlines():
32
+ if ":" in line:
33
+ key, _, val = line.partition(":")
34
+ meta[key.strip()] = val.strip().strip('"').strip("'")
35
+ return meta, body
36
+
37
+
38
+ def read_agent(path: Path) -> dict[str, str]:
39
+ """Read an agent file and return name + description + body."""
40
+ text = path.read_text(encoding="utf-8")
41
+ meta, body = parse_frontmatter(text)
42
+ return {
43
+ "name": meta.get("name", path.stem),
44
+ "description": meta.get("description", ""),
45
+ "body": body,
46
+ "filename": path.name,
47
+ }
48
+
49
+
50
+ def read_rule(path: Path) -> dict[str, str]:
51
+ """Read a rule file and return its title + content."""
52
+ text = path.read_text(encoding="utf-8")
53
+ meta, body = parse_frontmatter(text)
54
+
55
+ # Extract first heading as title
56
+ title_match = re.search(r"^#\s+(?:Rule:\s*)?(.+)$", body, re.MULTILINE)
57
+ title = title_match.group(1).strip() if title_match else path.stem
58
+
59
+ return {
60
+ "title": title,
61
+ "body": body,
62
+ "filename": path.name,
63
+ }
64
+
65
+
66
+ # Rules that are Claude-specific infrastructure and don't apply to Codex
67
+ SKIP_RULES = {
68
+ "agents-vs-skills.md", # Claude-specific agent/skill distinction
69
+ "break-the-glass.md", # Claude infrastructure protection
70
+ "ignore-agents-md.md", # Ironic — Codex *needs* AGENTS.md
71
+ "ignore-gemini-md.md", # Claude-specific
72
+ "lean-claude-md.md", # Claude-specific
73
+ "public-repo-sync.md", # Claude infrastructure
74
+ "read-docs-first.md", # Claude context system
75
+ "skill-outcome-logging.md", # Claude skill logging
76
+ "severity-gradient.md", # Claude review agents
77
+ "project-orchestration.md", # Claude project commands
78
+ }
79
+
80
+ # Rules to include with full body (most important for behaviour)
81
+ FULL_RULES = {
82
+ "scope-discipline.md",
83
+ "plan-first.md",
84
+ "data-sensitivity.md",
85
+ "overleaf-separation.md",
86
+ "design-before-results.md",
87
+ "no-hardcoded-results.md",
88
+ "latex-outdir.md",
89
+ }
90
+
91
+ # Agents to skip (Codex-specific ones don't make sense)
92
+ SKIP_AGENTS = {
93
+ "codex-research.md", # Meta — Codex reviewing itself
94
+ }
95
+
96
+
97
+ def generate_agents_md(
98
+ agents_dir: Path,
99
+ rules_dir: Path,
100
+ ) -> str:
101
+ """Generate the full AGENTS.md content."""
102
+ sections: list[str] = []
103
+
104
+ # ── Header ───────────────────────────────────────────────────────────
105
+ sections.append(
106
+ """\
107
+ # Codex Instructions
108
+
109
+ > Auto-generated by `sync-to-codex.sh` from Claude Code infrastructure.
110
+ > Do not edit manually — changes will be overwritten on next sync.
111
+
112
+ ## Identity
113
+
114
+ - **User:** the user
115
+ - **Role:** PhD Researcher (Year 1)
116
+ - **Affiliations:** [University 1], [University 2], [University 3] (research) + LSE (teaching)
117
+ - **Research:** [your research areas]
118
+
119
+ ## Conventions
120
+
121
+ - **LaTeX:** Build artifacts go to `out/` via `.latexmkrc`. Never leave `.aux`/`.log` in source.
122
+ - **Python:** Always use `uv` — never bare `python` or `pip`.
123
+ - **R:** Use `<-` for assignment, not `=`.
124
+ - **Git:** Many repos are local-only (Dropbox-synced). Check `git remote -v` before pushing.
125
+ - **Presentations:** Default to LaTeX Beamer.
126
+ - **Data:** `data/raw/` is READ-ONLY. Never modify raw data files.
127
+ """
128
+ )
129
+
130
+ # ── Rules ────────────────────────────────────────────────────────────
131
+ rules_section = ["## Rules\n"]
132
+
133
+ rule_files = sorted(rules_dir.glob("*.md")) if rules_dir.is_dir() else []
134
+ included = 0
135
+ for rf in rule_files:
136
+ if rf.name in SKIP_RULES:
137
+ continue
138
+ rule = read_rule(rf)
139
+ if rf.name in FULL_RULES:
140
+ rules_section.append(f"### {rule['title']}\n")
141
+ # Strip the top-level heading from body (already used as ###)
142
+ body = re.sub(r"^#\s+.*$", "", rule["body"], count=1, flags=re.MULTILINE).strip()
143
+ # Downshift all headings by 2 levels (## → ####, ### → #####)
144
+ body = re.sub(r"^(#{2,})", lambda m: m.group(1) + "##", body, flags=re.MULTILINE)
145
+ rules_section.append(body)
146
+ rules_section.append("")
147
+ else:
148
+ # Summary only — first paragraph after the heading
149
+ body_lines = rule["body"].splitlines()
150
+ summary_lines: list[str] = []
151
+ past_heading = False
152
+ for line in body_lines:
153
+ if line.startswith("#"):
154
+ if past_heading:
155
+ break
156
+ past_heading = True
157
+ continue
158
+ if past_heading and line.strip():
159
+ summary_lines.append(line.strip())
160
+ elif past_heading and not line.strip() and summary_lines:
161
+ break
162
+ summary = " ".join(summary_lines) if summary_lines else rule["title"]
163
+ rules_section.append(f"- **{rule['title']}:** {summary}")
164
+ included += 1
165
+
166
+ sections.append("\n".join(rules_section))
167
+
168
+ # ── Agents (as reference) ────────────────────────────────────────────
169
+ agents_section = [
170
+ "\n## Available Review Agents\n",
171
+ "These agents are available in Claude Code for fresh-context review. ",
172
+ "When using Codex, their descriptions inform what each role does.\n",
173
+ ]
174
+
175
+ agent_files = sorted(agents_dir.glob("*.md")) if agents_dir.is_dir() else []
176
+ for af in agent_files:
177
+ if af.name in SKIP_AGENTS:
178
+ continue
179
+ agent = read_agent(af)
180
+ # Extract just the first line of description (before examples)
181
+ desc = agent["description"].split("\n")[0] if agent["description"] else ""
182
+ # Clean up escaped newlines from YAML
183
+ desc = desc.replace("\\n", " ").strip()
184
+ agents_section.append(f"- **{agent['name']}:** {desc}")
185
+
186
+ sections.append("\n".join(agents_section))
187
+
188
+ # ── Footer ───────────────────────────────────────────────────────────
189
+ sections.append(
190
+ """
191
+ ## Notion Databases
192
+
193
+ | Database | ID |
194
+ |----------|-----|
195
+ | Tasks Tracker | `YOUR-TASKS-DATABASE-ID-HERE` |
196
+ | Research Pipeline | `YOUR-PIPELINE-DATABASE-ID-HERE` |
197
+ | Atlas (Topic Inventory) | `0a227f82-60f4-451a-a163-bff2ce8fa9c3` |
198
+ """
199
+ )
200
+
201
+ return "\n".join(sections)
202
+
203
+
204
+ def main() -> None:
205
+ parser = argparse.ArgumentParser(description="Generate AGENTS.md for Codex CLI")
206
+ parser.add_argument("--agents-dir", type=Path, required=True)
207
+ parser.add_argument("--rules-dir", type=Path, required=True)
208
+ parser.add_argument("--output", type=Path, required=True)
209
+ args = parser.parse_args()
210
+
211
+ content = generate_agents_md(args.agents_dir, args.rules_dir)
212
+ args.output.write_text(content, encoding="utf-8")
213
+ print(f"Generated {args.output} ({len(content)} chars, {content.count(chr(10))} lines)")
214
+
215
+
216
+ if __name__ == "__main__":
217
+ main()
package/.scripts/inbox ADDED
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Show tasks without due dates (inbox review).
4
+
5
+ Usage:
6
+ inbox # Show all inbox tasks
7
+ inbox --assign # Interactively assign due dates
8
+ """
9
+
10
+ import argparse
11
+ import json
12
+ import os
13
+ import sys
14
+ import urllib.request
15
+ import urllib.error
16
+ from datetime import datetime, timedelta
17
+
18
+
19
+ NOTION_TOKEN = os.environ.get("NOTION_TOKEN")
20
+ DATABASE_ID = "YOUR-TASKS-DATABASE-ID-HERE"
21
+
22
+
23
+ def query_inbox():
24
+ """Query tasks without due dates."""
25
+ if not NOTION_TOKEN:
26
+ print("❌ NOTION_TOKEN not set")
27
+ sys.exit(1)
28
+
29
+ data = {
30
+ "filter": {
31
+ "and": [
32
+ {"property": "Status", "status": {"does_not_equal": "Done"}},
33
+ {"property": "Due date", "date": {"is_empty": True}}
34
+ ]
35
+ },
36
+ "sorts": [
37
+ {"property": "Priority", "direction": "ascending"},
38
+ {"timestamp": "created_time", "direction": "descending"}
39
+ ]
40
+ }
41
+
42
+ req = urllib.request.Request(
43
+ f"https://api.notion.com/v1/databases/{DATABASE_ID}/query",
44
+ data=json.dumps(data).encode("utf-8"),
45
+ headers={
46
+ "Authorization": f"Bearer {NOTION_TOKEN}",
47
+ "Content-Type": "application/json",
48
+ "Notion-Version": "2022-06-28",
49
+ },
50
+ method="POST",
51
+ )
52
+
53
+ try:
54
+ with urllib.request.urlopen(req) as response:
55
+ return json.loads(response.read().decode("utf-8"))
56
+ except urllib.error.HTTPError as e:
57
+ error_body = json.loads(e.read().decode("utf-8"))
58
+ print(f"❌ Error: {e.code}")
59
+ print(error_body.get("message", str(error_body)))
60
+ sys.exit(1)
61
+
62
+
63
+ def get_property(page, prop_name, prop_type):
64
+ """Extract property value from a Notion page."""
65
+ prop = page.get("properties", {}).get(prop_name, {})
66
+
67
+ if prop_type == "title":
68
+ title_list = prop.get("title", [])
69
+ return title_list[0].get("plain_text", "") if title_list else ""
70
+ elif prop_type == "select":
71
+ select = prop.get("select")
72
+ return select.get("name", "") if select else ""
73
+ elif prop_type == "status":
74
+ status = prop.get("status")
75
+ return status.get("name", "") if status else ""
76
+ return ""
77
+
78
+
79
+ def set_due_date(page_id, date_str):
80
+ """Set due date for a task."""
81
+ data = {
82
+ "properties": {
83
+ "Due date": {"date": {"start": date_str}}
84
+ }
85
+ }
86
+
87
+ req = urllib.request.Request(
88
+ f"https://api.notion.com/v1/pages/{page_id}",
89
+ data=json.dumps(data).encode("utf-8"),
90
+ headers={
91
+ "Authorization": f"Bearer {NOTION_TOKEN}",
92
+ "Content-Type": "application/json",
93
+ "Notion-Version": "2022-06-28",
94
+ },
95
+ method="PATCH",
96
+ )
97
+
98
+ try:
99
+ with urllib.request.urlopen(req) as response:
100
+ return True
101
+ except urllib.error.HTTPError as e:
102
+ return False
103
+
104
+
105
+ def parse_date(date_str):
106
+ """Parse date input."""
107
+ today = datetime.now()
108
+ date_lower = date_str.lower().strip()
109
+
110
+ if date_lower in ["t", "today"]:
111
+ return today.strftime("%Y-%m-%d")
112
+ elif date_lower in ["tm", "tomorrow"]:
113
+ return (today + timedelta(days=1)).strftime("%Y-%m-%d")
114
+ elif date_lower in ["w", "week"]:
115
+ return (today + timedelta(days=7)).strftime("%Y-%m-%d")
116
+ elif date_lower in ["m", "month"]:
117
+ return (today + timedelta(days=30)).strftime("%Y-%m-%d")
118
+ elif date_lower in ["mon", "monday"]:
119
+ days = (7 - today.weekday()) % 7 or 7
120
+ return (today + timedelta(days=days)).strftime("%Y-%m-%d")
121
+ elif date_lower in ["fri", "friday"]:
122
+ days = (4 - today.weekday()) % 7 or 7
123
+ return (today + timedelta(days=days)).strftime("%Y-%m-%d")
124
+ else:
125
+ return date_str
126
+
127
+
128
+ def format_task(page, index=None):
129
+ """Format a task for display."""
130
+ title = get_property(page, "Task name", "title")
131
+ priority = get_property(page, "Priority", "select")
132
+ project = get_property(page, "Project", "select")
133
+
134
+ priority_emoji = {"High": "🔴", "Medium": "🟡", "Low": "🟢"}.get(priority, "⚪")
135
+
136
+ if index is not None:
137
+ line = f"{index:2}. {priority_emoji} {title}"
138
+ else:
139
+ line = f"{priority_emoji} {title}"
140
+
141
+ if project:
142
+ line += f" [{project}]"
143
+
144
+ return line
145
+
146
+
147
+ def main():
148
+ parser = argparse.ArgumentParser(description="Inbox review - tasks without due dates")
149
+ parser.add_argument("--assign", action="store_true", help="Interactively assign due dates")
150
+
151
+ args = parser.parse_args()
152
+
153
+ result = query_inbox()
154
+ pages = result.get("results", [])
155
+
156
+ if not pages:
157
+ print("📥 Inbox empty! All tasks have due dates.")
158
+ return
159
+
160
+ print(f"📥 Inbox ({len(pages)} tasks without due dates)")
161
+ print("-" * 50)
162
+
163
+ if args.assign:
164
+ print("Shortcuts: t=today, tm=tomorrow, w=week, m=month, fri=friday, s=skip, q=quit\n")
165
+
166
+ for i, page in enumerate(pages, 1):
167
+ print(format_task(page, i))
168
+ try:
169
+ date_input = input(" Due date: ").strip()
170
+
171
+ if date_input.lower() == 'q':
172
+ print("Done.")
173
+ break
174
+ elif date_input.lower() == 's' or not date_input:
175
+ continue
176
+ else:
177
+ date_str = parse_date(date_input)
178
+ if set_due_date(page["id"], date_str):
179
+ print(f" ✅ Set to {date_str}\n")
180
+ else:
181
+ print(f" ❌ Failed to set date\n")
182
+ except KeyboardInterrupt:
183
+ print("\nDone.")
184
+ break
185
+ else:
186
+ for page in pages:
187
+ print(format_task(page))
188
+
189
+ print()
190
+ print("Run 'inbox --assign' to set due dates interactively.")
191
+
192
+
193
+ if __name__ == "__main__":
194
+ main()