This repo is usable from three AI coding tools off one shared engine. The newsletter engine lives in scripts/newsletter/ (Node ESM) and every tool calls it as node scripts/newsletter <command> from the repo root — the commands are documented once in newsletter/engine-commands.md. Project instructions live once in AGENTS.md.
| Tool | Instruction file | How the workflow surfaces | Setup | Invocation example |
|---|---|---|---|---|
| Claude Code | CLAUDE.md → imports AGENTS.md |
Native skill auto-dispatch from .claude/skills/ |
npm ci once |
Paste a URL; mt-add-url auto-runs |
| OpenCode | AGENTS.md (auto-read) |
.claude/skills/ auto-discovered via the skill tool, governed by opencode.json |
npm ci once; opencode.json is committed |
Ask to add a URL; pick/skill mt-add-url |
| Codex | AGENTS.md (auto-read) |
Repository skills discovered from .agents/skills/ |
npm ci once; network access enabled |
Ask to add a URL or invoke $mt-add-url |
Shared engine: all three call node scripts/newsletter <command> from repo root — no per-tool script copies. It has npm dependencies, so run npm ci once after cloning.
- Claude Code —
CLAUDE.mdis a thin file that importsAGENTS.md(@AGENTS.md); all instruction content lives inAGENTS.md. No Claude permission file is committed; per-user permissions go in the gitignored.claude/settings.local.json. - OpenCode — reads
.claude/skills/<name>/SKILL.mdnatively (multi-location search up the worktree), so the samemt-*skills work with zero duplication.opencode.jsonis the only committed permission policy: it allows the engine (node scripts/newsletter), read-only and commit git commands,hugo,curl, agent-browser and basic file/text utilities; everything else asks. Rules are last-match-wins, so keep"*": "ask"first. No MCP block — relies on OpenCode's built-in web fetch/search. Restart OpenCode after editingopencode.json(config is not hot-reloaded). - Codex — reads repository skills from
.agents/skills/and can invoke them explicitly ($mt-add-url) or implicitly from their descriptions. Each.agents/skills/<name>/SKILL.mdis a symlink to its.claude/skills/counterpart, so there is one file to edit and nothing that can drift. If a checkout cannot follow symlinks (Windows without developer mode), replace them with thin pointer files that say "read and follow.claude/skills/<name>/SKILL.md". The engine and the fetch tiers need outbound network: run Codex with network enabled (e.g.sandbox_workspace_write.network_access = truein your Codex config), or approve the escalation when prompted.
Once you commit to one tool, delete the others' config. There are no committed Claude settings; .claude/settings.local.json is personal and gitignored.
- Keep Claude Code only → remove
opencode.jsonand.agents/. Keep.claude/anddocs/newsletter/. - Keep OpenCode only → remove
.agents/. Keep.claude/skills/— OpenCode reads it. If you want to drop the.claude/dir entirely, first move skills to.opencode/skills/(scripts are path-neutral inscripts/newsletter/, so the move breaks nothing). Optionally makeAGENTS.mdthe only instruction file (deleteCLAUDE.md). - Keep Codex only → keep
.agents/skills/,AGENTS.md,scripts/newsletter/,docs/newsletter/, and the canonical.claude/skills/files the Codex skills symlink to. You may removeopencode.json.
In every case: keep scripts/newsletter/, .claude/skills/, docs/newsletter/, and AGENTS.md — they are the shared engine, canonical workflows, shared documentation, and instructions.