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.
- package/.claude/agents/domain-reviewer.md +336 -0
- package/.claude/agents/fixer.md +226 -0
- package/.claude/agents/paper-critic.md +370 -0
- package/.claude/agents/peer-reviewer.md +289 -0
- package/.claude/agents/proposal-reviewer.md +215 -0
- package/.claude/agents/referee2-reviewer.md +367 -0
- package/.claude/agents/references/journal-referee-profiles.md +354 -0
- package/.claude/agents/references/paper-critic/council-personas.md +77 -0
- package/.claude/agents/references/paper-critic/council-prompts.md +198 -0
- package/.claude/agents/references/peer-reviewer/report-template.md +199 -0
- package/.claude/agents/references/peer-reviewer/sa-prompts.md +260 -0
- package/.claude/agents/references/peer-reviewer/security-scan.md +188 -0
- package/.claude/agents/references/proposal-reviewer/report-template.md +144 -0
- package/.claude/agents/references/proposal-reviewer/sa-prompts.md +149 -0
- package/.claude/agents/references/referee-config.md +114 -0
- package/.claude/agents/references/referee2-reviewer/audit-checklists.md +287 -0
- package/.claude/agents/references/referee2-reviewer/report-template.md +334 -0
- package/.claude/rules/design-before-results.md +52 -0
- package/.claude/rules/ignore-agents-md.md +17 -0
- package/.claude/rules/ignore-gemini-md.md +17 -0
- package/.claude/rules/lean-claude-md.md +45 -0
- package/.claude/rules/learn-tags.md +99 -0
- package/.claude/rules/overleaf-separation.md +67 -0
- package/.claude/rules/plan-first.md +175 -0
- package/.claude/rules/read-docs-first.md +50 -0
- package/.claude/rules/scope-discipline.md +28 -0
- package/.claude/settings.json +125 -0
- package/.context/current-focus.md +33 -0
- package/.context/preferences/priorities.md +36 -0
- package/.context/preferences/task-naming.md +28 -0
- package/.context/profile.md +29 -0
- package/.context/projects/_index.md +41 -0
- package/.context/projects/papers/nudge-exp.md +22 -0
- package/.context/projects/papers/uncertainty.md +31 -0
- package/.context/resources/claude-scientific-writer-review.md +48 -0
- package/.context/resources/cunningham-multi-analyst-agents.md +104 -0
- package/.context/resources/cunningham-multilang-code-audit.md +62 -0
- package/.context/resources/google-ai-co-scientist-review.md +72 -0
- package/.context/resources/karpathy-llm-council-review.md +58 -0
- package/.context/resources/multi-coder-reliability-protocol.md +175 -0
- package/.context/resources/pedro-santanna-takeaways.md +96 -0
- package/.context/resources/venue-rankings/abs_ajg_2024.csv +1823 -0
- package/.context/resources/venue-rankings/abs_ajg_2024_econ.csv +356 -0
- package/.context/resources/venue-rankings/cabs_4_4star_theory.csv +40 -0
- package/.context/resources/venue-rankings/core_2026.csv +801 -0
- package/.context/resources/venue-rankings.md +147 -0
- package/.context/workflows/README.md +69 -0
- package/.context/workflows/daily-review.md +91 -0
- package/.context/workflows/meeting-actions.md +108 -0
- package/.context/workflows/replication-protocol.md +155 -0
- package/.context/workflows/weekly-review.md +113 -0
- package/.mcp-server-biblio/formatters.py +158 -0
- package/.mcp-server-biblio/pyproject.toml +11 -0
- package/.mcp-server-biblio/server.py +678 -0
- package/.mcp-server-biblio/sources/__init__.py +14 -0
- package/.mcp-server-biblio/sources/base.py +73 -0
- package/.mcp-server-biblio/sources/formatters.py +83 -0
- package/.mcp-server-biblio/sources/models.py +22 -0
- package/.mcp-server-biblio/sources/multi_source.py +243 -0
- package/.mcp-server-biblio/sources/openalex_source.py +183 -0
- package/.mcp-server-biblio/sources/scopus_source.py +309 -0
- package/.mcp-server-biblio/sources/wos_source.py +508 -0
- package/.mcp-server-biblio/uv.lock +896 -0
- package/.scripts/README.md +161 -0
- package/.scripts/ai_pattern_density.py +446 -0
- package/.scripts/conf +445 -0
- package/.scripts/config.py +122 -0
- package/.scripts/count_inventory.py +275 -0
- package/.scripts/daily_digest.py +288 -0
- package/.scripts/done +177 -0
- package/.scripts/extract_meeting_actions.py +223 -0
- package/.scripts/focus +176 -0
- package/.scripts/generate-codex-agents-md.py +217 -0
- package/.scripts/inbox +194 -0
- package/.scripts/notion_helpers.py +325 -0
- package/.scripts/openalex/query_helpers.py +306 -0
- package/.scripts/papers +227 -0
- package/.scripts/query +223 -0
- package/.scripts/session-history.py +201 -0
- package/.scripts/skill-health.py +516 -0
- package/.scripts/skill-log-miner.py +273 -0
- package/.scripts/sync-to-codex.sh +252 -0
- package/.scripts/task +213 -0
- package/.scripts/tasks +190 -0
- package/.scripts/week +206 -0
- package/CLAUDE.md +197 -0
- package/LICENSE +21 -0
- package/MEMORY.md +38 -0
- package/README.md +269 -0
- package/docs/agents.md +44 -0
- package/docs/bibliography-setup.md +55 -0
- package/docs/council-mode.md +36 -0
- package/docs/getting-started.md +245 -0
- package/docs/hooks.md +38 -0
- package/docs/mcp-servers.md +82 -0
- package/docs/notion-setup.md +109 -0
- package/docs/rules.md +33 -0
- package/docs/scripts.md +303 -0
- package/docs/setup-overview/setup-overview.pdf +0 -0
- package/docs/skills.md +70 -0
- package/docs/system.md +159 -0
- package/hooks/block-destructive-git.sh +66 -0
- package/hooks/context-monitor.py +114 -0
- package/hooks/postcompact-restore.py +157 -0
- package/hooks/precompact-autosave.py +181 -0
- package/hooks/promise-checker.sh +124 -0
- package/hooks/protect-source-files.sh +81 -0
- package/hooks/resume-context-loader.sh +53 -0
- package/hooks/startup-context-loader.sh +102 -0
- package/package.json +51 -0
- package/packages/cli-council/.github/workflows/claude-code-review.yml +44 -0
- package/packages/cli-council/.github/workflows/claude.yml +50 -0
- package/packages/cli-council/README.md +100 -0
- package/packages/cli-council/pyproject.toml +43 -0
- package/packages/cli-council/src/cli_council/__init__.py +19 -0
- package/packages/cli-council/src/cli_council/__main__.py +185 -0
- package/packages/cli-council/src/cli_council/backends/__init__.py +8 -0
- package/packages/cli-council/src/cli_council/backends/base.py +81 -0
- package/packages/cli-council/src/cli_council/backends/claude.py +25 -0
- package/packages/cli-council/src/cli_council/backends/codex.py +27 -0
- package/packages/cli-council/src/cli_council/backends/gemini.py +26 -0
- package/packages/cli-council/src/cli_council/checkpoint.py +212 -0
- package/packages/cli-council/src/cli_council/config.py +51 -0
- package/packages/cli-council/src/cli_council/council.py +391 -0
- package/packages/cli-council/src/cli_council/models.py +46 -0
- package/packages/llm-council/.github/workflows/claude-code-review.yml +44 -0
- package/packages/llm-council/.github/workflows/claude.yml +50 -0
- package/packages/llm-council/README.md +453 -0
- package/packages/llm-council/pyproject.toml +42 -0
- package/packages/llm-council/src/llm_council/__init__.py +23 -0
- package/packages/llm-council/src/llm_council/__main__.py +259 -0
- package/packages/llm-council/src/llm_council/checkpoint.py +193 -0
- package/packages/llm-council/src/llm_council/client.py +253 -0
- package/packages/llm-council/src/llm_council/config.py +232 -0
- package/packages/llm-council/src/llm_council/council.py +482 -0
- package/packages/llm-council/src/llm_council/models.py +46 -0
- package/packages/mcp-bibliography/MEMORY.md +31 -0
- package/packages/mcp-bibliography/_app.py +226 -0
- package/packages/mcp-bibliography/formatters.py +158 -0
- package/packages/mcp-bibliography/log/2026-03-13-2100.md +35 -0
- package/packages/mcp-bibliography/pyproject.toml +15 -0
- package/packages/mcp-bibliography/run.sh +20 -0
- package/packages/mcp-bibliography/scholarly_formatters.py +83 -0
- package/packages/mcp-bibliography/server.py +1857 -0
- package/packages/mcp-bibliography/tools/__init__.py +28 -0
- package/packages/mcp-bibliography/tools/_registry.py +19 -0
- package/packages/mcp-bibliography/tools/altmetric.py +107 -0
- package/packages/mcp-bibliography/tools/core.py +92 -0
- package/packages/mcp-bibliography/tools/dblp.py +52 -0
- package/packages/mcp-bibliography/tools/openalex.py +296 -0
- package/packages/mcp-bibliography/tools/opencitations.py +102 -0
- package/packages/mcp-bibliography/tools/openreview.py +179 -0
- package/packages/mcp-bibliography/tools/orcid.py +131 -0
- package/packages/mcp-bibliography/tools/scholarly.py +575 -0
- package/packages/mcp-bibliography/tools/unpaywall.py +63 -0
- package/packages/mcp-bibliography/tools/zenodo.py +123 -0
- package/packages/mcp-bibliography/uv.lock +711 -0
- package/scripts/setup.sh +143 -0
- package/skills/beamer-deck/SKILL.md +199 -0
- package/skills/beamer-deck/references/quality-rubric.md +54 -0
- package/skills/beamer-deck/references/review-prompts.md +106 -0
- package/skills/bib-validate/SKILL.md +261 -0
- package/skills/bib-validate/references/council-mode.md +34 -0
- package/skills/bib-validate/references/deep-verify.md +79 -0
- package/skills/bib-validate/references/fix-mode.md +36 -0
- package/skills/bib-validate/references/openalex-verification.md +45 -0
- package/skills/bib-validate/references/preprint-check.md +31 -0
- package/skills/bib-validate/references/ref-manager-crossref.md +41 -0
- package/skills/bib-validate/references/report-template.md +82 -0
- package/skills/code-archaeology/SKILL.md +141 -0
- package/skills/code-review/SKILL.md +265 -0
- package/skills/code-review/references/quality-rubric.md +67 -0
- package/skills/consolidate-memory/SKILL.md +208 -0
- package/skills/context-status/SKILL.md +126 -0
- package/skills/creation-guard/SKILL.md +230 -0
- package/skills/devils-advocate/SKILL.md +130 -0
- package/skills/devils-advocate/references/competing-hypotheses.md +83 -0
- package/skills/init-project/SKILL.md +115 -0
- package/skills/init-project-course/references/memory-and-settings.md +92 -0
- package/skills/init-project-course/references/organise-templates.md +94 -0
- package/skills/init-project-course/skill.md +147 -0
- package/skills/init-project-light/skill.md +139 -0
- package/skills/init-project-research/SKILL.md +368 -0
- package/skills/init-project-research/references/atlas-pipeline-sync.md +70 -0
- package/skills/init-project-research/references/atlas-schema.md +81 -0
- package/skills/init-project-research/references/confirmation-report.md +39 -0
- package/skills/init-project-research/references/domain-profile-template.md +104 -0
- package/skills/init-project-research/references/interview-round3.md +34 -0
- package/skills/init-project-research/references/literature-discovery.md +43 -0
- package/skills/init-project-research/references/scaffold-details.md +197 -0
- package/skills/init-project-research/templates/field-calibration.md +60 -0
- package/skills/init-project-research/templates/pipeline-manifest.md +63 -0
- package/skills/init-project-research/templates/run-all.sh +116 -0
- package/skills/init-project-research/templates/seed-files.md +337 -0
- package/skills/insights-deck/SKILL.md +151 -0
- package/skills/interview-me/SKILL.md +157 -0
- package/skills/latex/SKILL.md +141 -0
- package/skills/latex/references/latex-configs.md +183 -0
- package/skills/latex-autofix/SKILL.md +230 -0
- package/skills/latex-autofix/references/known-errors.md +183 -0
- package/skills/latex-autofix/references/quality-rubric.md +50 -0
- package/skills/latex-health-check/SKILL.md +161 -0
- package/skills/learn/SKILL.md +220 -0
- package/skills/learn/scripts/validate_skill.py +265 -0
- package/skills/lessons-learned/SKILL.md +201 -0
- package/skills/literature/SKILL.md +335 -0
- package/skills/literature/references/agent-templates.md +393 -0
- package/skills/literature/references/bibliometric-apis.md +44 -0
- package/skills/literature/references/cli-council-search.md +79 -0
- package/skills/literature/references/openalex-api-guide.md +371 -0
- package/skills/literature/references/openalex-common-queries.md +381 -0
- package/skills/literature/references/openalex-workflows.md +248 -0
- package/skills/literature/references/reference-manager-sync.md +36 -0
- package/skills/literature/references/scopus-api-guide.md +208 -0
- package/skills/literature/references/wos-api-guide.md +308 -0
- package/skills/multi-perspective/SKILL.md +311 -0
- package/skills/multi-perspective/references/computational-many-analysts.md +77 -0
- package/skills/pipeline-manifest/SKILL.md +226 -0
- package/skills/pre-submission-report/SKILL.md +153 -0
- package/skills/process-reviews/SKILL.md +244 -0
- package/skills/process-reviews/references/rr-routing.md +101 -0
- package/skills/project-deck/SKILL.md +87 -0
- package/skills/project-safety/SKILL.md +135 -0
- package/skills/proofread/SKILL.md +254 -0
- package/skills/proofread/references/quality-rubric.md +104 -0
- package/skills/python-env/SKILL.md +57 -0
- package/skills/quarto-deck/SKILL.md +226 -0
- package/skills/quarto-deck/references/markdown-format.md +143 -0
- package/skills/quarto-deck/references/quality-rubric.md +54 -0
- package/skills/save-context/SKILL.md +174 -0
- package/skills/session-log/SKILL.md +98 -0
- package/skills/shared/concept-validation-gate.md +161 -0
- package/skills/shared/council-protocol.md +265 -0
- package/skills/shared/distribution-diagnostics.md +164 -0
- package/skills/shared/engagement-stratified-sampling.md +218 -0
- package/skills/shared/escalation-protocol.md +74 -0
- package/skills/shared/external-audit-protocol.md +205 -0
- package/skills/shared/intercoder-reliability.md +256 -0
- package/skills/shared/mcp-degradation.md +81 -0
- package/skills/shared/method-probing-questions.md +163 -0
- package/skills/shared/multi-language-conventions.md +143 -0
- package/skills/shared/paid-api-safety.md +174 -0
- package/skills/shared/palettes.md +90 -0
- package/skills/shared/progressive-disclosure.md +92 -0
- package/skills/shared/project-documentation-content.md +443 -0
- package/skills/shared/project-documentation-format.md +281 -0
- package/skills/shared/project-documentation.md +100 -0
- package/skills/shared/publication-output.md +138 -0
- package/skills/shared/quality-scoring.md +70 -0
- package/skills/shared/reference-resolution.md +77 -0
- package/skills/shared/research-quality-rubric.md +165 -0
- package/skills/shared/rhetoric-principles.md +54 -0
- package/skills/shared/skill-design-patterns.md +272 -0
- package/skills/shared/skill-index.md +240 -0
- package/skills/shared/system-documentation.md +334 -0
- package/skills/shared/tikz-rules.md +402 -0
- package/skills/shared/validation-tiers.md +121 -0
- package/skills/shared/venue-guides/README.md +46 -0
- package/skills/shared/venue-guides/cell_press_style.md +483 -0
- package/skills/shared/venue-guides/conferences_formatting.md +564 -0
- package/skills/shared/venue-guides/cs_conference_style.md +463 -0
- package/skills/shared/venue-guides/examples/cell_summary_example.md +247 -0
- package/skills/shared/venue-guides/examples/medical_structured_abstract.md +313 -0
- package/skills/shared/venue-guides/examples/nature_abstract_examples.md +213 -0
- package/skills/shared/venue-guides/examples/neurips_introduction_example.md +245 -0
- package/skills/shared/venue-guides/journals_formatting.md +486 -0
- package/skills/shared/venue-guides/medical_journal_styles.md +535 -0
- package/skills/shared/venue-guides/ml_conference_style.md +556 -0
- package/skills/shared/venue-guides/nature_science_style.md +405 -0
- package/skills/shared/venue-guides/reviewer_expectations.md +417 -0
- package/skills/shared/venue-guides/venue_writing_styles.md +321 -0
- package/skills/split-pdf/SKILL.md +172 -0
- package/skills/split-pdf/methodology.md +48 -0
- package/skills/sync-notion/SKILL.md +93 -0
- package/skills/system-audit/SKILL.md +157 -0
- package/skills/system-audit/references/sub-agent-prompts.md +294 -0
- package/skills/task-management/SKILL.md +131 -0
- package/skills/update-focus/SKILL.md +204 -0
- package/skills/update-project-doc/SKILL.md +194 -0
- package/skills/validate-bib/SKILL.md +242 -0
- package/skills/validate-bib/references/council-mode.md +34 -0
- package/skills/validate-bib/references/deep-verify.md +71 -0
- package/skills/validate-bib/references/openalex-verification.md +45 -0
- package/skills/validate-bib/references/preprint-check.md +31 -0
- 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()
|