diff --git a/.senpi/permissions-approved.jsonl b/.senpi/permissions-approved.jsonl new file mode 100644 index 000000000..ebb464009 --- /dev/null +++ b/.senpi/permissions-approved.jsonl @@ -0,0 +1,9 @@ +{"permission":"read","pattern":"/Users/yeongyu/.agents/skills/ssh-jobdori-machine/SKILL.md","action":"allow"} +{"permission":"bash","pattern":"ls","action":"allow"} +{"permission":"bash","pattern":"ls *","action":"allow"} +{"permission":"bash","pattern":"ssh","action":"allow"} +{"permission":"bash","pattern":"ssh *","action":"allow"} +{"permission":"bash","pattern":"tailscale","action":"allow"} +{"permission":"bash","pattern":"tailscale *","action":"allow"} +{"permission":"bash","pattern":"scp","action":"allow"} +{"permission":"bash","pattern":"scp *","action":"allow"} diff --git a/README.md b/README.md index 82ade48f7..ebf67e35d 100644 --- a/README.md +++ b/README.md @@ -101,30 +101,68 @@ Install oh-my-openagent. Type `ultrawork`. Done. ## Installation +oh-my-openagent ships in two editions of the same product: + +- **Ultimate Edition (omo for OpenCode)** — full omo. 11 agents, 54+ lifecycle hooks, 5 built-in MCPs, all slash commands, Team Mode, ultragoal, ultrawork, hashline edits — everything. +- **Light Edition (omo for Codex CLI)** — the 5 components that port cleanly to Codex's plugin system: `rules`, `comment-checker`, `lsp`, `ultrawork`, `ultragoal`. No agent orchestration, no `team_*` tools, no built-in MCPs beyond LSP — Codex CLI's own surface does that work. + +Pick the edition(s) you want. + +### TL;DR + +| You want | Run | What lands on disk | +| :--- | :--- | :--- | +| **Ultimate** (OpenCode) | `bunx omo install` (TUI walks you through it) | Plugin registered in `opencode.json` + agent/model config + provider auth prompts | +| **Light** (Codex CLI) | `bunx omo install --platform=codex` | `~/.codex/plugins/cache/code-yeongyu-codex-plugins/omo/` + `~/.codex/config.toml` plugin block + `~/.local/bin/omo-*` | +| **Both** | `bunx omo install --platform=both` | Both of the above | + +`--platform` defaults to `opencode` (Ultimate). The `bunx lazycodex install` alias is a one-letter-cheaper shortcut for `bunx omo install --platform=codex` — use whichever reads cleaner. + ### For Humans -Copy and paste this prompt to your LLM agent (Claude Code, AmpCode, Cursor, etc.): +**Strongly recommended: let an LLM agent install this for you.** The Ultimate edition setup involves subscription detection, model selection across 11 agents, and per-provider authentication — humans fat-finger these. An LLM agent reads the full guide and walks every step correctly. + +Paste this prompt into Claude Code, AmpCode, Cursor, or any agent: ``` Install and configure oh-my-openagent by following the instructions here: https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md ``` -Or read the [Installation Guide](docs/guide/installation.md), but seriously, let an agent do it. Humans fat-finger configs. +If you only want the **Light edition** (Codex CLI), the installer asks no questions and you can run it yourself in one line: + +```bash +bunx omo install --platform=codex +``` + +> **Do not** use `npm install -g`, `bun add -g`, or `bun install -g`. Global installation is not officially supported — oh-my-openagent is a plugin that must resolve from where OpenCode/Codex loads plugins. Always invoke via `bunx`. ### For LLM Agents -Fetch the installation guide and follow it: +Fetch the full guide and follow it step by step: ```bash -curl -s https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md +curl -fsSL https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md ``` -**Note**: The published npm package and CLI binary are still named `oh-my-opencode` (dual-published as `oh-my-openagent` during the transition). Inside `opencode.json`, the compatibility layer now prefers the plugin entry `oh-my-openagent`, while legacy `oh-my-opencode` entries still load with a warning. Plugin config files still commonly use `oh-my-opencode.json` or `oh-my-opencode.jsonc`; both legacy and renamed basenames are recognized during the transition. +The guide covers: platform selection, the subscription interview, provider authentication (Anthropic / Gemini / Copilot / Z.ai / OpenCode Zen), the agent-to-model matching matrix, modes (`ultrawork`, `search`, `analyze`, `team`, `hyperplan`), slash commands, the Codex adapter's 5 components, Team Mode, and uninstall. Don't summarize it — read it end to end. -Anonymous telemetry is enabled by default to track active installations (DAU/WAU/MAU). A single event is sent at most once per UTC day per machine using a hashed installation identifier, never the raw hostname, and PostHog person profiles are not created. Disable with `OMO_SEND_ANONYMOUS_TELEMETRY=0` or `OMO_DISABLE_POSTHOG=1`. See [Privacy Policy](docs/legal/privacy-policy.md) and [Terms of Service](docs/legal/terms-of-service.md). +### Note on package and command names -If you also use OpenAI Codex CLI, add the optional Codex adapter with `bunx omo install --codex=yes` or the shortcut `bunx lazycodex install`. The Codex adapter emits `omo_codex_daily_active` at most once per UTC day per machine from two sources - the installer (`install_completed`) and the Codex plugin runtime on every session start (`session_start`) - using the same hashed installation identifier and PostHog person-profile suppression as the main plugin. Codex-only telemetry can be disabled with `OMO_CODEX_DISABLE_POSTHOG=1` or `OMO_CODEX_SEND_ANONYMOUS_TELEMETRY=0`. +The published npm package and CLI binary are still named `oh-my-opencode` (dual-published as `oh-my-openagent` during the rename transition). Inside `opencode.json`, the compatibility layer prefers the plugin entry `oh-my-openagent`, while legacy `oh-my-opencode` entries still load with a warning. Plugin config files still commonly use `oh-my-opencode.json[c]`; both legacy and renamed basenames are recognized. + +All four `bunx` aliases — `oh-my-opencode`, `oh-my-openagent`, `omo`, `lazycodex` — invoke the same compiled CLI. `omo` is the recommended short form for documentation and prompts. `lazycodex` is a single-purpose shortcut: `bunx lazycodex install` is exactly equivalent to `bunx omo install --platform=codex`. + +### Telemetry + +Anonymous telemetry is enabled by default to track active installations (DAU/WAU/MAU). For both products, a single event is sent **at most once per UTC day per machine** using a SHA256-hashed installation identifier (never the raw hostname), and PostHog person profiles are not created. The main plugin emits `oh_my_openagent_daily_active`; the Codex adapter emits `omo_codex_daily_active` from two sources (`install_completed` and `session_start`). + +Opt out per product: + +- Main plugin: `OMO_DISABLE_POSTHOG=1` or `OMO_SEND_ANONYMOUS_TELEMETRY=0` +- Codex adapter: `OMO_CODEX_DISABLE_POSTHOG=1` or `OMO_CODEX_SEND_ANONYMOUS_TELEMETRY=0` (the global flags also disable Codex) + +See [Privacy Policy](docs/legal/privacy-policy.md) and [Terms of Service](docs/legal/terms-of-service.md). --- @@ -159,25 +197,30 @@ Even with only the following subscriptions, `ultrawork` works well (this project - [GLM Coding Plan ($10)](https://z.ai/subscribe) - If you're eligible for pay-per-token, using Kimi and Gemini models won't cost much. -| | Feature | What it does | -| :---: | :------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 🤖 | **Discipline Agents** | Sisyphus orchestrates Hephaestus, Oracle, Librarian, Explore. A full AI dev team in parallel. | -| 🧩 | **Codex Harness Adapter** | Same OMO features for OpenAI Codex CLI. Install via `bunx lazycodex install` or `bunx omo install --codex=yes`. | -| 👥 | **Team Mode** (v4.0, opt-in) | Lead agent + up to 8 parallel members, real-time tmux visualization, dedicated `team_*` tools. Powers `hyperplan` (5 hostile critics) and `security-research` (3 hunters + 2 PoC engineers). [Docs →](docs/guide/team-mode.md) | -| ⚡ | **`ultrawork` / `ulw`** | One word. Every agent activates. Doesn't stop until done. | -| 🚪 | **[IntentGate](https://factory.ai/news/terminal-bench)** | Analyzes true user intent before classifying or acting. No more literal misinterpretations. | -| 🔗 | **Hash-Anchored Edit Tool** | `LINE#ID` content hash validates every change. Zero stale-line errors. Inspired by [oh-my-pi](https://github.com/can1357/oh-my-pi). [The Harness Problem →](https://blog.can.ac/2026/02/12/the-harness-problem/) | -| 🛠️ | **LSP + AST-Grep** | Workspace rename, pre-build diagnostics, AST-aware rewrites. IDE precision for agents. | -| 🧠 | **Background Agents** | Fire 5+ specialists in parallel. Context stays lean. Results when ready. | -| 📚 | **Built-in MCPs** | Exa (web search), Context7 (official docs), Grep.app (GitHub search). Always on. | -| 🔁 | **Ralph Loop / `/ulw-loop`** | Self-referential loop. Doesn't stop until 100% done. | -| ✅ | **Todo Enforcer** | Agent goes idle? System yanks it back. Your task gets done, period. | -| 💬 | **Comment Checker** | No AI slop in comments. Code reads like a senior wrote it. | -| 🖥️ | **Tmux Integration** | Full interactive terminal. REPLs, debuggers, TUIs. All live. | -| 🔌 | **Claude Code Compatible** | Your hooks, commands, skills, MCPs, and plugins? All work here. | -| 🎯 | **Skill-Embedded MCPs** | Skills carry their own MCP servers. No context bloat. | -| 📋 | **Prometheus Planner** | Interview-mode strategic planning before any execution. | -| 🔍 | **`/init-deep`** | Auto-generates hierarchical `AGENTS.md` files throughout your project. Great for both token efficiency and your agent's performance. | +| | Feature | Edition | What it does | +| :---: | :------------------------------------------------------- | :------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 🤖 | **Discipline Agents** | Ultimate | Sisyphus orchestrates Hephaestus, Oracle, Librarian, Explore. A full AI dev team in parallel. | +| 🧩 | **Codex CLI Light Edition** | Light | The 5 portable components of omo (rules, comment-checker, LSP, ultrawork, ultragoal) running inside OpenAI Codex CLI. Install via `bunx omo install --platform=codex`. | +| 👥 | **Team Mode** (v4.0, opt-in) | Ultimate | Lead agent + up to 8 parallel members, real-time tmux visualization, dedicated `team_*` tools. Powers `hyperplan` (5 hostile critics) and `security-research` (3 hunters + 2 PoC engineers). [Docs →](docs/guide/team-mode.md) | +| ⚡ | **`ultrawork` / `ulw`** | Both | One word. Every agent activates. Doesn't stop until done. | +| 🚪 | **[IntentGate](https://factory.ai/news/terminal-bench)** | Ultimate | Analyzes true user intent before classifying or acting. No more literal misinterpretations. (Light edition only recognises the `ultrawork`/`ulw` keyword.) | +| 🔗 | **Hash-Anchored Edit Tool** | Ultimate | `LINE#ID` content hash validates every change. Zero stale-line errors. Inspired by [oh-my-pi](https://github.com/can1357/oh-my-pi). [The Harness Problem →](https://blog.can.ac/2026/02/12/the-harness-problem/) | +| 🛠️ | **LSP integration** | Both | Diagnostics, navigation, symbols, workspace rename. IDE precision for agents. Same LSP MCP server in both editions. | +| 🔎 | **AST-Grep** | Ultimate | Pattern-aware code search and rewriting across 25 languages. | +| 🧠 | **Background Agents** | Ultimate | Fire 5+ specialists in parallel. Context stays lean. Results when ready. | +| 📚 | **Built-in MCPs** (web/docs/code search) | Ultimate | Exa (web search), Context7 (official docs), Grep.app (GitHub search). Always on. | +| 🔁 | **Ralph Loop / `/ulw-loop`** | Ultimate | Self-referential loop. Doesn't stop until 100% done. | +| ✅ | **Todo Enforcer** | Ultimate | Agent goes idle? System yanks it back. Your task gets done, period. | +| 💬 | **Comment Checker** | Both | No AI slop in comments. Code reads like a senior wrote it. | +| 📐 | **Rules Injection** (`AGENTS.md` / `.omo/rules/**`) | Both | Project rules and AGENTS.md auto-loaded into the agent's context at every prompt. | +| 🎯 | **Ultragoal** | Both | Durable multi-goal orchestration with evidence audit, backed by `.omo/ultragoal/`. | +| 🖥️ | **Tmux Integration** | Ultimate | Full interactive terminal. REPLs, debuggers, TUIs. All live. | +| 🔌 | **Claude Code Compatible** | Ultimate | Your hooks, commands, skills, MCPs, and plugins? All work here. | +| 🧬 | **Skill-Embedded MCPs** | Ultimate | Skills carry their own MCP servers. No context bloat. | +| 📋 | **Prometheus Planner** | Ultimate | Interview-mode strategic planning before any execution. | +| 🔍 | **`/init-deep`** | Ultimate | Auto-generates hierarchical `AGENTS.md` files throughout your project. Great for both token efficiency and your agent's performance. | + +> **Edition legend.** **Ultimate** = OpenCode-only (`bunx omo install`). **Light** = Codex CLI-only (`bunx omo install --platform=codex`). **Both** = shipped in both editions, often with slightly different implementations under the hood. ### Discipline Agents diff --git a/asdf.md b/asdf.md new file mode 100644 index 000000000..673d2eb3c --- /dev/null +++ b/asdf.md @@ -0,0 +1,20166 @@ +# codex-plugins 이전 및 omo 인스톨러 --codex PR + +**Session ID:** ses_1a205942affeLaSfg0KrkaRiJU +**Created:** 5/25/2026, 4:12:33 PM +**Updated:** 5/25/2026, 11:59:08 PM + +--- + +## User + + + +**MANDATORY**: You MUST say "ULTRAWORK MODE ENABLED!" to the user as your first response when this mode activates. This is non-negotiable. + +[CODE RED] Maximum precision required. Ultrathink before acting. + +## **ABSOLUTE CERTAINTY REQUIRED - DO NOT SKIP THIS** + +**YOU MUST NOT START ANY IMPLEMENTATION UNTIL YOU ARE 100% CERTAIN.** + +| **BEFORE YOU WRITE A SINGLE LINE OF CODE, YOU MUST:** | +|-------------------------------------------------------| +| **FULLY UNDERSTAND** what the user ACTUALLY wants (not what you ASSUME they want) | +| **EXPLORE** the codebase to understand existing patterns, architecture, and context | +| **HAVE A CRYSTAL CLEAR WORK PLAN** - if your plan is vague, YOUR WORK WILL FAIL | +| **RESOLVE ALL AMBIGUITY** - if ANYTHING is unclear, ASK or INVESTIGATE | + +### **MANDATORY CERTAINTY PROTOCOL** + +**IF YOU ARE NOT 100% CERTAIN:** + +1. **THINK DEEPLY** - What is the user's TRUE intent? What problem are they REALLY trying to solve? +2. **EXPLORE THOROUGHLY** - Fire explore/librarian agents to gather ALL relevant context +3. **CONSULT SPECIALISTS** - For hard/complex tasks, DO NOT struggle alone. Delegate: + - **Oracle**: Conventional problems - architecture, debugging, complex logic + - **Artistry**: Non-conventional problems - different approach needed, unusual constraints +4. **ASK THE USER** - If ambiguity remains after exploration, ASK. Don't guess. + +**SIGNS YOU ARE NOT READY TO IMPLEMENT:** +- You're making assumptions about requirements +- You're unsure which files to modify +- You don't understand how existing code works +- Your plan has "probably" or "maybe" in it +- You can't explain the exact steps you'll take + +**WHEN IN DOUBT:** +``` +task(subagent_type="explore", load_skills=[], prompt="I'm implementing [TASK DESCRIPTION] and need to understand [SPECIFIC KNOWLEDGE GAP]. Find [X] patterns in the codebase - show file paths, implementation approach, and conventions used. I'll use this to [HOW RESULTS WILL BE USED]. Focus on src/ directories, skip test files unless test patterns are specifically needed. Return concrete file paths with brief descriptions of what each file does.", run_in_background=true) +task(subagent_type="librarian", load_skills=[], prompt="I'm working with [LIBRARY/TECHNOLOGY] and need [SPECIFIC INFORMATION]. Find official documentation and production-quality examples for [Y] - specifically: API reference, configuration options, recommended patterns, and common pitfalls. Skip beginner tutorials. I'll use this to [DECISION THIS WILL INFORM].", run_in_background=true) +task(subagent_type="oracle", load_skills=[], prompt="I need architectural review of my approach to [TASK]. Here's my plan: [DESCRIBE PLAN WITH SPECIFIC FILES AND CHANGES]. My concerns are: [LIST SPECIFIC UNCERTAINTIES]. Please evaluate: correctness of approach, potential issues I'm missing, and whether a better alternative exists.", run_in_background=false) +``` + +**ONLY AFTER YOU HAVE:** +- Gathered sufficient context via agents +- Resolved all ambiguities +- Created a precise, step-by-step work plan +- Achieved 100% confidence in your understanding + +**...THEN AND ONLY THEN MAY YOU BEGIN IMPLEMENTATION.** + +--- + +## **NO EXCUSES. NO COMPROMISES. DELIVER WHAT WAS ASKED.** + +**THE USER'S ORIGINAL REQUEST IS SACRED. YOU MUST FULFILL IT EXACTLY.** + +| VIOLATION | CONSEQUENCE | +|-----------|-------------| +| "I couldn't because..." | **UNACCEPTABLE.** Find a way or ask for help. | +| "This is a simplified version..." | **UNACCEPTABLE.** Deliver the FULL implementation. | +| "You can extend this later..." | **UNACCEPTABLE.** Finish it NOW. | +| "Due to limitations..." | **UNACCEPTABLE.** Use agents, tools, whatever it takes. | +| "I made some assumptions..." | **UNACCEPTABLE.** You should have asked FIRST. | + +**THERE ARE NO VALID EXCUSES FOR:** +- Delivering partial work +- Changing scope without explicit user approval +- Making unauthorized simplifications +- Stopping before the task is 100% complete +- Compromising on any stated requirement + +**IF YOU ENCOUNTER A BLOCKER:** +1. **DO NOT** give up +2. **DO NOT** deliver a compromised version +3. **DO** consult specialists (oracle for conventional, artistry for non-conventional) +4. **DO** ask the user for guidance +5. **DO** explore alternative approaches + +**THE USER ASKED FOR X. DELIVER EXACTLY X. PERIOD.** + +--- + +YOU MUST LEVERAGE ALL AVAILABLE AGENTS / **CATEGORY + SKILLS** TO THEIR FULLEST POTENTIAL. +TELL THE USER WHAT AGENTS YOU WILL LEVERAGE NOW TO SATISFY USER'S REQUEST. + +## MANDATORY: PLAN AGENT INVOCATION (NON-NEGOTIABLE) + +**YOU MUST ALWAYS INVOKE THE PLAN AGENT FOR ANY NON-TRIVIAL TASK.** + +| Condition | Action | +|-----------|--------| +| Task has 2+ steps | MUST call plan agent | +| Task scope unclear | MUST call plan agent | +| Implementation required | MUST call plan agent | +| Architecture decision needed | MUST call plan agent | + +``` +task(subagent_type="plan", load_skills=[], run_in_background=false, prompt="") +``` + +**WHY PLAN AGENT IS MANDATORY:** +- Plan agent analyzes dependencies and parallel execution opportunities +- Plan agent outputs a **parallel task graph** with waves and dependencies +- Plan agent provides structured TODO list with category + skills per task +- YOU are an orchestrator, NOT an implementer + +### SESSION CONTINUITY WITH PLAN AGENT (CRITICAL) + +**Plan agent output includes a continuation ID (`ses_...`). USE IT for follow-up interactions via `task(task_id="ses_...", ...)`.** + +| Scenario | Action | +|----------|--------| +| Plan agent asks clarifying questions | `task(task_id="{returned_task_id}", load_skills=[], run_in_background=false, prompt="")` | +| Need to refine the plan | `task(task_id="{returned_task_id}", load_skills=[], run_in_background=false, prompt="Please adjust: ")` | +| Plan needs more detail | `task(task_id="{returned_task_id}", load_skills=[], run_in_background=false, prompt="Add more detail to Task N")` | + +**WHY TASK_ID IS CRITICAL:** +- Plan agent retains FULL conversation context +- No repeated exploration or context gathering +- Saves 70%+ tokens on follow-ups +- Maintains interview continuity until plan is finalized + +``` +// WRONG: Starting fresh loses all context +task(subagent_type="plan", load_skills=[], run_in_background=false, prompt="Here's more info...") + +// CORRECT: Resume preserves everything +task(task_id="ses_abc123", load_skills=[], run_in_background=false, prompt="Here's my answer to your question: ...") +``` + +**FAILURE TO CALL PLAN AGENT = INCOMPLETE WORK.** + +--- + +## AGENTS / **CATEGORY + SKILLS** UTILIZATION PRINCIPLES + +**DEFAULT BEHAVIOR: DELEGATE. DO NOT WORK YOURSELF.** + +| Task Type | Action | Why | +|-----------|--------|-----| +| Codebase exploration | task(subagent_type="explore", load_skills=[], run_in_background=true) | Parallel, context-efficient | +| Documentation lookup | task(subagent_type="librarian", load_skills=[], run_in_background=true) | Specialized knowledge | +| Planning | task(subagent_type="plan", load_skills=[], run_in_background=false) | Parallel task graph + structured TODO list | +| Hard problem (conventional) | task(subagent_type="oracle", load_skills=[], run_in_background=false) | Architecture, debugging, complex logic | +| Hard problem (non-conventional) | task(category="artistry", load_skills=[...], run_in_background=true) | Different approach needed | +| Implementation | task(category="...", load_skills=[...], run_in_background=true) | Domain-optimized models | + +**CATEGORY + SKILL DELEGATION:** +``` +// Frontend work +task(category="visual-engineering", load_skills=["frontend-ui-ux"], run_in_background=true) + +// Complex logic +task(category="ultrabrain", load_skills=["typescript-programmer"], run_in_background=true) + +// Quick fixes +task(category="quick", load_skills=["git-master"], run_in_background=true) +``` + +**YOU SHOULD ONLY DO IT YOURSELF WHEN:** +- Task is trivially simple (1-2 lines, obvious change) +- You have ALL context already loaded +- Delegation overhead exceeds task complexity + +**OTHERWISE: DELEGATE. ALWAYS.** + +--- + +## EXECUTION RULES +- **TODO format**: `path: for — verify by ` encoding WHERE / WHY (which scenario it advances) / HOW / VERIFY. Exactly ONE in_progress at a time. Mark completed IMMEDIATELY — never batch. + - GOOD pair (test-first, ordered): `foo.test.ts: Write FAILING case invalid-email→ValidationError for S2 — verify by RED with assertion msg` → `src/foo/bar.ts: Implement validateEmail() for S2 — verify by foo.test.ts GREEN + curl 400 body` + - BAD: "Implement feature" / "Fix bug" / "Add tests later" / production code before its failing test → rewrite. +- **PARALLEL**: Fire independent agent calls simultaneously via task(run_in_background=true) — NEVER wait sequentially. But NEVER parallelise RED and GREEN of the same scenario. +- **BACKGROUND FIRST**: Use task for exploration/research agents (10+ concurrent if needed). +- **VERIFY**: Re-read request after completion. Check every scenario PASS with both artifacts captured. +- **DELEGATE**: Don't do everything yourself — orchestrate specialized agents for their strengths. + +## WORKFLOW +1. Analyze the request and identify required capabilities +2. Spawn exploration/librarian agents via task(run_in_background=true) in PARALLEL (10+ if needed) +3. Use Plan agent with gathered context to create detailed work breakdown +4. Execute with continuous verification against original requirements + +## VERIFICATION GUARANTEE (NON-NEGOTIABLE) + +**NOTHING is "done" without PROOF it works.** + +### Pre-Implementation: Scenario Contract (BINDING) + +BEFORE writing ANY code, define **3+ realistic scenarios** covering: + +| Class | Required | Example | +|-------|----------|---------| +| **Happy path** | yes | Valid input → 200 OK with expected body | +| **Edge** (boundary / empty / malformed / concurrent) | yes | Empty list, max-length input, two writers race | +| **Adjacent-surface regression** | yes | Caller X still works, sibling endpoint Y unchanged | + +Each scenario MUST specify, upfront: +- Pass condition as a binary observable ("returns 200 + body matches schema"), not "should work". +- The REAL surface that proves it: tmux transcript, curl status+body, browser/Playwright assertion, computer-use action log, CLI stdout, parsed config dump, DB state diff. Asserting "tests pass" alone is NOT evidence. +- The automated test file + test id that exercises this scenario (written test-first — see TDD below). + +**These scenarios are the CONTRACT.** Record them in your TODO/notepad. You are not done until every one PASSES with both pieces of evidence captured (RED→GREEN proof + real-surface artifact). + +### Durable Notepad (survives context loss) + +Run once at start: `NOTE=$(mktemp -t ulw-$(date +%Y%m%d-%H%M%S).XXXXXX.md)`. Echo the path. Initialise with these sections and APPEND (never rewrite) as you work: + +``` +# Ultrawork Notepad — +Started: + +## Plan (exhaustive, atomic) +## Scenarios (the contract) +## Now (single step in progress) +## Todo (remaining, ordered) +## Findings (non-obvious facts with file:line refs) +## Learnings (patterns / pitfalls for next turn) +``` + +If context is lost, you re-read the notepad and resume. Do not skip this — it is the only durable memory across turns. + +### Execution & Evidence Requirements + +Every scenario requires TWO captured artifacts — both mandatory: + +| Artifact | Source | Captures | +|----------|--------|----------| +| **RED→GREEN proof** | Test runner output before AND after the change | Test id + assertion message in both states | +| **Real-surface artifact** | tmux / curl / browser / Playwright / computer-use / CLI / DB | What the user actually sees | + +Supporting (necessary, not sufficient): build exit 0, full suite green, lsp_diagnostics clean on changed files, regression scenarios still PASS. + +Tests are the FLOOR (always required). Surface artifact is the CEILING (also required). "tests pass" alone is NOT done. + + +### YOU MUST EXECUTE MANUAL QA YOURSELF. THIS IS NOT OPTIONAL. + +**YOUR FAILURE MODE**: You finish coding, run lsp_diagnostics, and declare "done" without actually TESTING the feature. lsp_diagnostics catches type errors, NOT functional bugs. Your work is NOT verified until you MANUALLY test it. + +**WHAT MANUAL QA MEANS - execute ALL that apply:** + +| If your change... | YOU MUST... | +|---|---| +| Adds/modifies a CLI command | Run the command with Bash. Show the output. | +| Changes build output | Run the build. Verify the output files exist and are correct. | +| Modifies API behavior | Call the endpoint. Show the response. | +| Changes UI rendering | Describe what renders. Use a browser tool if available. | +| Adds a new tool/hook/feature | Test it end-to-end in a real scenario. | +| Modifies config handling | Load the config. Verify it parses correctly. | + +**UNACCEPTABLE QA CLAIMS:** +- "This should work" - RUN IT. +- "The types check out" - Types don't catch logic bugs. RUN IT. +- "lsp_diagnostics is clean" - That's a TYPE check, not a FUNCTIONAL check. RUN IT. +- "Tests pass" - Tests cover known cases. Does the ACTUAL FEATURE work as the user expects? RUN IT. + +**You have Bash, you have tools. There is ZERO excuse for not running manual QA.** +**Manual QA is the FINAL gate before reporting completion. Skip it and your work is INCOMPLETE.** + + +### TDD Workflow (MANDATORY on every production change) + +Test-first is not optional. Every behavior change — features, fixes, refactors, perf, glue, config-with-logic — follows RED → GREEN → SURFACE. + +1. **RED**: Write the failing test FIRST. Run it. Capture the assertion message proving it fails for the RIGHT reason (not syntax, not import). Paste RED output into the notepad. No production code yet. +2. **GREEN**: Write the SMALLEST change that flips RED→GREEN. Re-run. Capture GREEN output. If GREEN required ~20+ lines, your test was too coarse — split it. +3. **SURFACE**: Exercise the real user-facing surface named by the scenario. Capture artifact path into the notepad. +4. **REFACTOR**: Optional, only if needed. Tests MUST stay green throughout. +5. **REGRESSION**: Re-run the FULL scenario list. Record PASS/FAIL inline with both evidence paths. + +**Refactor exception**: Write characterization tests pinning current observable behavior FIRST, watch them go GREEN against old code, THEN refactor. They remain green throughout. + +**Exemption whitelist** (no new test required): pure formatting, comment-only edits, dependency version bumps with no behavior delta, rename-only moves. Each exemption MUST be justified in `## Findings` with the exact reason. Unjustified exemption is rejection. + +**If you typed production code without a failing test preceding it in the notepad: STOP, revert, write the test, watch it fail, then redo.** + +### Verification Anti-Patterns (BLOCKING) + +| Violation | Why It Fails | +|-----------|--------------| +| "It should work now" | No evidence. Run it. | +| "I added the tests" | Did they go RED first, then GREEN? Show both. | +| "Fixed the bug" | What scenario proves it? Where's the artifact? | +| "Implementation complete" | Every scenario PASS with both artifacts captured? | +| Skipping test execution | Tests exist to be RUN, not just written | +| Writing code before its failing test | TDD floor violated — revert, write test, redo | + +**CLAIM NOTHING WITHOUT PROOF. EXECUTE. VERIFY. SHOW EVIDENCE.** + +### Reviewer Gate (triggered, not optional) + +Trigger when ANY apply: user said "엄밀" / "strictly" / "rigorously" / "properly review"; task touches 3+ files OR ran 20+ turns OR 30+ minutes; refactor / migration / perf / security work; user called it "깊게" / "deeply". + +Procedure (non-negotiable): +1. Spawn a reviewer via `task(category="ultrabrain", subagent_type="plan", load_skills=[...], run_in_background=false, prompt="")` — or any high-rigor reviewer agent available. +2. Reviewer verdict is BINDING. There is no "false positive". Do not argue, minimise, or explain away. +3. Fix every concern. Re-run the FULL scenario QA. Capture fresh evidence. Update notepad. +4. Re-submit to the SAME reviewer. Loop until UNCONDITIONAL approval. "looks good but..." = REJECTION. +5. Only on unconditional approval may you declare done. + +## ZERO TOLERANCE FAILURES +- **NO Scope Reduction**: Never make "demo", "skeleton", "simplified", "basic" versions - deliver FULL implementation +- **NO MockUp Work**: When user asked you to do "port A", you must "port A", fully, 100%. No Extra feature, No reduced feature, no mock data, fully working 100% port. +- **NO Partial Completion**: Never stop at 60-80% saying "you can extend this..." - finish 100% +- **NO Assumed Shortcuts**: Never skip requirements you deem "optional" or "can be added later" +- **NO Premature Stopping**: Never declare done until ALL TODOs are completed and verified +- **NO TEST DELETION**: Never delete or skip failing tests to make the build pass. Fix the code, not the tests. + +THE USER ASKED FOR X. DELIVER EXACTLY X. NOT A SUBSET. NOT A DEMO. NOT A STARTING POINT. + +1. EXPLORES + LIBRARIANS +2. GATHER -> PLAN AGENT SPAWN +3. WORK BY DELEGATING TO ANOTHER AGENTS + +NOW. + + + + + +--- + +그 ../codex-plugins 읽고, 여기 로드맵 읽고, 적당한 위치에 이거 옮겨주고, 'omo' 라는 이름으로 인스톨러도 구성해서 패키지 안에 그 잘 만들어서 인스톨러에 --codex 이렇게 해서 설치되도록하게 해서 구상해서 작업해서 pr 올려주라 ulw + +--- + +## Assistant (Sisyphus - Ultraworker · Opus 4.7 · 17.2s) + +_Thinking:_ + + I need to understand the task: explore the codex-plugins directory and the roadmap, then move that code to the right place, set up an 'omo' installer with a `--codex` flag option, and get this ready for a PR while working in ultrawork mode. + +ULTRAWORK MODE ENABLED! + +먼저 `../codex-plugins`, 현재 프로젝트의 ROADMAP, 그리고 기존 인스톨러 구조를 병렬로 탐색해서 정확한 작업 범위를 파악할게요. + +**Tool: bash** + +**Input:** +```json +{ + "command": "ls -la /Users/yeongyu/local-workspaces/", + "description": "List sibling workspaces" +} +``` + +**Output:** +``` +total 10376 +drwxr-xr-x 173 yeongyu staff 5536 May 25 16:09 . +drwxr-xr-x@ 155 yeongyu staff 4960 May 25 13:21 .. +-rw-r--r-- 1 yeongyu staff 30724 May 19 13:53 .DS_Store +drwxr-xr-x@ 7 yeongyu staff 224 May 23 13:28 .omo +drwxr-xr-x@ 3 yeongyu staff 96 May 12 13:12 .sisyphus +drwxr-xr-x 10 yeongyu staff 320 Feb 25 10:07 agent-build +drwxr-xr-x 9 yeongyu staff 288 Feb 25 10:09 agent-build-all +drwxr-xr-x@ 29 yeongyu staff 928 Apr 28 17:47 agent-messenger +drwxr-xr-x@ 23 yeongyu staff 736 Feb 4 14:28 agent-messenger-backup-20260422141405 +drwxr-xr-x@ 6 yeongyu staff 192 Apr 30 17:19 agent-reversing +drwxr-xr-x 30 yeongyu staff 960 May 24 16:07 agentika +drwxr-xr-x@ 8 yeongyu staff 256 Mar 19 13:18 agentika-opencode +drwxr-xr-x@ 36 yeongyu staff 1152 May 15 11:33 ai +drwxr-xr-x 26 yeongyu staff 832 Mar 2 15:46 akiflow-cli +drwxr-xr-x 19 yeongyu staff 608 Jan 9 02:09 anthropic-bypass +drwxr-xr-x 7 yeongyu staff 224 Jan 30 11:12 anthropic-quota +drwxr-xr-x@ 22 yeongyu staff 704 Apr 1 04:07 anthropics-claude-code +drwxr-xr-x 16 yeongyu staff 512 Dec 28 22:27 antigravity-python +drwxr-xr-x@ 36 yeongyu staff 1152 May 20 23:48 apitopia +drwxr-xr-x 200 yeongyu staff 6400 Mar 2 15:50 archived +-rw-r--r-- 1 yeongyu staff 8266 Feb 27 02:08 asdf.md +drwxr-xr-x@ 13 yeongyu staff 416 May 1 21:20 ast-grep-skill +drwxr-xr-x@ 61 yeongyu staff 1952 May 15 11:21 bun +drwxr-xr-x@ 11 yeongyu staff 352 Apr 27 21:51 c11-compiler-zig-omo +drwxr-xr-x@ 19 yeongyu staff 608 Apr 28 10:38 c11-compiler-zig-omo.wt +drwxr-xr-x@ 23 yeongyu staff 736 May 25 01:47 c99inrust +drwxr-xr-x 17 yeongyu staff 544 May 19 16:39 ccapi +drwxr-xr-x@ 3 yeongyu staff 96 Apr 17 11:20 ccapi-worktrees +drwxr-xr-x@ 8 yeongyu staff 256 Apr 14 21:48 chatwise-ccapi-tui +drwxr-xr-x 20 yeongyu staff 640 Feb 22 02:15 claude-agent-sdk-python +drwxr-xr-x 8 yeongyu staff 256 Feb 22 01:55 claude-agent-sdk-typescript +drwxr-xr-x@ 28 yeongyu staff 896 Apr 1 08:28 claude-code +drwxr-xr-x@ 19 yeongyu staff 608 Apr 1 04:35 claude-code-1 +drwxr-xr-x@ 13 yeongyu staff 416 Apr 1 12:19 claw-code +drwxr-xr-x 166 yeongyu staff 5312 May 15 14:11 clawdbot +drwxr-xr-x 32 yeongyu staff 1024 May 24 14:53 CLIProxyAPI +drwxr-xr-x@ 72 yeongyu staff 2304 May 15 12:21 cmux +drwxr-xr-x 4 yeongyu staff 128 Dec 16 00:02 code-yeongyu +drwxr-xr-x 48 yeongyu staff 1536 May 24 16:47 codex +drwxr-xr-x@ 24 yeongyu staff 768 May 16 15:12 codex-lsp-posttooluse-lsp +drwxr-xr-x@ 9 yeongyu staff 288 May 20 11:52 codex-plugins +drwxr-xr-x@ 33 yeongyu staff 1056 May 17 16:26 codex-ratatui +-rw-r--r--@ 1 yeongyu staff 5251414 May 23 22:36 codex-ultrawork-agents.jsonl +drwxr-xr-x@ 7 yeongyu staff 224 May 10 14:56 codextest +drwxr-xr-x 29 yeongyu staff 928 May 18 18:13 comment-checker +drwxr-xr-x 26 yeongyu staff 832 Feb 10 16:24 compare-chat +drwxr-xr-x@ 41 yeongyu staff 1312 May 13 19:46 cua +drwxr-xr-x@ 18 yeongyu staff 576 May 20 15:59 cursor-api +drwxr-xr-x@ 24 yeongyu staff 768 May 19 16:37 cursor-proxy +drwxr-xr-x@ 13 yeongyu staff 416 May 23 14:15 dev-asmr-schedule-proxy +drwxr-xr-x 20 yeongyu staff 640 Dec 11 11:07 dev-browser +drwxr-xr-x 23 yeongyu staff 736 Jan 30 11:20 dev-browser-enhanced +drwxr-xr-x@ 40 yeongyu staff 1280 May 25 11:43 dori +drwxr-xr-x@ 30 yeongyu staff 960 May 7 15:17 dori-broker-adapter +drwxr-xr-x@ 41 yeongyu staff 1312 May 22 01:08 dori-hobby +drwxr-xr-x@ 34 yeongyu staff 1088 May 17 16:25 dori-k2p6turbo-ratatui +drwxr-xr-x@ 32 yeongyu staff 1024 May 17 16:15 dori-mimov25pro-ratatui +drwxr-xr-x@ 33 yeongyu staff 1056 May 16 17:52 dori-senpi-latest-ulw +drwxr-xr-x@ 28 yeongyu staff 896 May 8 19:28 dori-skill-writer +drwxr-xr-x@ 24 yeongyu staff 768 May 15 13:55 flue +drwxr-xr-x@ 18 yeongyu staff 576 Apr 22 16:59 free-code +drwxr-xr-x 60 yeongyu staff 1920 Feb 26 00:09 frommp4tokosrt +drwxr-xr-x 18 yeongyu staff 576 Feb 8 18:52 frontendtest +drwxr-xr-x 26 yeongyu staff 832 Mar 2 06:04 golang-compiler +drwxr-xr-x@ 7 yeongyu staff 224 May 16 18:50 grokbuild +drwxr-xr-x 22 yeongyu staff 704 Feb 28 13:36 harness-reversing +drwxr-xr-x@ 92 yeongyu staff 2944 May 24 17:49 hermes-agent +drwxr-xr-x@ 8 yeongyu staff 256 May 17 02:47 inside-grok-build +drwxr-xr-x@ 32 yeongyu staff 1024 May 17 16:14 kimik26-ratatui +drwxr-xr-x@ 31 yeongyu staff 992 May 24 17:50 letta-code +drwxr-xr-x@ 2 yeongyu staff 64 May 16 18:16 lsp-mcp +drwxr-xr-x@ 20 yeongyu staff 640 May 20 14:15 lsp-tools-mcp +drwxr-xr-x@ 8 yeongyu staff 256 May 1 14:29 m5-mlx-bench +drwxr-xr-x 12 yeongyu staff 384 Feb 26 11:50 macos-bigbrother +drwxr-xr-x@ 19 yeongyu staff 608 May 21 19:01 macos-cua +drwxr-xr-x@ 21 yeongyu staff 672 Apr 24 17:34 memkraft +drwxr-xr-x@ 25 yeongyu staff 800 May 1 13:48 mlx +drwxr-xr-x@ 26 yeongyu staff 832 May 1 13:54 mlx-build +drwxr-xr-x 3 yeongyu staff 96 Apr 13 13:35 mlx-project +drwxr-xr-x 11 yeongyu staff 352 Aug 27 2025 modern-rm.go +drwxr-xr-x 24 yeongyu staff 768 Feb 26 00:07 modern-srt-translator +drwxr-xr-x@ 16 yeongyu staff 512 Apr 30 14:38 morescience +drwxr-xr-x@ 2 yeongyu staff 64 Apr 28 20:26 morescience-plan +drwxr-xr-x 11 yeongyu staff 352 Nov 28 11:29 my-claude-code-harness +drwxr-xr-x@ 30 yeongyu staff 960 May 24 00:20 nomad-web +drwxr-xr-x@ 17 yeongyu staff 544 Apr 1 13:28 not-claude-code-emulator +drwxr-xr-x@ 34 yeongyu staff 1088 May 23 22:25 oh-my-codex +drwxr-xr-x@ 39 yeongyu staff 1248 May 24 15:37 oh-my-openagent +drwxr-xr-x@ 5 yeongyu staff 160 May 24 23:15 oh-my-openagent-wt +drwxr-xr-x@ 21 yeongyu staff 672 May 6 16:11 oh-my-opencode-slim +drwxr-xr-x@ 28 yeongyu staff 896 Mar 19 13:05 oh-my-opencode-web +drwxr-xr-x 35 yeongyu staff 1120 May 23 13:53 oh-my-pi +drwxr-xr-x@ 45 yeongyu staff 1440 May 24 23:38 omo +-rw-r--r--@ 1 yeongyu staff 10225 May 17 15:32 omo_opencode_graph_map.html +drwxr-xr-x@ 33 yeongyu staff 1056 May 18 12:41 omo-ratatui +lrwxr-xr-x@ 1 yeongyu staff 48 Apr 19 14:15 omo-team -> /Users/yeongyu/local-workspaces/omo-wt/team-mode +drwxr-xr-x@ 18 yeongyu staff 576 May 25 00:50 omo-wt +drwxr-xr-x@ 36 yeongyu staff 1152 May 25 16:09 omodex +drwxr-xr-x@ 6 yeongyu staff 192 May 22 20:02 omomon +drwxr-xr-x@ 58 yeongyu staff 1856 May 20 21:56 openclaw +drwxr-xr-x 11 yeongyu staff 352 Feb 23 18:40 openclaw-memory-auto-recall +drwxr-xr-x 69 yeongyu staff 2208 May 24 14:36 opencode +drwxr-xr-x 17 yeongyu staff 544 Feb 2 17:35 opencode-antigravity-auth +drwxr-xr-x@ 20 yeongyu staff 640 May 19 12:54 opencode-cursor +drwxr-xr-x 11 yeongyu staff 352 Feb 11 16:43 opencode-kimi-for-coding-auth +drwxr-xr-x 15 yeongyu staff 480 Feb 9 16:11 opencode-memory +drwxr-xr-x 2 yeongyu staff 64 Feb 14 13:38 opencode-simple-tui +drwxr-xr-x 9 yeongyu staff 288 Feb 19 13:30 opencode-tui-ratatui +drwxr-xr-x 28 yeongyu staff 896 Feb 19 13:15 opencode-zen-abusing +drwxr-xr-x 18 yeongyu staff 576 Dec 6 17:04 opentui +drwxr-xr-x 4 yeongyu staff 128 Apr 13 15:14 opus45-vs-opus46-04132026 +drwxr-xr-x@ 30 yeongyu staff 960 Mar 11 20:03 ouroboros +drwxr-xr-x 12 yeongyu staff 384 Jan 23 18:57 pathtent +drwxr-xr-x@ 19 yeongyu staff 608 May 23 21:02 pi-cursor-sdk +drwxr-xr-x@ 33 yeongyu staff 1056 May 18 15:33 pi-extensions +drwxr-xr-x@ 23 yeongyu staff 736 May 18 15:49 pi-mono +drwxr-xr-x@ 36 yeongyu staff 1152 May 24 00:28 planet-sim-atlas +drwxr-xr-x@ 6 yeongyu staff 192 Apr 28 20:37 planet-sim-atlas-wt +drwxr-xr-x@ 71 yeongyu staff 2272 May 24 00:23 planet-simulator +drwxr-xr-x@ 33 yeongyu staff 1056 Apr 28 20:21 planet-simulator-fixwave-A +drwxr-xr-x@ 33 yeongyu staff 1056 Apr 28 20:23 planet-simulator-fixwave-B +drwxr-xr-x@ 33 yeongyu staff 1056 Apr 28 20:21 planet-simulator-fixwave-C +drwxr-xr-x@ 26 yeongyu staff 832 Apr 30 15:51 plugsuits +drwxr-xr-x@ 34 yeongyu staff 1088 Mar 11 18:40 pr2366-review +drwxr-xr-x@ 34 yeongyu staff 1088 Mar 11 17:30 pr2367-review +drwxr-xr-x@ 34 yeongyu staff 1088 Mar 11 18:27 pr2370-review +drwxr-xr-x@ 32 yeongyu staff 1024 Mar 11 18:42 pr2371-review +drwxr-xr-x@ 2 yeongyu staff 64 Apr 30 17:18 prompting-guides +drwxr-xr-x@ 26 yeongyu staff 832 May 15 12:22 psmux +drwxr-xr-x@ 2 yeongyu staff 64 Mar 17 14:49 saneagent-private +drwxr-xr-x@ 2 yeongyu staff 64 Apr 28 20:16 science +drwxr-xr-x@ 39 yeongyu staff 1248 May 24 18:33 senpi +drwxr-xr-x@ 26 yeongyu staff 832 May 15 15:34 senpi-codex-error-hardening +drwxr-xr-x@ 24 yeongyu staff 768 May 15 14:43 senpi-issue-2-fix +drwxr-xr-x@ 25 yeongyu staff 800 May 8 11:54 senpi-mono-model-config-controls +drwxr-xr-x@ 24 yeongyu staff 768 May 8 12:10 senpi-mono-rename +drwxr-xr-x@ 25 yeongyu staff 800 May 10 15:34 senpi-mono-tui-flicker +drwxr-xr-x@ 34 yeongyu staff 1088 May 18 14:24 senpi-neo-tui +drwxr-xr-x@ 30 yeongyu staff 960 May 20 12:53 senpi-neo-tui-rewrite +drwxr-xr-x@ 25 yeongyu staff 800 May 15 12:13 senpi-provider-recovery-hardening +drwxr-xr-x@ 24 yeongyu staff 768 May 15 14:10 senpi-provider-recovery-ulw +drwxr-xr-x@ 24 yeongyu staff 768 May 15 16:09 senpi-rate-limit-wait-handling +drwxr-xr-x@ 25 yeongyu staff 800 May 15 12:21 senpi-sync-upstream-a8af0b5e +drwxr-xr-x@ 25 yeongyu staff 800 May 15 13:15 senpi-tui-mux-rendering +drwxr-xr-x@ 36 yeongyu staff 1152 May 24 18:06 senpi-tui-tool-call-background +drwxr-xr-x@ 74 yeongyu staff 2368 May 13 10:47 shuvcode +drwxr-xr-x 43 yeongyu staff 1376 Mar 12 14:24 sisyphus +drwxr-xr-x 8 yeongyu staff 256 Dec 31 18:06 sisyphus-ideanotes +drwxr-xr-x 37 yeongyu staff 1184 Mar 4 00:43 sisyphus-sandbox +drwxr-xr-x 33 yeongyu staff 1056 Apr 20 14:20 storm-cli +drwxr-xr-x 20 yeongyu staff 640 Apr 20 14:19 storm-linter +drwxr-xr-x 17 yeongyu staff 544 Dec 29 00:17 stt +drwxr-xr-x@ 2 yeongyu staff 64 Apr 14 21:38 talk +drwxr-xr-x@ 22 yeongyu staff 704 Apr 25 08:33 tetris-web +drwxr-xr-x@ 12 yeongyu staff 384 Apr 25 03:56 tetris-web-core +drwxr-xr-x@ 12 yeongyu staff 384 Apr 25 03:56 tetris-web-mp +drwxr-xr-x@ 12 yeongyu staff 384 Apr 25 03:56 tetris-web-render +drwxr-xr-x@ 12 yeongyu staff 384 Apr 25 03:56 tetris-web-ui +drwxr-xr-x@ 42 yeongyu staff 1344 Mar 22 01:23 thehackathon +drwxr-xr-x@ 173 yeongyu staff 5536 May 15 12:20 tmux +drwxr-xr-x 9 yeongyu staff 288 Dec 29 06:01 token-router +drwxr-xr-x 24 yeongyu staff 768 May 20 15:55 tokscale +drwxr-xr-x 16 yeongyu staff 512 Feb 8 15:26 tokscale-improved +drwxr-xr-x 21 yeongyu staff 672 Mar 22 01:09 tps-checker +drwxr-xr-x@ 10 yeongyu staff 320 Apr 25 13:44 tt-web +drwxr-xr-x@ 11 yeongyu staff 352 May 24 00:28 ultimate-webfetch-skill +drwxr-xr-x@ 12 yeongyu staff 384 May 1 17:51 ultimate-websearch-skill +drwxr-xr-x 54 yeongyu staff 1728 May 15 14:10 ulwcode +drwxr-xr-x@ 45 yeongyu staff 1440 May 15 14:04 warp +drwxr-xr-x 53 yeongyu staff 1696 Mar 2 16:34 whisper-client +drwxr-xr-x@ 8 yeongyu staff 256 May 10 13:36 you-are-the-product +drwxr-xr-x 29 yeongyu staff 928 Dec 9 13:53 yt-dlp +drwxr-xr-x@ 31 yeongyu staff 992 May 15 12:21 zellij + +``` + +**Tool: bash** + +**Input:** +```json +{ + "command": "ls -la /Users/yeongyu/local-workspaces/omodex/", + "description": "Root layout of current project" +} +``` + +**Output:** +``` +total 672 +drwxr-xr-x@ 36 yeongyu staff 1152 May 25 16:09 . +drwxr-xr-x 173 yeongyu staff 5536 May 25 16:09 .. +drwxr-xr-x@ 6 yeongyu staff 192 May 25 16:09 .agents +-rw-r--r--@ 1 yeongyu staff 66 May 25 16:09 .git +drwxr-xr-x@ 7 yeongyu staff 224 May 25 16:09 .github +-rw-r--r--@ 1 yeongyu staff 665 May 25 16:09 .gitignore +-rw-r--r--@ 1 yeongyu staff 121 May 25 16:09 .gitmodules +drwxr-xr-x@ 5 yeongyu staff 160 May 25 16:09 .omo +drwxr-xr-x@ 10 yeongyu staff 320 May 25 16:10 .opencode +-rw-r--r--@ 1 yeongyu staff 29172 May 25 16:09 AGENTS.md +drwxr-xr-x@ 4 yeongyu staff 128 May 25 16:09 assets +drwxr-xr-x@ 6 yeongyu staff 192 May 25 16:09 bin +-rw-r--r--@ 1 yeongyu staff 2062 May 25 16:09 bun-test.d.ts +-rw-r--r--@ 1 yeongyu staff 46826 May 25 16:09 bun.lock +-rw-r--r--@ 1 yeongyu staff 132 May 25 16:09 bunfig.toml +-rw-r--r--@ 1 yeongyu staff 17520 May 25 16:09 CHANGELOG.md +-rw-r--r--@ 1 yeongyu staff 2783 May 25 16:09 CLA.md +-rw-r--r--@ 1 yeongyu staff 9081 May 25 16:09 CONTRIBUTING.md +drwxr-xr-x@ 11 yeongyu staff 352 May 25 16:09 docs +-rw-r--r--@ 1 yeongyu staff 3973 May 25 16:09 LICENSE.md +-rw-r--r--@ 1 yeongyu staff 5717 May 25 16:09 package.json +drwxr-xr-x@ 26 yeongyu staff 832 May 25 16:09 packages +-rw-r--r--@ 1 yeongyu staff 3533 May 25 16:09 postinstall.mjs +-rw-r--r--@ 1 yeongyu staff 35665 May 25 16:09 README.ja.md +-rw-r--r--@ 1 yeongyu staff 31030 May 25 16:09 README.ko.md +-rw-r--r--@ 1 yeongyu staff 27652 May 25 16:09 README.md +-rw-r--r--@ 1 yeongyu staff 40373 May 25 16:09 README.ru.md +-rw-r--r--@ 1 yeongyu staff 28884 May 25 16:09 README.zh-cn.md +-rw-r--r--@ 1 yeongyu staff 6314 May 25 16:09 ROADMAP.md +drwxr-xr-x@ 17 yeongyu staff 544 May 25 16:09 script +drwxr-xr-x@ 3 yeongyu staff 96 May 25 16:09 signatures +drwxr-xr-x@ 41 yeongyu staff 1312 May 25 16:09 src +-rw-r--r--@ 1 yeongyu staff 2424 May 25 16:09 test-setup.ts +drwxr-xr-x@ 3 yeongyu staff 96 May 25 16:09 test-support +drwxr-xr-x@ 3 yeongyu staff 96 May 25 16:09 tests +-rw-r--r--@ 1 yeongyu staff 545 May 25 16:09 tsconfig.json + +``` + +--- + +## Assistant (Sisyphus - Ultraworker · Opus 4.7 · 13.6s) + +_Thinking:_ + + Now I'm reviewing the ROADMAP, examining the codex-plugins directory structure, and looking at the existing installer implementation to understand how everything fits together. + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/omodex/ROADMAP.md" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/omodex/ROADMAP.md +file + +1: # ROADMAP +2: +3: - [What This Is](#what-this-is) +4: - [Current Priority: Package Layering Refactor](#current-priority-package-layering-refactor) +5: - [Architecture Direction](#architecture-direction) +6: - [Multi-Harness Support (Exploratory)](#multi-harness-support-exploratory) +7: - [Why Not OpenCode-Native](#why-not-opencode-native) +8: - [Non-Goals](#non-goals) +9: - [Decision Principle](#decision-principle) +10: +11: ## What This Is +12: +13: Oh-my-opencode is a harness for agents. +14: +15: The human is not the worker. The agent is the worker. The human says what they want. Then they leave. The agent does the work. The human does not come back to fix details. The human does not come back to clarify. The human does not come back at all. +16: +17: OMO does not make agents better at small tasks. OMO makes it possible to hand off big tasks. The kind of tasks where a human would normally stay in the loop for hours. OMO removes that loop. +18: +19: The agent thinks. The agent decides. The agent executes. The human only initiates. +20: +21: ## Current Priority: Package Layering Refactor +22: +23: **This is the most urgent work.** +24: +25: The current `packages/` directory mixes binaries, web apps, MCP servers, and pure TypeScript logic in one flat namespace. This makes reuse across harnesses impossible and creates duplication across three repositories (`omo`, `pi-extensions`, `codex-plugins`). +26: +27: The refactor splits packages into strict layers by runtime boundary: +28: +29: | Layer | Contents | Boundary | +30: |---|---|---| +31: | Core | Pure TypeScript logic: rule discovery, AGENTS.md parsing, config schemas, model capabilities, todo state machines | No harness dependencies. Testable in isolation. | +32: | MCP | External tool servers: LSP, ast-grep | stdio process boundary. Host-agnostic. | +33: | Skills | Static declarative files (SKILL.md) | Markdown consumed by the agent. No code. | +34: | Adapters | Harness-specific glue: OpenCode plugin, Pi extensions, Codex plugins | Thin wrappers. Import core, wrap in harness API, export. | +35: | Platform | Bun compile binaries per target | Deployment artifacts. Never imported. | +36: | Web | Marketing site | Independent application. | +37: +38: **Dependency rule:** The DAG flows downward only. Adapters depend on Core, MCP, and Skills. Nothing depends on Adapters. Platform and Web are leaves. +39: +40: **Migration principle:** Existing behavior is preserved. Nothing breaks. Each extraction is a pure move: copy logic into Core, make the original location re-export from Core, verify tests still pass, then delete the duplicate in the other repositories. +41: +42: **Current extraction status:** +43: +44: - 7 Core packages are now extracted under `packages/`: `utils`, `model-core`, `rules-engine`, `agents-md-core`, `ast-grep-core`, `comment-checker-core`, `boulder-state`. +45: - `omo` consumes all 7 via workspace dependencies plus per-file re-export shims at the original `src/` locations. +46: - `pi-extensions` and `codex-plugins` are not yet migrated to consume these packages. That migration is the next phase. +47: - The `lsp-tools-mcp` submodule is untouched. `lsp-core` extraction is `[~]` deferred pending submodule strategy. +48: +49: Layering achieved: Core (7 pure-TS packages) → Adapter (`omo` plugin) → Platform binaries. Future Pi and Codex adapters will consume the same Core layer. +50: +51: The Pi Engine DI abstraction was deferred. It can be revisited once the adapter migration is complete. +52: +53: ## Architecture Direction +54: +55: The codebase is built for the agent doing the work, not for the human reading it. If a structure is harder for a human to understand but makes the agent's job easier, we keep it. If a pattern adds friction to the agent's reasoning, we remove it. +56: +57: The hierarchy of expression is: +58: +59: 1. **Skill** (static knowledge, zero runtime cost) +60: 2. **MCP** (external tool with process boundary) +61: 3. **Tool** (first-party runtime capability) +62: 4. **Hook** (injection into the agent loop itself) +63: +64: This order is not dogma. If the loop performs better another way, we change it. Agent performance is the only metric. +65: +66: ## Multi-Harness Support (Exploratory) +67: +68: We may support additional harnesses: Claude Code, Codex, Pi, Amp, Droid, and others. Not confirmed. The current codebase is strongly coupled to OpenCode. Extracting the pure logic into a harness-neutral layer is a prerequisite if we ever do this. +69: +70: Most harnesses share common lifecycle hooks: pre-tool-use guards, post-tool-use transforms, system message injection, model parameter overrides. One could abstract these into a unified hook layer. Rule injection could become a harness-agnostic primitive that adapts to each plugin API. +71: +72: We are skeptical of this abstraction. +73: +74: The industry changes too fast. Fixed patterns and agreed conventions should be implemented directly. Uncertain parts should not be over-abstracted. If an adapter for a new harness is needed, an agent can write it in one shot. The connection points are a single question away. Premature "adapter pattern" abstraction across unstable interfaces causes more pain than duplication. +75: +76: We express what each component does in markdown documentation, not in interface definitions. +77: +78: ## Why Not OpenCode-Native +79: +80: OpenCode is the current host. But its plugin API makes it trivial to break the main agent loop. +81: +82: Session prompt injection (`session.prompt`, `session.promptAsync`) returns before the prompt is durably accepted. Later failures arrive as `session.error`. Multiple hooks observe the same idle or error edge and inject the same internal message into a live parent session. Duplicate work. Infinite loops. State corruption. +83: +84: The TUI burns CPU. +85: +86: Breaking changes are frequent. +87: +88: These are not OpenCode-specific flaws. Any plugin system that exposes the main loop to arbitrary injection has the same disease. We treat OpenCode as one adapter target among several. Not the center of the architecture. +89: +90: ## Non-Goals +91: +92: - We will not create a grand unified plugin interface that abstracts every harness. +93: - We will not prioritize human-readable file organization over agent loop performance. +94: - We will not fill in unspecified human details as a primary objective. The harness completes what was stated, using the model's natural representation. +95: +96: ## Decision Principle +97: +98: When in doubt, prefer the representation that requires the least reasoning from the agent doing the work. +99: +100: If that makes the directory structure messy for a human, the directory structure is wrong for humans and right for agents. + +(End of file - total 100 lines) + + +[Project README: /Users/yeongyu/local-workspaces/omodex/README.md] +> [!NOTE] +> **Multi-Harness Agent OS Refactor in Progress** +> +> We are restructuring the codebase to support multiple agent harnesses (OpenCode, Codex, Pi, and others). If you are interested in contributing, please read the [ROADMAP](./ROADMAP.md) first. PRs related to roadmap work should use the `ROADMAP` label. + +> [!TIP] +> **Building in Public** +> +> The maintainer builds and maintains oh-my-openagent in real-time with Jobdori, an AI assistant running on a heavily customized fork of OpenClaw. +> Every feature, every fix, every issue triage — live in our Discord. +> +> [![Building in Public](./.github/assets/building-in-public.png)](https://discord.gg/PUwSMR9XNk) +> +> [**→ Watch it happen in #building-in-public**](https://discord.gg/PUwSMR9XNk) + +> [!NOTE] +> +> [![Sisyphus Labs - Meet Dori. Not a demo. Subscribes to everything.](./.github/assets/sisyphuslabs.png?v=4)](https://sisyphuslabs.ai) +> > **OmO is maintained by Jobdori, the AI assistant shown above. Meet your own Jobdori — Dori.
Join the waitlist [here](https://sisyphuslabs.ai).** + +> [!TIP] +> Be with us! +> +> | [Discord link](https://discord.gg/PUwSMR9XNk) | Join our [Discord community](https://discord.gg/PUwSMR9XNk) to connect with contributors and fellow `oh-my-openagent` users. | +> | :-----| :----- | +> | [X link](https://x.com/justsisyphus) | Updates for `oh-my-openagent` used to be posted on my X account.
Since it was mistakenly suspended, [@justsisyphus](https://x.com/justsisyphus) now posts updates on my behalf. | +> | [GitHub Follow](https://github.com/code-yeongyu) | Follow [@code-yeongyu](https://github.com/code-yeongyu) on GitHub for more projects. | + + + +
+ +OmO + +[![Oh My OpenAgent](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent) + +[![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent) + +
+ +> This is oh-my-openagent, running Team Mode. With Kimi K2.6 and GPT-5.5. + +> Anthropic [**blocked OpenCode because of us.**](https://x.com/thdxr/status/2010149530486911014) **Yes, this is true.** +> They want you locked in. Claude Code is a nice prison, but it's still a prison. +> +> You don't need to pay $200 for 2 hours of work. +> The future isn't picking one winner; it's orchestrating them all. Models get cheaper every month. Smarter every month. No single provider will dominate. We're building for that open market, not their walled gardens. + +
+ +[![GitHub Release](https://img.shields.io/github/v/release/code-yeongyu/oh-my-openagent?color=369eff&labelColor=black&logo=github&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/releases) +[![npm downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fohmyopenagent.com%2Fapi%2Fnpm-downloads&style=flat-square)](https://www.npmjs.com/package/oh-my-opencode) +[![GitHub Contributors](https://img.shields.io/github/contributors/code-yeongyu/oh-my-openagent?color=c4f042&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/graphs/contributors) +[![GitHub Forks](https://img.shields.io/github/forks/code-yeongyu/oh-my-openagent?color=8ae8ff&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/network/members) +[![GitHub Stars](https://img.shields.io/github/stars/code-yeongyu/oh-my-openagent?color=ffcb47&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/stargazers) +[![GitHub Issues](https://img.shields.io/github/issues/code-yeongyu/oh-my-openagent?color=ff80eb&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/issues) +[![License](https://img.shields.io/badge/license-SUL--1.0-white?labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/blob/dev/LICENSE.md) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/code-yeongyu/oh-my-openagent) +[![Docs](https://img.shields.io/badge/docs-omo.vibetip.help-369eff?labelColor=black&logo=readthedocs&logoColor=white&style=flat-square)](https://omo.vibetip.help/docs) + +[English](README.md) | [한국어](README.ko.md) | [日本語](README.ja.md) | [简体中文](README.zh-cn.md) + +
+ + + +## Reviews + +> "It made me cancel my Cursor subscription. Unbelievable things are happening in the open source community." - [Arthur Guiot](https://x.com/arthur_guiot/status/2008736347092382053?s=20) + +> "If Claude Code does in 7 days what a human does in 3 months, Sisyphus does it in 1 hour. It just works until the task is done. It is a discipline agent."
- B, Quant Researcher + +> "Knocked out 8000 eslint warnings with Oh My Opencode, just in a day"
- [Jacob Ferrari](https://x.com/jacobferrari_/status/2003258761952289061) + +> "I converted a 45k line tauri app into a SaaS web app overnight using Ohmyopencode and ralph loop. Started with interview me prompt, asked it for ratings and recommendations on the questions. It was amazing to watch it work and to wake up this morning to a mostly working website!" - [James Hargis](https://x.com/hargabyte/status/2007299688261882202) + +> "use oh-my-opencode, you will never go back"
- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503) + +> "I haven't really been able to articulate exactly what makes it so great yet, but the development experience has reached a completely different dimension." - [ +苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20) + +> "Experimenting with open code, oh my opencode and supermemory this weekend to build some minecraft/souls-like abomination." +> "Asking it to add crouch animations while I go take my post-lunch walk. [Video]" - [MagiMetal](https://x.com/MagiMetal/status/2005374704178373023) + +> "You guys should pull this into core and recruit him. Seriously. It's really, really, really good."
- Henning Kilset + +> "Hire @yeon_gyu_kim if you can convince him, this dude has revolutionized opencode."
- [mysticaltech](https://x.com/mysticaltech/status/2001858758608376079) + +> "Oh My OpenCode Is Actually Insane" - [YouTube - Darren Builds AI](https://www.youtube.com/watch?v=G_Snfh2M41M) + +--- + +# Oh My OpenAgent + +You're juggling Claude Code, Codex, and random OSS models. Configuring workflows. Debugging agents. + +We did the work. Tested everything. Kept what actually shipped. + +Install oh-my-openagent. Type `ultrawork`. Done. + + +## Installation + +### For Humans + +Copy and paste this prompt to your LLM agent (Claude Code, AmpCode, Cursor, etc.): + +``` +Install and configure oh-my-openagent by following the instructions here: +https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md +``` + +Or read the [Installation Guide](docs/guide/installation.md), but seriously, let an agent do it. Humans fat-finger configs. + +### For LLM Agents + +Fetch the installation guide and follow it: + +```bash +curl -s https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md +``` + +**Note**: The published npm package and CLI binary are still named `oh-my-opencode` (dual-published as `oh-my-openagent` during the transition). Inside `opencode.json`, the compatibility layer now prefers the plugin entry `oh-my-openagent`, while legacy `oh-my-opencode` entries still load with a warning. Plugin config files still commonly use `oh-my-opencode.json` or `oh-my-opencode.jsonc`; both legacy and renamed basenames are recognized during the transition. + +Anonymous telemetry is enabled by default to track active installations (DAU/WAU/MAU). A single event is sent at most once per UTC day per machine using a hashed installation identifier, never the raw hostname, and PostHog person profiles are not created. Disable with `OMO_SEND_ANONYMOUS_TELEMETRY=0` or `OMO_DISABLE_POSTHOG=1`. See [Privacy Policy](docs/legal/privacy-policy.md) and [Terms of Service](docs/legal/terms-of-service.md). + +--- + +## Skip This README + +We're past the era of reading docs. Just paste this into your agent: + +``` +Read this and tell me why it's not just another boilerplate: https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/README.md +``` + + +## ROADMAP + +We are restructuring the codebase to support multiple agent harnesses (OpenCode, Codex, Pi, Claude Code, and others). The most urgent work is the package layering refactor: separating pure TypeScript core logic, MCP servers, skills, and adapter shims into distinct layers so the same logic can be reused across harnesses without duplication. + +If you want to contribute, read the [ROADMAP](./ROADMAP.md) first. PRs related to this refactor should use the `ROADMAP` label so we can track them. + +## Highlights + +### 🪄 `ultrawork` + +You're actually reading this? Wild. + +Install. Type `ultrawork` (or `ulw`). Done. + +Everything below, every feature, every optimization: you don't need to know any of it. It just works. + +Even with only the following subscriptions, `ultrawork` works well (this project is not affiliated; these are personal recommendations): +- [ChatGPT Subscription ($20)](https://chatgpt.com/) +- [Kimi Code Subscription ($19)](https://www.kimi.com/code) +- [GLM Coding Plan ($10)](https://z.ai/subscribe) +- If you're eligible for pay-per-token, using Kimi and Gemini models won't cost much. + +| | Feature | What it does | +| :---: | :------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 🤖 | **Discipline Agents** | Sisyphus orchestrates Hephaestus, Oracle, Librarian, Explore. A full AI dev team in parallel. | +| 👥 | **Team Mode** (v4.0, opt-in) | Lead agent + up to 8 parallel members, real-time tmux visualization, dedicated `team_*` tools. Powers `hyperplan` (5 hostile critics) and `security-research` (3 hunters + 2 PoC engineers). [Docs →](docs/guide/team-mode.md) | +| ⚡ | **`ultrawork` / `ulw`** | One word. Every agent activates. Doesn't stop until done. | +| 🚪 | **[IntentGate](https://factory.ai/news/terminal-bench)** | Analyzes true user intent before classifying or acting. No more literal misinterpretations. | +| 🔗 | **Hash-Anchored Edit Tool** | `LINE#ID` content hash validates every change. Zero stale-line errors. Inspired by [oh-my-pi](https://github.com/can1357/oh-my-pi). [The Harness Problem →](https://blog.can.ac/2026/02/12/the-harness-problem/) | +| 🛠️ | **LSP + AST-Grep** | Workspace rename, pre-build diagnostics, AST-aware rewrites. IDE precision for agents. | +| 🧠 | **Background Agents** | Fire 5+ specialists in parallel. Context stays lean. Results when ready. | +| 📚 | **Built-in MCPs** | Exa (web search), Context7 (official docs), Grep.app (GitHub search). Always on. | +| 🔁 | **Ralph Loop / `/ulw-loop`** | Self-referential loop. Doesn't stop until 100% done. | +| ✅ | **Todo Enforcer** | Agent goes idle? System yanks it back. Your task gets done, period. | +| 💬 | **Comment Checker** | No AI slop in comments. Code reads like a senior wrote it. | +| 🖥️ | **Tmux Integration** | Full interactive terminal. REPLs, debuggers, TUIs. All live. | +| 🔌 | **Claude Code Compatible** | Your hooks, commands, skills, MCPs, and plugins? All work here. | +| 🎯 | **Skill-Embedded MCPs** | Skills carry their own MCP servers. No context bloat. | +| 📋 | **Prometheus Planner** | Interview-mode strategic planning before any execution. | +| 🔍 | **`/init-deep`** | Auto-generates hierarchical `AGENTS.md` files throughout your project. Great for both token efficiency and your agent's performance. | + +### Discipline Agents + + + + +
+ +**Sisyphus** (`claude-opus-4-7` / **`kimi-k2.6`** / **`glm-5.1`** ) is your main orchestrator. He plans, delegates to specialists, and drives tasks to completion with aggressive parallel execution. He does not stop halfway. + +**Hephaestus** (`gpt-5.5`) is your autonomous deep worker. Give him a goal, not a recipe. He explores the codebase, researches patterns, and executes end-to-end without hand-holding. *The Legitimate Craftsman.* + +**Prometheus** (`claude-opus-4-7` / **`kimi-k2.6`** / **`glm-5.1`** ) is your strategic planner. Interview mode: he asks questions, identifies scope, and builds a detailed plan before a single line of code is touched. + +Every agent is tuned to its model's specific strengths. No manual model juggling. [Learn more →](docs/guide/overview.md) + +> Anthropic [blocked OpenCode because of us.](https://x.com/thdxr/status/2010149530486911014) That's why Hephaestus is called "The Legitimate Craftsman." The irony is intentional. +> +> We run best on Opus, but Kimi K2.6 + GPT-5.5 already beats vanilla Claude Code. Zero config needed. + +### Team Mode (v4.0) + +One agent is fast. A coordinated team is *devastating*. + +**Team Mode** turns oh-my-openagent from "one agent with subagents" into a real multi-agent system. A lead agent orchestrates a team of category-specialized members, all running **in parallel** and communicating through dedicated tools (`team_create`, `team_send_message`, `team_task_create`, `team_status`, ...). Watch every member work simultaneously in a tmux layout with focus + grid windows. + +```jsonc +// .opencode/oh-my-openagent.jsonc +{ + "team_mode": { + "enabled": true, + "max_parallel_members": 4, + "tmux_visualization": true + } +} +``` + +Restart opencode and the `team_*` tool family unlocks. Two skills already ride on top: + +- **`hyperplan`** — 5 hostile agents tear apart your plan from orthogonal angles before a single line of code is written. +- **`security-research`** — 3 vulnerability hunters + 2 PoC engineers audit your codebase in parallel, with severity calibrated by *actual exploitability*. + +> **Off by default. Enable it when you want it.** [Full Team Mode guide →](docs/guide/team-mode.md) + +### Agent Orchestration + +When Sisyphus delegates to a subagent, it doesn't pick a model. It picks a **category**. The category maps automatically to the right model: + +| Category | What it's for | +| :------------------- | :--------------------------------- | +| `visual-engineering` | Frontend, UI/UX, design | +| `deep` | Autonomous research + execution | +| `quick` | Single-file changes, typos | +| `ultrabrain` | Hard logic, architecture decisions | + +The agent says what kind of work it needs; the harness picks the right model. `ultrabrain` now routes to GPT-5.5 xhigh by default. You touch nothing. + +### Claude Code Compatibility + +You dialed in your Claude Code setup. Good. + +Every hook, command, skill, MCP, plugin works here unchanged. Full compatibility, including plugins. + +### World-Class Tools for Your Agents + +LSP, AST-Grep, Tmux, and MCP, actually integrated, not duct-taped together. + +- **LSP**: `lsp_rename`, `lsp_goto_definition`, `lsp_find_references`, `lsp_diagnostics`. IDE precision for every agent. +- **AST-Grep**: Pattern-aware code search and rewriting across 25 languages. +- **Tmux**: Full interactive terminal. REPLs, debuggers, TUI apps. Your agent stays in session. +- **MCP**: Web search, official docs, GitHub code search. All baked in. + +### Skill-Embedded MCPs + +MCP servers eat your context budget. We fixed that. + +Skills bring their own MCP servers. They spin up on demand, scoped to the task, and go away when done. The context window stays clean. + +### Codes Better. Hash-Anchored Edits + +The harness problem is real. Most agent failures aren't the model's fault; it's the edit tool. + +> *"None of these tools give the model a stable, verifiable identifier for the lines it wants to change... They all rely on the model reproducing content it already saw. When it can't - and it often can't - the user blames the model."* +> +>
- [Can Bölük, The Harness Problem](https://blog.can.ac/2026/02/12/the-harness-problem/) + +Inspired by [oh-my-pi](https://github.com/can1357/oh-my-pi), we built **Hashline**. Every line the agent reads comes back tagged with a content hash: + +``` +11#VK| function hello() { +22#XJ| return "world"; +33#MB| } +``` + +The agent edits by referencing those tags. If the file has changed since the last read, the hash won't match and the edit is rejected before any corruption. No whitespace reproduction. No stale-line errors. + +Grok Code Fast 1: **6.7% → 68.3%** success rate, just from changing the edit tool. + +### Deep Initialization. `/init-deep` + +Run `/init-deep`. It generates hierarchical `AGENTS.md` files: + +``` +project/ +├── AGENTS.md ← project-wide context +├── src/ +│ ├── AGENTS.md ← src-specific context +│ └── components/ +│ └── AGENTS.md ← component-specific context +``` + +Agents auto-read relevant context. Zero manual management. + +### Planning. Prometheus + +Complex task? Don't prompt and pray. + +`/start-work` calls Prometheus. He **interviews you like a real engineer**, identifies scope and ambiguities, and builds a verified plan before touching code. The agent knows what it's building before it starts. + +### Skills + +Skills aren't just prompts. Each brings: + +- Domain-tuned system instructions. +- Embedded MCP servers, on demand. +- Scoped permissions so agents stay in bounds. + +Built-ins: `playwright` (browser automation), `git-master` (atomic commits, rebase surgery), `frontend-ui-ux` (design-first UI). + +Add your own under `.opencode/skills/*/SKILL.md` or `~/.config/opencode/skills/*/SKILL.md`. + +**Want the full feature breakdown?** See the **[Features Documentation](docs/reference/features.md)** for agents, hooks, tools, MCPs, and everything else in detail. + +--- + +> **New to oh-my-openagent?** Read the **[Overview](docs/guide/overview.md)** to understand what you have, or check the **[Orchestration Guide](docs/guide/orchestration.md)** for how agents collaborate. + +## Uninstallation + +To remove oh-my-openagent: + +1. **Remove the plugin from your OpenCode config** + + Edit `~/.config/opencode/opencode.json` (or `opencode.jsonc`) and remove either `"oh-my-openagent"` or the legacy `"oh-my-opencode"` entry from the `plugin` array: + + ```bash + # Using jq + jq '.plugin = [.plugin[] | select(. != "oh-my-openagent" and . != "oh-my-opencode")]' \ + ~/.config/opencode/opencode.json > /tmp/oc.json && \ + mv /tmp/oc.json ~/.config/opencode/opencode.json + ``` + +2. **Remove configuration files (optional)** + + ```bash + # Remove plugin config files recognized during the compatibility window + rm -f ~/.config/opencode/oh-my-openagent.jsonc ~/.config/opencode/oh-my-openagent.json \ + ~/.config/opencode/oh-my-opencode.jsonc ~/.config/opencode/oh-my-opencode.json + + # Remove project config (if exists) + rm -f .opencode/oh-my-openagent.jsonc .opencode/oh-my-openagent.json \ + .opencode/oh-my-opencode.jsonc .opencode/oh-my-opencode.json + ``` + +3. **Verify removal** + + ```bash + opencode --version + # Plugin should no longer be loaded + ``` + +## Features + +Features you'll think should've always existed. Once you use them, you can't go back. + +See full [Features Documentation](docs/reference/features.md). + +**Quick Overview:** +- **Agents**: Sisyphus (the main agent), Prometheus (planner), Oracle (architecture/debugging), Librarian (docs/code search), Explore (fast codebase grep), Multimodal Looker +- **Background Agents**: Run multiple agents in parallel like a real dev team +- **LSP & AST Tools**: Refactoring, rename, diagnostics, AST-aware code search +- **Hash-anchored Edit Tool**: `LINE#ID` references validate content before applying every change. Surgical edits, zero stale-line errors +- **Context Injection**: Auto-inject AGENTS.md, README.md, conditional rules +- **Claude Code Compatibility**: Full hook system, commands, skills, agents, MCPs +- **Built-in MCPs**: websearch (Exa), context7 (docs), grep_app (GitHub search) — injected at runtime by the plugin; not visible in `opencode mcp list` (see [MCP docs](docs/reference/features.md#native-vs-plugin-injected-mcps)) +- **Session Tools**: List, read, search, and analyze session history +- **Productivity Features**: Ralph Loop, Todo Enforcer, Comment Checker, Think Mode, and more +- **Doctor Command**: Built-in diagnostics (`bunx oh-my-opencode doctor`) verify plugin registration, config, models, and environment +- **Model Fallbacks**: `fallback_models` can mix plain model strings with per-fallback object settings in the same array +- **File Prompts**: Load prompts from files with `file://` support in agent configurations +- **Session Recovery**: Automatic recovery from session errors, context window limits, and API failures +- **Model Setup**: Agent-model matching is built into the [Installation Guide](docs/guide/installation.md#step-5-understand-your-model-setup) + +## Configuration + +Opinionated defaults, adjustable if you insist. + +See [Configuration Documentation](docs/reference/configuration.md). + +**Quick Overview:** +- **Config Locations**: User config plus walked `.opencode/oh-my-openagent.json[c]` configs up to `$HOME`; closest wins. Legacy `oh-my-opencode.json[c]` still works. +- **JSONC Support**: Comments and trailing commas supported +- **Agents**: Override models, temperatures, prompts, and permissions for any agent +- **Built-in Skills**: `playwright` (browser automation), `git-master` (atomic commits) +- **Sisyphus Agent**: Main orchestrator with Prometheus (Planner) and Metis (Plan Consultant) +- **Background Tasks**: Configure concurrency limits per provider/model +- **Categories**: Domain-specific task delegation (`visual`, `business-logic`, custom) +- **Hooks**: 54+ lifecycle hooks (61 with Team Mode), all configurable via `disabled_hooks` +- **MCPs**: Built-in websearch (Exa), context7 (docs), grep_app (GitHub search) — runtime-injected, not shown in `opencode mcp list` +- **LSP**: Full LSP support with refactoring tools +- **Experimental**: Aggressive truncation, auto-resume, and more + + +## Author's Note + +**Want the philosophy?** Read the [Ultrawork Manifesto](docs/manifesto.md). + +--- + +I burned through $24K in LLM tokens on personal projects. Tried every tool. Configured everything to death. OpenCode won. + +Every problem I hit, the fix is baked into this plugin. Install and go. + +If OpenCode is Debian/Arch, oh-my-openagent is Ubuntu/[Omarchy](https://omarchy.org/). + +Heavily influenced by [AmpCode](https://ampcode.com) and [Claude Code](https://code.claude.com/docs/overview). Features ported, often improved. Still building. It's **Open**Code. + +Other harnesses promise multi-model orchestration. We ship it. Stability too. And features that actually work. + +I'm this project's most obsessive user: +- Which model has the sharpest logic? +- Who's the debugging god? +- Who writes the best prose? +- Who dominates frontend? +- Who owns backend? +- What's fastest for daily driving? +- What are competitors shipping? + +This plugin is the distillation. Take the best. Got improvements? PRs welcome. + +**Stop agonizing over harness choices.** +**I'll research, steal the best, and ship it here.** + +Sounds arrogant? Have a better way? Contribute. You're welcome. + +No affiliation with any project or model mentioned. Just personal experimentation. + +99% of this project was built with OpenCode. I don't really know TypeScript, **but I personally reviewed and largely rewrote this doc.** + +## Loved by professionals at + +- [Indent](https://indentcorp.com) + - Makers of Spray (influencer marketing solution), vovushop (cross-border commerce platform), and vreview (AI commerce review marketing solution). +- [Google](https://google.com) +- [Microsoft](https://microsoft.com) +- [Vercel](https://vercel.com) +- [ELESTYLE](https://elestyle.jp) + - Makers of elepay (multi-mobile payment gateway) and OneQR (mobile application SaaS for cashless solutions). +- [Deepgram](https://deepgram.com) + +*Special thanks to [@junhoyeo](https://github.com/junhoyeo) for this amazing hero image.* + +[Category+Skill Reminder] + +**Built-in**: playwright, review-work, ai-slop-remover, team-mode +**⚡ YOUR SKILLS (PRIORITY)**: frontend-ui-ux, git-master, commit, merge-skills, ast-grep, frontend-perfectionist, browsing, prompt-engineering (+32 more) + +> User-installed skills OVERRIDE built-in defaults. ALWAYS prefer YOUR SKILLS when domain matches. + +```typescript +task(category="visual-engineering", load_skills=["frontend-ui-ux"], run_in_background=true) +``` + +``` + +**Tool: bash** + +**Input:** +```json +{ + "command": "ls -la /Users/yeongyu/local-workspaces/codex-plugins/", + "description": "List codex-plugins directory" +} +``` + +**Output:** +``` +total 32 +drwxr-xr-x@ 9 yeongyu staff 288 May 20 11:52 . +drwxr-xr-x 173 yeongyu staff 5536 May 25 16:09 .. +drwxr-xr-x@ 3 yeongyu staff 96 May 15 13:25 .agents +drwxr-xr-x@ 3 yeongyu staff 96 May 20 12:50 .omo +-rw-r--r--@ 1 yeongyu staff 10518 May 18 16:39 notepad.md +drwxr-xr-x@ 6 yeongyu staff 192 May 19 12:51 plans +drwxr-xr-x@ 5 yeongyu staff 160 May 24 15:19 plugins +-rw-r--r--@ 1 yeongyu staff 1681 May 24 15:20 README.md +drwxr-xr-x@ 5 yeongyu staff 160 May 24 15:22 scripts + +``` + +**Tool: bash** + +**Input:** +```json +{ + "command": "ls -la /Users/yeongyu/local-workspaces/omodex/src/cli/", + "description": "List current CLI structure" +} +``` + +**Output:** +``` +total 392 +drwxr-xr-x@ 3 yeongyu staff 96 May 25 16:09 __snapshots__ +drwxr-xr-x@ 40 yeongyu staff 1280 May 25 16:09 . +drwxr-xr-x@ 41 yeongyu staff 1312 May 25 16:09 .. +-rw-r--r--@ 1 yeongyu staff 3708 May 25 16:09 AGENTS.md +drwxr-xr-x@ 8 yeongyu staff 256 May 25 16:09 boulder +-rw-r--r--@ 1 yeongyu staff 2103 May 25 16:09 cli-installer.telemetry.test.ts +-rw-r--r--@ 1 yeongyu staff 3452 May 25 16:09 cli-installer.test.ts +-rw-r--r--@ 1 yeongyu staff 4971 May 25 16:09 cli-installer.ts +-rw-r--r--@ 1 yeongyu staff 1151 May 25 16:09 cli-program.test.ts +-rw-r--r--@ 1 yeongyu staff 9010 May 25 16:09 cli-program.ts +drwxr-xr-x@ 28 yeongyu staff 896 May 25 16:09 config-manager +-rw-r--r--@ 1 yeongyu staff 1230 May 25 16:09 config-manager.ts +drwxr-xr-x@ 18 yeongyu staff 576 May 25 16:09 doctor +-rw-r--r--@ 1 yeongyu staff 1799 May 25 16:09 fallback-chain-resolution.ts +drwxr-xr-x@ 6 yeongyu staff 192 May 25 16:09 get-local-version +-rw-r--r--@ 1 yeongyu staff 480 May 25 16:09 index.test.ts +-rw-r--r--@ 1 yeongyu staff 68 May 25 16:09 index.ts +-rw-r--r--@ 1 yeongyu staff 868 May 25 16:09 install-validators.test.ts +-rw-r--r--@ 1 yeongyu staff 7135 May 25 16:09 install-validators.ts +-rw-r--r--@ 1 yeongyu staff 5340 May 25 16:09 install.test.ts +-rw-r--r--@ 1 yeongyu staff 402 May 25 16:09 install.ts +drwxr-xr-x@ 10 yeongyu staff 320 May 25 16:09 mcp-oauth +-rw-r--r--@ 1 yeongyu staff 495 May 25 16:09 minimum-opencode-version.ts +-rw-r--r--@ 1 yeongyu staff 889 May 25 16:09 model-fallback-requirements.test.ts +-rw-r--r--@ 1 yeongyu staff 345 May 25 16:09 model-fallback-requirements.ts +-rw-r--r--@ 1 yeongyu staff 715 May 25 16:09 model-fallback-types.ts +-rw-r--r--@ 1 yeongyu staff 23250 May 25 16:09 model-fallback.test.ts +-rw-r--r--@ 1 yeongyu staff 8487 May 25 16:09 model-fallback.ts +-rw-r--r--@ 1 yeongyu staff 2256 May 25 16:09 openai-only-model-catalog.test.ts +-rw-r--r--@ 1 yeongyu staff 1260 May 25 16:09 openai-only-model-catalog.ts +-rw-r--r--@ 1 yeongyu staff 1120 May 25 16:09 provider-availability.ts +-rw-r--r--@ 1 yeongyu staff 14330 May 25 16:09 provider-model-id-transform.test.ts +-rw-r--r--@ 1 yeongyu staff 107 May 25 16:09 provider-model-id-transform.ts +-rw-r--r--@ 1 yeongyu staff 3034 May 25 16:09 refresh-model-capabilities.test.ts +-rw-r--r--@ 1 yeongyu staff 1639 May 25 16:09 refresh-model-capabilities.ts +drwxr-xr-x@ 48 yeongyu staff 1536 May 25 16:09 run +-rw-r--r--@ 1 yeongyu staff 4790 May 25 16:09 tui-install-prompts.ts +-rw-r--r--@ 1 yeongyu staff 4615 May 25 16:09 tui-installer.test.ts +-rw-r--r--@ 1 yeongyu staff 4943 May 25 16:09 tui-installer.ts +-rw-r--r--@ 1 yeongyu staff 1110 May 25 16:09 types.ts + +``` + +**Tool: bash** + +**Input:** +```json +{ + "command": "ls -la /Users/yeongyu/local-workspaces/omodex/packages/", + "description": "List packages directory" +} +``` + +**Output:** +``` +total 16 +drwxr-xr-x@ 26 yeongyu staff 832 May 25 16:09 . +drwxr-xr-x@ 36 yeongyu staff 1152 May 25 16:09 .. +drwxr-xr-x@ 6 yeongyu staff 192 May 25 16:09 agents-md-core +-rw-r--r--@ 1 yeongyu staff 5002 May 25 16:09 AGENTS.md +drwxr-xr-x@ 5 yeongyu staff 160 May 25 16:09 ast-grep-core +drwxr-xr-x@ 5 yeongyu staff 160 May 25 16:09 ast-grep-mcp +drwxr-xr-x@ 5 yeongyu staff 160 May 25 16:09 boulder-state +drwxr-xr-x@ 6 yeongyu staff 192 May 25 16:09 comment-checker-core +drwxr-xr-x@ 5 yeongyu staff 160 May 25 16:09 hashline-core +drwxr-xr-x@ 2 yeongyu staff 64 May 25 16:09 lsp-tools-mcp +drwxr-xr-x@ 5 yeongyu staff 160 May 25 16:09 model-core +drwxr-xr-x@ 4 yeongyu staff 128 May 25 16:09 oh-my-opencode-darwin-arm64 +drwxr-xr-x@ 4 yeongyu staff 128 May 25 16:09 oh-my-opencode-darwin-x64 +drwxr-xr-x@ 3 yeongyu staff 96 May 25 16:09 oh-my-opencode-darwin-x64-baseline +drwxr-xr-x@ 4 yeongyu staff 128 May 25 16:09 oh-my-opencode-linux-arm64 +drwxr-xr-x@ 4 yeongyu staff 128 May 25 16:09 oh-my-opencode-linux-arm64-musl +drwxr-xr-x@ 4 yeongyu staff 128 May 25 16:09 oh-my-opencode-linux-x64 +drwxr-xr-x@ 3 yeongyu staff 96 May 25 16:09 oh-my-opencode-linux-x64-baseline +drwxr-xr-x@ 4 yeongyu staff 128 May 25 16:09 oh-my-opencode-linux-x64-musl +drwxr-xr-x@ 3 yeongyu staff 96 May 25 16:09 oh-my-opencode-linux-x64-musl-baseline +drwxr-xr-x@ 4 yeongyu staff 128 May 25 16:09 oh-my-opencode-windows-x64 +drwxr-xr-x@ 3 yeongyu staff 96 May 25 16:09 oh-my-opencode-windows-x64-baseline +drwxr-xr-x@ 7 yeongyu staff 224 May 25 16:09 prompts-core +drwxr-xr-x@ 6 yeongyu staff 192 May 25 16:09 rules-engine +drwxr-xr-x@ 5 yeongyu staff 160 May 25 16:09 utils +drwxr-xr-x@ 29 yeongyu staff 928 May 25 16:09 web + +``` + +--- + +## User + +[search-mode] +MAXIMIZE SEARCH EFFORT. Launch multiple background agents IN PARALLEL: +- explore agents (codebase patterns, file structures, ast-grep) +- librarian agents (remote repos, official docs, GitHub examples) +Plus direct tools: Grep, ripgrep (rg), ast-grep (sg) +NEVER stop at first result - be exhaustive. + +--- + +그리고 그 여기 posthog 설정된거랑, posthog agents 이런거 찾아보고서 omo-codex 라고 새로 만들어서 얘도 사용량 비슷하게 같은 지표들 트래킹되게하게해주라 + +--- + +## Assistant (Sisyphus - Ultraworker · Opus 4.7 · 109.8s) + +_Thinking:_ + + The user wants me to expand the scope significantly—I need to not only port the codex-plugins with the installer flag, but also hunt down PostHog integration points and agent implementations in the codebase so I can build an "omo-codex" package with equivalent tracking capabilities. This is going to require launching multiple parallel search agents to cover ground quickly across the repository. + +병렬 탐색 폭격 발사합니다. 10개 백그라운드 에이전트 + 직접 도구 동시 실행. + +**Tool: task** + +**Input:** +```json +{ + "subagent_type": "explore", + "description": "Map codex-plugins repo", + "prompt": "[CONTEXT] I need a COMPLETE map of `/Users/yeongyu/local-workspaces/codex-plugins/`. This sibling repo is going to be merged into the current `omodex` repo as the Codex harness adapter. [GOAL] Understand its structure, dependencies, entry points, installer logic, and how it integrates with Codex. [DOWNSTREAM] I will create a new adapter package inside `packages/` named `omo-codex` and an installer flag `--codex` in the CLI. [REQUEST]\n- Full directory tree (3-4 levels deep) of `/Users/yeongyu/local-workspaces/codex-plugins/`\n- Identify package manager, build system, entry points, manifests\n- Read every `package.json` / `pyproject.toml` / `Cargo.toml` / installer script\n- Identify: where does Codex look for plugins? What format? What APIs?\n- Identify: any installer logic that writes to `~/.codex/`, `~/.config/codex/`, or similar\n- List every file under `src/` or equivalent with one-line description\n- Identify any PostHog/telemetry instrumentation in this repo\n- Identify any \"agent\" definitions (system prompts, model configs) similar to OmO's Sisyphus/Hephaestus/Oracle\n- Return concrete absolute file paths + brief description per file. Skip node_modules / .git.\n\nVERY THOROUGH. I need the complete picture.", + "run_in_background": true, + "load_skills": [] +} +``` + +**Output:** +``` +Background task launched. + +Background Task ID: bg_9524ffd0 +Description: Map codex-plugins repo +Agent: explore +Status: pending + +System notifies on completion. Use `background_output` with task_id="bg_9524ffd0" to check. + +Do NOT call background_output now. Wait for notification first. + + +session_id: ses_1a204b9ffffeWfGGl6W4wTmW5v +background_task_id: bg_9524ffd0 +subagent: explore + + +to continue: task(task_id="ses_1a204b9ffffeWfGGl6W4wTmW5v", load_skills=[], run_in_background=false, prompt="...") +``` + +**Tool: task** + +**Input:** +```json +{ + "subagent_type": "explore", + "description": "Find PostHog/telemetry in omodex", + "prompt": "[CONTEXT] Current repo is `/Users/yeongyu/local-workspaces/omodex/`. It's an OpenCode plugin called oh-my-openagent (npm name oh-my-opencode). I need to understand the COMPLETE PostHog / telemetry / analytics setup. The README mentions: \"Anonymous telemetry is enabled by default to track active installations (DAU/WAU/MAU). A single event is sent at most once per UTC day per machine using a hashed installation identifier... Disable with OMO_SEND_ANONYMOUS_TELEMETRY=0 or OMO_DISABLE_POSTHOG=1.\" [GOAL] I need to replicate this telemetry system for a sibling product called `omo-codex` so it tracks installations and usage with the same metrics. [DOWNSTREAM] Build a parallel telemetry pathway that distinguishes `omo` vs `omo-codex` installations in PostHog. [REQUEST]\n- Grep ENTIRE codebase for: posthog, PostHog, POSTHOG, OMO_SEND_ANONYMOUS_TELEMETRY, OMO_DISABLE_POSTHOG, telemetry, analytics, capture, identify, distinct_id\n- Return every file that touches telemetry with file path + 5-10 line excerpt\n- Identify: where is the PostHog API key stored? Hardcoded? Env var? Config?\n- Identify: what events are emitted? With what properties?\n- Identify: how is the hashed installation ID computed? Where is it persisted?\n- Identify: dedup mechanism (once per UTC day per machine) - how implemented?\n- Identify: any agent / hook / CLI command that calls PostHog\n- Identify: cli-installer telemetry flow (`cli-installer.telemetry.test.ts` exists at src/cli/)\n- Identify: any docs files mentioning telemetry, posthog, privacy\n- Return concrete file paths + descriptions. EXHAUSTIVE. I need every touchpoint.\n\nNOTE: skip node_modules, dist, .git, but include test files since they document expected behavior.", + "run_in_background": true, + "load_skills": [] +} +``` + +**Output:** +``` +Background task launched. + +Background Task ID: bg_d544d440 +Description: Find PostHog/telemetry in omodex +Agent: explore +Status: pending + +System notifies on completion. Use `background_output` with task_id="bg_d544d440" to check. + +Do NOT call background_output now. Wait for notification first. + + +session_id: ses_1a2049248ffeMyBe6HikRKvrBX +background_task_id: bg_d544d440 +subagent: explore + + +to continue: task(task_id="ses_1a2049248ffeMyBe6HikRKvrBX", load_skills=[], run_in_background=false, prompt="...") +``` + +**Tool: task** + +**Input:** +```json +{ + "subagent_type": "explore", + "description": "Map CLI installer + bin structure", + "prompt": "[CONTEXT] I'm at `/Users/yeongyu/local-workspaces/omodex/`. Need a deep understanding of how the CLI installer works. The current binary is `oh-my-opencode` (dual-published as `oh-my-openagent`). [GOAL] Add a new flag `--codex` to the installer that installs the Codex adapter instead of (or in addition to) the OpenCode plugin. Also need an installer entry named `omo` (the user explicitly mentioned 'omo' as the install command name). [DOWNSTREAM] Edit the CLI program / installer to support `--codex`, possibly add a new bin entry, document the workflow. [REQUEST]\n- Read `bin/` directory contents in full\n- Read `package.json` \"bin\" entries, \"scripts\", \"files\", \"publishConfig\"\n- Read `src/cli/cli-program.ts` in full\n- Read `src/cli/cli-installer.ts` in full\n- Read `src/cli/install.ts` and `src/cli/install-validators.ts` in full\n- Read `src/cli/tui-installer.ts` and `src/cli/tui-install-prompts.ts` in full\n- Read `src/cli/index.ts`\n- Read `postinstall.mjs` in full\n- Identify ALL CLI subcommands and their flags\n- Identify how the binary is built / compiled (bun build? bun compile?)\n- Identify where `~/.config/opencode/` writes happen\n- Identify any platform-detection / package.json bin name routing logic (oh-my-opencode vs oh-my-openagent shim)\n- Return everything with absolute paths + line numbers when referencing specific logic\n\nEXHAUSTIVE. I need the full picture of installer architecture before I add `--codex`.", + "run_in_background": true, + "load_skills": [] +} +``` + +**Output:** +``` +Background task launched. + +Background Task ID: bg_984b7a80 +Description: Map CLI installer + bin structure +Agent: explore +Status: pending + +System notifies on completion. Use `background_output` with task_id="bg_984b7a80" to check. + +Do NOT call background_output now. Wait for notification first. + + +session_id: ses_1a2046ba3ffeJHk1fVLKVR1Ud5 +background_task_id: bg_984b7a80 +subagent: explore + + +to continue: task(task_id="ses_1a2046ba3ffeJHk1fVLKVR1Ud5", load_skills=[], run_in_background=false, prompt="...") +``` + +**Tool: task** + +**Input:** +```json +{ + "subagent_type": "explore", + "description": "Map packages/ layering + how adapters are wired", + "prompt": "[CONTEXT] `/Users/yeongyu/local-workspaces/omodex/packages/` contains a workspace with Core packages (pure TS: utils, model-core, rules-engine, agents-md-core, ast-grep-core, comment-checker-core, boulder-state, prompts-core, hashline-core), MCP packages (ast-grep-mcp, lsp-tools-mcp), platform binaries (oh-my-opencode-*), and a web app. The ROADMAP says future Pi and Codex adapters will consume the same Core layer. [GOAL] Understand how packages are organized, how they declare dependencies, and where a new `omo-codex` adapter package should live. [DOWNSTREAM] I'll create `packages/omo-codex/` that follows the SAME conventions as existing core/adapter packages. [REQUEST]\n- Read `packages/AGENTS.md` in full\n- Read root `package.json` workspaces declaration\n- Read `bun.lock` workspace section (just the relevant chunk identifying which workspaces exist)\n- For each Core package (utils, model-core, rules-engine, agents-md-core, ast-grep-core, comment-checker-core, boulder-state, prompts-core, hashline-core): read its `package.json`, `tsconfig.json` (if exists), top-level `src/index.ts` or `src/` directory listing\n- For each MCP package (ast-grep-mcp, lsp-tools-mcp): same depth\n- Identify the conventions: naming, version, type:module, exports, devDependencies, scripts\n- Identify how `omo` (the OpenCode adapter) consumes these packages\n- Identify build outputs and what gets shipped to npm\n- Identify whether tsconfig path-mapping or workspace protocol (`workspace:*`) is used\n- Return absolute paths + concrete excerpts so I can faithfully mirror conventions\n\nEXHAUSTIVE. Convention compliance is non-negotiable in this codebase.", + "run_in_background": true, + "load_skills": [] +} +``` + +**Output:** +``` +Background task launched. + +Background Task ID: bg_f89ae6de +Description: Map packages/ layering + how adapters are wired +Agent: explore +Status: pending + +System notifies on completion. Use `background_output` with task_id="bg_f89ae6de" to check. + +Do NOT call background_output now. Wait for notification first. + + +session_id: ses_1a2044219ffeHRBnOldLHCF0lG +background_task_id: bg_f89ae6de +subagent: explore + + +to continue: task(task_id="ses_1a2044219ffeHRBnOldLHCF0lG", load_skills=[], run_in_background=false, prompt="...") +``` + +**Tool: task** + +**Input:** +```json +{ + "subagent_type": "explore", + "description": "Find agent definitions + categories + skills used by Sisyphus", + "prompt": "[CONTEXT] `/Users/yeongyu/local-workspaces/omodex/src/agents/` contains 11 agents (Sisyphus, Hephaestus, Oracle, Librarian, Explore, Atlas, Prometheus, Metis, Momus, Multimodal-Looker, Sisyphus-Junior). These are OpenCode-specific. For the Codex adapter we may need equivalent agent definitions adapted to the Codex harness. [GOAL] Catalog every agent definition file with its model defaults, system prompt source, and registration mechanism. [DOWNSTREAM] Determine which agents transfer to Codex 1:1, which need adaptation, and what naming convention the Codex variant should use. [REQUEST]\n- List every file under `src/agents/` (3 levels deep, with one-line descriptions)\n- For each agent: model defaults, prompt source (markdown file path or inline), permissions, tools whitelist\n- Identify the agent factory pattern (`createXxxAgent`)\n- Identify the registration mechanism in `src/plugin-handlers/` or `src/plugin/`\n- Identify `src/tools/delegate-task/constants.ts` DEFAULT_CATEGORIES + CATEGORY_MODEL_REQUIREMENTS\n- Identify how OpenCode-specific lifecycle hooks interact with agents (so I can understand which agent capabilities map to Codex's plugin surface)\n- Return absolute paths + concrete excerpts\n\nThis is for understanding what the Codex adapter must / can ship.", + "run_in_background": true, + "load_skills": [] +} +``` + +**Output:** +``` +Background task launched. + +Background Task ID: bg_4c8f991c +Description: Find agent definitions + categories + skills used by Sisyphus +Agent: explore +Status: pending + +System notifies on completion. Use `background_output` with task_id="bg_4c8f991c" to check. + +Do NOT call background_output now. Wait for notification first. + + +session_id: ses_1a2041ee8ffeCnbmy21p4Xqy5y +background_task_id: bg_4c8f991c +subagent: explore + + +to continue: task(task_id="ses_1a2041ee8ffeCnbmy21p4Xqy5y", load_skills=[], run_in_background=false, prompt="...") +``` + +**Tool: task** + +**Input:** +```json +{ + "subagent_type": "librarian", + "description": "Research Codex plugin/extension API", + "prompt": "[CONTEXT] I'm building a plugin/adapter for OpenAI Codex CLI (the official OpenAI Codex tool — possibly the Rust-based or TypeScript-based agent runtime). The repo is at https://github.com/openai/codex. There's also a sibling repo `oh-my-codex` and `codex-plugins` in this user's local workspace. [GOAL] Understand the OFFICIAL Codex extension/plugin API: how plugins register, what hooks they expose, what file format they use, where they're discovered. [DOWNSTREAM] I'll write a Codex adapter that integrates oh-my-openagent's core capabilities (telemetry, rules injection, AGENTS.md, etc.) into Codex. [REQUEST]\n- Search GitHub for `openai/codex` repo structure — focus on plugin / extension / hook / configuration APIs\n- Find official docs for Codex plugin format, lifecycle hooks, config file locations (e.g. `~/.codex/config.toml`, `~/.codex/agents/`, etc.)\n- Find example community plugins / extensions\n- Identify: does Codex use TOML, JSON, YAML, Markdown for config?\n- Identify: what's the equivalent of OpenCode's \"agent definition\" in Codex?\n- Identify: where does Codex look for \"rules\" / system prompts / AGENTS.md?\n- Identify: any TypeScript SDK or Rust plugin trait that third parties use\n- Return links + concise summaries + code snippets\n\nAlso do a broad web search for \"Codex plugin\", \"Codex extension\", \"Codex agent\", \"OpenAI Codex configuration AGENTS.md\" to find any community documentation. Skip beginner tutorials. I need API-level facts.", + "run_in_background": true, + "load_skills": [] +} +``` + +**Output:** +``` +Background task launched. + +Background Task ID: bg_0baa8bd3 +Description: Research Codex plugin/extension API +Agent: librarian +Status: pending + +System notifies on completion. Use `background_output` with task_id="bg_0baa8bd3" to check. + +Do NOT call background_output now. Wait for notification first. + + +session_id: ses_1a203f959ffeh4ZI3KfbfemChp +background_task_id: bg_0baa8bd3 +subagent: librarian + + +to continue: task(task_id="ses_1a203f959ffeh4ZI3KfbfemChp", load_skills=[], run_in_background=false, prompt="...") +``` + +**Tool: task** + +**Input:** +```json +{ + "subagent_type": "explore", + "description": "Look at sibling oh-my-codex repo for prior art", + "prompt": "[CONTEXT] There's a sibling directory `/Users/yeongyu/local-workspaces/oh-my-codex/` — likely an earlier or parallel attempt at the same Codex-adapter idea. Also `/Users/yeongyu/local-workspaces/codex-plugins/` exists (which we're consolidating into omodex). I need to understand if oh-my-codex has any useful prior art. [GOAL] Catalog what oh-my-codex contains so I can either reuse, learn from, or supersede it. [DOWNSTREAM] Decide whether the new `omo-codex` package borrows from oh-my-codex, codex-plugins, or both. [REQUEST]\n- Full directory tree of `/Users/yeongyu/local-workspaces/oh-my-codex/` (3-4 levels)\n- Read its README.md, package.json (or equivalent manifest), entry points\n- Identify what it does — installer? plugin? config injector? AGENTS.md generator?\n- Identify any overlap with the OpenCode plugin's capabilities\n- Identify telemetry / PostHog usage if present\n- Compare its approach vs codex-plugins approach in one paragraph\n- Return concrete absolute paths + a clear verdict: \"use this code\", \"use this idea\", or \"ignore\"\n\nSkip node_modules / dist / .git. EXHAUSTIVE.", + "run_in_background": true, + "load_skills": [] +} +``` + +**Output:** +``` +Background task launched. + +Background Task ID: bg_424806df +Description: Look at sibling oh-my-codex repo for prior art +Agent: explore +Status: pending + +System notifies on completion. Use `background_output` with task_id="bg_424806df" to check. + +Do NOT call background_output now. Wait for notification first. + + +session_id: ses_1a203dbfcffeOImnYDp4COf7Ky +background_task_id: bg_424806df +subagent: explore + + +to continue: task(task_id="ses_1a203dbfcffeOImnYDp4COf7Ky", load_skills=[], run_in_background=false, prompt="...") +``` + +**Tool: task** + +**Input:** +```json +{ + "subagent_type": "explore", + "description": "Find install docs + uninstall + privacy policy", + "prompt": "[CONTEXT] At `/Users/yeongyu/local-workspaces/omodex/`. I need to understand all the user-facing documentation around installation, telemetry, and privacy so a new `--codex` flag fits the existing UX. [GOAL] Compile every doc file that mentions installation, configuration, privacy, telemetry, posthog, or uninstall. [DOWNSTREAM] I'll need to update these docs to mention the `--codex` flag and the omo-codex telemetry stream. [REQUEST]\n- List every file under `docs/` (3 levels deep)\n- Read `docs/guide/installation.md` in full\n- Read `docs/legal/privacy-policy.md` in full\n- Read `docs/legal/terms-of-service.md` in full\n- Read `docs/guide/overview.md`\n- Read CHANGELOG.md (just the most recent 100 lines)\n- Grep across docs/ + README*.md for: codex, posthog, telemetry, privacy, install, --codex\n- Identify the section structure of installation.md so I can add Codex installation steps in the right place\n- Return absolute paths + concrete excerpts\n\nEXHAUSTIVE. I want to know every place that needs updating.", + "run_in_background": true, + "load_skills": [] +} +``` + +**Output:** +``` +Background task launched. + +Background Task ID: bg_f8d4250d +Description: Find install docs + uninstall + privacy policy +Agent: explore +Status: pending + +System notifies on completion. Use `background_output` with task_id="bg_f8d4250d" to check. + +Do NOT call background_output now. Wait for notification first. + + +session_id: ses_1a203c10fffemAkXIlkn5WGLL1 +background_task_id: bg_f8d4250d +subagent: explore + + +to continue: task(task_id="ses_1a203c10fffemAkXIlkn5WGLL1", load_skills=[], run_in_background=false, prompt="...") +``` + +**Tool: task** + +**Input:** +```json +{ + "subagent_type": "explore", + "description": "Find build script / publish workflow / platform binary system", + "prompt": "[CONTEXT] At `/Users/yeongyu/local-workspaces/omodex/`. The repo ships 11 platform binaries (oh-my-opencode-darwin-arm64, etc.) and dual-publishes to npm as `oh-my-opencode` + `oh-my-openagent`. The user wants a new install entry point named `omo` and a `--codex` flag. [GOAL] Understand the build + publish pipeline so I know whether `--codex` requires new binaries, a new npm package, a new bin shim, or all of the above. [DOWNSTREAM] Decide whether `omo-codex` is shipped as: (a) a flag inside the existing binary, (b) a separate binary, (c) a separate npm package, or (d) all three. [REQUEST]\n- List every file under `script/` (full depth)\n- Read `script/build.ts` (or whichever drives `bun run build`) in full\n- Read `script/publish.ts` or the publish entry\n- Read `.github/workflows/publish.yml` and `.github/workflows/ci.yml` in full\n- Read `.github/workflows/publish-platform.yml`\n- Read all files under `bin/` in full\n- Read the `postinstall.mjs` in full\n- Read `package.json` \"scripts\" section\n- Identify the dual-publish mechanism (oh-my-opencode + oh-my-openagent)\n- Identify the platform-binary selection logic at runtime\n- Identify how `bin/oh-my-opencode.js` (or equivalent) dispatches to the right native binary\n- Return absolute paths + concrete excerpts\n\nEXHAUSTIVE. The build system constraints will dictate my packaging strategy.", + "run_in_background": true, + "load_skills": [] +} +``` + +**Output:** +``` +Background task launched. + +Background Task ID: bg_58841818 +Description: Find build script / publish workflow / platform binary system +Agent: explore +Status: pending + +System notifies on completion. Use `background_output` with task_id="bg_58841818" to check. + +Do NOT call background_output now. Wait for notification first. + + +session_id: ses_1a2039dedffeJavOZIP82SzIKQ +background_task_id: bg_58841818 +subagent: explore + + +to continue: task(task_id="ses_1a2039dedffeJavOZIP82SzIKQ", load_skills=[], run_in_background=false, prompt="...") +``` + +**Tool: task** + +**Input:** +```json +{ + "subagent_type": "explore", + "description": "Find config schema + plugin entry + how it loads", + "prompt": "[CONTEXT] At `/Users/yeongyu/local-workspaces/omodex/`. Plugin entry is `src/index.ts` (18 lines, delegates to `src/testing/create-plugin-module.ts`). Config loads via `src/plugin-config.ts` (Zod v4). [GOAL] Understand the plugin module factory + config schema so I know how to write a parallel Codex adapter that reuses the same config layer. [DOWNSTREAM] The Codex adapter should reuse Core packages (rules-engine, agents-md-core, prompts-core, model-core, utils, etc.) and produce equivalent functionality through Codex's plugin API. [REQUEST]\n- Read `src/index.ts` in full\n- Read `src/testing/create-plugin-module.ts` in full\n- Read `src/plugin-config.ts` in full\n- List `src/config/schema/` (full depth) and read `src/config/schema/index.ts` if exists\n- Identify which schema fields are OpenCode-specific vs harness-agnostic\n- Identify the entry pattern: how does OpenCode discover and load this plugin?\n- Identify any existing \"harness abstraction\" or \"harness:\" field in config\n- Read `src/create-managers.ts`, `src/create-tools.ts`, `src/create-hooks.ts` (full)\n- Identify Core-vs-Adapter boundary: which managers/tools/hooks are pure logic vs OpenCode-specific\n- Return absolute paths + concrete excerpts\n\nEXHAUSTIVE.", + "run_in_background": true, + "load_skills": [] +} +``` + +**Output:** +``` +Background task launched. + +Background Task ID: bg_487b60c3 +Description: Find config schema + plugin entry + how it loads +Agent: explore +Status: pending + +System notifies on completion. Use `background_output` with task_id="bg_487b60c3" to check. + +Do NOT call background_output now. Wait for notification first. + + +session_id: ses_1a2037c49ffeD9SNh5Usb2WwBI +background_task_id: bg_487b60c3 +subagent: explore + + +to continue: task(task_id="ses_1a2037c49ffeD9SNh5Usb2WwBI", load_skills=[], run_in_background=false, prompt="...") +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins +directory + +.agents/ +.omo/ +notepad.md +plans/ +plugins/ +README.md +scripts/ + +(7 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/README.md" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/README.md +file + +1: # codex-plugins +2: +3: Local marketplace for the `omo` Codex plugin components ported from `../pi-extensions`. +4: +5: ## Plugin +6: +7: `omo` is one Codex plugin namespace with isolated internal components: +8: +9: - `components/comment-checker`: runs comment-checker automatically after successful `apply_patch` edits. +10: - `components/rules`: injects local project rule files into Codex context through lifecycle hooks. +11: - `components/lsp`: exposes Language Server Protocol diagnostics, navigation, symbols, and rename tools through MCP and post-edit hooks. +12: - `components/ultrawork`: injects the ultrawork orchestration directive when a user prompt contains `ultrawork` or `ulw`. +13: - `components/ultragoal`: durable repo-native multi-goal orchestration with embedded success criteria and observable evidence audit (`.omo/ultragoal/`). +14: +15: ## Local Install +16: +17: ```bash +18: codex plugin marketplace add /Users/yeongyu/local-workspaces/codex-plugins +19: node /Users/yeongyu/local-workspaces/codex-plugins/scripts/install-local.mjs /Users/yeongyu/local-workspaces/codex-plugins +20: ``` +21: +22: The installer builds `omo`, copies a clean versioned cache entry into `~/.codex/plugins/cache/code-yeongyu-codex-plugins/omo`, installs runtime dependencies in the cache, prunes stale split-plugin cache/config entries, and enables `[plugins."omo@code-yeongyu-codex-plugins"]` in `~/.codex/config.toml`. +23: It also enables both `plugins = true` and `plugin_hooks = true` under `[features]` so bundled hook files run. +24: +25: If your local Codex build exposes plugin install commands, you can use those instead. For older local builds, the installer replaces the manual copy fallback: +26: +27: ```text +28: ~/.codex/plugins/cache/code-yeongyu-codex-plugins/omo/0.1.0 +29: ``` + +(End of file - total 29 lines) + + +[Project README: /Users/yeongyu/local-workspaces/codex-plugins/README.md] +# codex-plugins + +Local marketplace for the `omo` Codex plugin components ported from `../pi-extensions`. + +## Plugin + +`omo` is one Codex plugin namespace with isolated internal components: + +- `components/comment-checker`: runs comment-checker automatically after successful `apply_patch` edits. +- `components/rules`: injects local project rule files into Codex context through lifecycle hooks. +- `components/lsp`: exposes Language Server Protocol diagnostics, navigation, symbols, and rename tools through MCP and post-edit hooks. +- `components/ultrawork`: injects the ultrawork orchestration directive when a user prompt contains `ultrawork` or `ulw`. +- `components/ultragoal`: durable repo-native multi-goal orchestration with embedded success criteria and observable evidence audit (`.omo/ultragoal/`). + +## Local Install + +```bash +codex plugin marketplace add /Users/yeongyu/local-workspaces/codex-plugins +node /Users/yeongyu/local-workspaces/codex-plugins/scripts/install-local.mjs /Users/yeongyu/local-workspaces/codex-plugins +``` + +The installer builds `omo`, copies a clean versioned cache entry into `~/.codex/plugins/cache/code-yeongyu-codex-plugins/omo`, installs runtime dependencies in the cache, prunes stale split-plugin cache/config entries, and enables `[plugins."omo@code-yeongyu-codex-plugins"]` in `~/.codex/config.toml`. +It also enables both `plugins = true` and `plugin_hooks = true` under `[features]` so bundled hook files run. + +If your local Codex build exposes plugin install commands, you can use those instead. For older local builds, the installer replaces the manual copy fallback: + +```text +~/.codex/plugins/cache/code-yeongyu-codex-plugins/omo/0.1.0 +``` + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/omodex/src/cli/cli-installer.ts" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/omodex/src/cli/cli-installer.ts +file + +1: import color from "picocolors" +2: import { PLUGIN_NAME, PUBLISHED_PACKAGE_NAME } from "../shared" +3: import type { InstallArgs } from "./types" +4: import { +5: addPluginToOpenCodeConfig, +6: detectCurrentConfig, +7: getOpenCodeVersion, +8: isOpenCodeInstalled, +9: writeOmoConfig, +10: } from "./config-manager" +11: import { +12: SYMBOLS, +13: argsToConfig, +14: detectedToInitialValues, +15: formatConfigSummary, +16: printBox, +17: printError, +18: printHeader, +19: printInfo, +20: printStep, +21: printSuccess, +22: printWarning, +23: validateNonTuiArgs, +24: } from "./install-validators" +25: import { getUnsupportedOpenCodeVersionMessage } from "./minimum-opencode-version" +26: +27: export async function runCliInstaller(args: InstallArgs, version: string): Promise { +28: const validation = validateNonTuiArgs(args) +29: if (!validation.valid) { +30: printHeader(false) +31: printError("Validation failed:") +32: for (const err of validation.errors) { +33: console.log(` ${SYMBOLS.bullet} ${err}`) +34: } +35: console.log() +36: printInfo( +37: `Usage: bunx ${PUBLISHED_PACKAGE_NAME} install --no-tui --claude= --gemini= --copilot=`, +38: ) +39: console.log() +40: return 1 +41: } +42: +43: const detected = detectCurrentConfig() +44: const isUpdate = detected.isInstalled +45: +46: printHeader(isUpdate) +47: +48: const totalSteps = 4 +49: let step = 1 +50: +51: printStep(step++, totalSteps, "Checking OpenCode installation...") +52: const installed = await isOpenCodeInstalled() +53: const openCodeVersion = await getOpenCodeVersion() +54: if (!installed) { +55: printWarning( +56: "OpenCode binary not found. Plugin will be configured, but you'll need to install OpenCode to use it.", +57: ) +58: printInfo("Visit https://opencode.ai/docs for installation instructions") +59: } else { +60: printSuccess(`OpenCode ${openCodeVersion ?? ""} detected`) +61: +62: const unsupportedVersionMessage = getUnsupportedOpenCodeVersionMessage(openCodeVersion) +63: if (unsupportedVersionMessage) { +64: printWarning(unsupportedVersionMessage) +65: return 1 +66: } +67: } +68: +69: if (isUpdate) { +70: const initial = detectedToInitialValues(detected) +71: printInfo(`Current config: Claude=${initial.claude}, Gemini=${initial.gemini}`) +72: } +73: +74: const config = argsToConfig(args) +75: +76: printStep(step++, totalSteps, `Adding ${PLUGIN_NAME} plugin...`) +77: const pluginResult = await addPluginToOpenCodeConfig(version) +78: if (!pluginResult.success) { +79: printError(`Failed: ${pluginResult.error}`) +80: return 1 +81: } +82: printSuccess( +83: `Plugin ${isUpdate ? "verified" : "added"} ${SYMBOLS.arrow} ${color.dim(pluginResult.configPath)}`, +84: ) +85: +86: printStep(step++, totalSteps, `Writing ${PLUGIN_NAME} configuration...`) +87: const omoResult = writeOmoConfig(config) +88: if (!omoResult.success) { +89: printError(`Failed: ${omoResult.error}`) +90: return 1 +91: } +92: printSuccess(`Config written ${SYMBOLS.arrow} ${color.dim(omoResult.configPath)}`) +93: +94: printBox(formatConfigSummary(config), isUpdate ? "Updated Configuration" : "Installation Complete") +95: +96: if (!config.hasClaude) { +97: printInfo( +98: "Note: Sisyphus agent performs best with Claude Opus 4.5+. " + +99: "Other models work but may have reduced orchestration quality.", +100: ) +101: } +102: +103: if ( +104: !config.hasClaude && +105: !config.hasOpenAI && +106: !config.hasGemini && +107: !config.hasCopilot && +108: !config.hasOpencodeZen && +109: !config.hasVercelAiGateway +110: ) { +111: printWarning("No model providers configured. Using opencode/big-pickle as fallback.") +112: } +113: +114: console.log(`${SYMBOLS.star} ${color.bold(color.green(isUpdate ? "Configuration updated!" : "Installation complete!"))}`) +115: console.log(` Run ${color.cyan("opencode")} to start!`) +116: console.log() +117: +118: printInfo( +119: "Anonymous telemetry is enabled by default. Disable it with OMO_SEND_ANONYMOUS_TELEMETRY=0 or OMO_DISABLE_POSTHOG=1.", +120: ) +121: printInfo("Docs: docs/legal/privacy-policy.md and docs/legal/terms-of-service.md") +122: console.log() +123: +124: printBox( +125: `${color.bold("Pro Tip:")} Include ${color.cyan("ultrawork")} (or ${color.cyan("ulw")}) in your prompt.\n` + +126: `All features work like magic-parallel agents, background tasks,\n` + +127: `deep exploration, and relentless execution until completion.`, +128: "The Magic Word", +129: ) +130: +131: console.log(`${SYMBOLS.star} ${color.yellow("If you found this helpful, consider starring the repo!")}`) +132: console.log( +133: ` ${color.dim("gh api --silent --method PUT /user/starred/code-yeongyu/oh-my-openagent >/dev/null 2>&1 || true")}`, +134: ) +135: console.log() +136: console.log(color.dim("oMoMoMoMo... Enjoy!")) +137: console.log() +138: +139: if ((config.hasClaude || config.hasGemini || config.hasCopilot) && !args.skipAuth) { +140: printBox( +141: `Run ${color.cyan("opencode auth login")} and select your provider:\n` + +142: (config.hasClaude ? ` ${SYMBOLS.bullet} Anthropic ${color.gray("→ Claude Pro/Max")}\n` : "") + +143: (config.hasGemini ? ` ${SYMBOLS.bullet} Google ${color.gray("→ Gemini")}\n` : "") + +144: (config.hasCopilot ? ` ${SYMBOLS.bullet} GitHub ${color.gray("→ Copilot")}` : ""), +145: "Authenticate Your Providers", +146: ) +147: } +148: +149: return 0 +150: } + +(End of file - total 150 lines) + + + +Instructions from: /Users/yeongyu/local-workspaces/omodex/src/cli/AGENTS.md +# src/cli/ — CLI: install, run, doctor, mcp-oauth, refresh-model-capabilities, get-local-version, version, boulder + +**Generated:** 2026-05-20 + +## OVERVIEW + +Commander.js CLI with 8 commands. Entry: `index.ts` → `runCli()` in `cli-program.ts`. + +## COMMANDS + +| Command | Purpose | Key Logic | +|---------|---------|-----------| +| `install` | Interactive/non-interactive setup | Provider selection → config gen → plugin registration | +| `run ` | Non-interactive session launcher | Agent resolution (flag → env → config → Sisyphus) | +| `doctor` | 4-category health checks | System, Config, Tools, Models | +| `get-local-version` | Version detection | Installed vs npm latest | +| `version` | Print plugin version | Trivial 2-line subcommand | +| `mcp-oauth` | OAuth token management | login (PKCE), logout, status | +| `refresh-model-capabilities` | Refresh models.dev cache | Model capabilities refresh | +| `boulder` | Boulder state inspector | Format work-state + tasks from `.omo/boulder-state/` | + +## STRUCTURE + +``` +cli/ +├── index.ts # Entry point → runCli() +├── cli-program.ts # Commander.js program (8 commands) +├── install.ts # Routes to TUI or CLI installer +├── cli-installer.ts # Non-interactive (console output) +├── tui-installer.ts # Interactive (@clack/prompts) +├── model-fallback.ts # Model config gen by provider availability +├── provider-availability.ts # Provider detection +├── fallback-chain-resolution.ts # Fallback chain logic +├── config-manager/ # 20 config utilities +│ ├── plugin registration, provider config +│ ├── JSONC operations, auth plugins +│ └── npm dist-tags, binary detection +├── doctor/ +│ ├── runner.ts # Parallel check execution +│ ├── formatter.ts # Output formatting +│ └── checks/ # 15 check files in 4 categories +│ ├── system.ts # Binary, plugin, version +│ ├── config.ts # JSONC validity, Zod schema +│ ├── tools.ts # AST-Grep, LSP, GH CLI, MCP +│ └── model-resolution.ts # Cache, resolution, overrides (6 sub-files) +├── run/ # Session launcher +│ ├── runner.ts # Main orchestration +│ ├── agent-resolver.ts # Flag → env → config → Sisyphus +│ ├── session-resolver.ts # Create/resume sessions +│ ├── event-handlers.ts # Event processing +│ └── poll-for-completion.ts # Wait for todos/background tasks +└── mcp-oauth/ # OAuth token management +``` + +## MODEL FALLBACK SYSTEM + +No single global priority. CLI install-time resolution uses per-agent fallback chains from `model-fallback-requirements.ts`. + +Common patterns: Claude/OpenAI/Gemini are preferred when an agent chain includes them, `librarian` prefers ZAI, `sisyphus` falls back through Kimi then GLM-5, and `hephaestus` requires OpenAI-compatible providers. + +## DOCTOR CHECKS + +| Category | Validates | +|----------|-----------| +| **System** | Binary found, version >=1.0.150, plugin registered, version match | +| **Config** | JSONC validity, Zod schema, model override syntax | +| **Tools** | AST-Grep, comment-checker, LSP servers, GH CLI, MCP servers | +| **Models** | Cache exists, model resolution, agent/category overrides, availability | + +## HOW TO ADD A DOCTOR CHECK + +1. Create `src/cli/doctor/checks/{name}.ts` +2. Export check function matching `DoctorCheck` interface +3. Register in `checks/index.ts` + + +Instructions from: /Users/yeongyu/local-workspaces/omodex/src/AGENTS.md +# src/ — Plugin Source + +**Generated:** 2026-05-20 + +## OVERVIEW + +Entry `index.ts` orchestrates a 7-step initialization. Total: ~1314 source files + 730 tests across the directories below. Cross-cutting helpers live in `shared/`; module boundaries are established by 120 barrel `index.ts` files. + +## KEY FILES + +| File | Purpose | +|------|---------| +| `index.ts` | Plugin entry; default-exports `pluginModule: PluginModule` with `{ id, server }` | +| `plugin-config.ts` | JSONC parse, multi-level merge (user + walked project), Zod v4 validation, migration | +| `plugin-state.ts` | `createModelCacheState()` — model resolution cache shared across handlers | +| `plugin-interface.ts` | 11 OpenCode hook handlers wired into `Hooks` (the 12th + 13th — `experimental.session.compacting` + `experimental.compaction.autocontinue` — are wired in `src/testing/create-plugin-module.ts`) | +| `create-managers.ts` | TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler | +| `create-tools.ts` | SkillContext + AvailableCategories + ToolRegistry composition | +| `create-hooks.ts` | 5-tier composition: `createCoreHooks() + createContinuationHooks() + createSkillHooks()` | +| `create-runtime-tmux-config.ts` | `isTmuxIntegrationEnabled()` + `createRuntimeTmuxConfig()` | + +## INITIALIZATION (7 STEPS) + +``` +serverPlugin(input, options) + 1. installAgentSortShim() # patches Array.prototype.{toSorted,sort} for canonical agent ordering + 2. initConfigContext() # detects opencode-vs-openagent config layout + 3. detectExternalSkillPlugin() # warn if conflicting plugin loaded + 4. injectServerAuthIntoClient() # wire auth headers into shared SDK client + 5. loadPluginConfig() # walk project + user JSONC → Zod safeParse → migrate + 6a. initializeOpenClaw() # if openclaw config present (start reply-listener daemon) + 6b. checkTeamModeDependencies() # if team_mode.enabled (verify git, tmux, ensure ~/.omo/teams/) + 7. createManagers/Tools/Hooks/PluginInterface +``` + +## CONFIG LOADING (Phase pipeline) + +``` +loadPluginConfig(directory, ctx) + 1. User: ~/.config/opencode/oh-my-openagent.jsonc (legacy: oh-my-opencode.jsonc) + 2. Walked configs: /.opencode/oh-my-openagent.jsonc + 3. mergeConfigs(user, walked) + - agents/categories/claude_code: deepMerge (recursive, prototype-pollution safe) + - disabled_*: Set union + - mcp_env_allowlist: user-only (security) + - others: override replaces + 4. Zod safeParse → defaults for omitted fields + 5. migrateConfigFile() → idempotent via _migrations tracking + timestamped backups +``` + +## HOOK COMPOSITION (5-tier) + +Counts verified from each composer's return object. Numbers in brackets show counts when `team_mode.enabled`. + +``` +createHooks() + ├─→ createCoreHooks() + │ ├─ createSessionHooks() # 24: contextWindowMonitor, preemptiveCompaction, sessionRecovery, + │ │ sessionNotification, thinkMode, modelFallback, + │ │ anthropicContextWindowLimitRecovery, autoUpdateChecker, + │ │ agentUsageReminder, nonInteractiveEnv, interactiveBashSession, + │ │ ralphLoop, editErrorRecovery, delegateTaskRetry, startWork, + │ │ prometheusMdOnly, sisyphusJuniorNotepad, noSisyphusGpt, + │ │ noHephaestusNonGpt, questionLabelTruncator, taskResumeInfo, + │ │ anthropicEffort, runtimeFallback, legacyPluginToast + │ ├─ createToolGuardHooks() # 16 [+1 with team-mode]: commentChecker, toolOutputTruncator, + │ │ directoryAgentsInjector, directoryReadmeInjector, + │ │ emptyTaskResponseDetector, rulesInjector, tasksTodowriteDisabler, + │ │ writeExistingFileGuard, bashFileReadGuard, hashlineReadEnhancer, + │ │ jsonErrorRecovery, readImageResizer, todoDescriptionOverride, + │ │ webfetchRedirectGuard, fsyncSkipWarning [+ teamToolGating] + │ └─ createTransformHooks() # 5 [+2 with team-mode]: claudeCodeHooks, keywordDetector, + │ contextInjectorMessagesTransform, thinkingBlockValidator, + │ toolPairValidator [+ teamModeStatusInjector, teamMailboxInjector] + ├─→ createContinuationHooks() # 7: stopContinuationGuard, compactionContextInjector, + │ compactionTodoPreserver, todoContinuationEnforcer (boulder), + │ unstableAgentBabysitter, backgroundNotificationHook, atlasHook + └─→ createSkillHooks() # 2: categorySkillReminder, autoSlashCommand + + Direct event handlers (src/plugin/event.ts, when team_mode.enabled): +4 + team-idle-wake-hint, team-lead-orphan-handler, + team-member-error-handler, team-member-status-handler +``` + +Total: 54 base, 61 with team-mode. Each tier produces an object whose values are `(input, output) => void` handlers; the matching OpenCode handler invokes them in registration order via `safeHook()` wrappers. + +## SUBSYSTEM INVENTORY + +| Subdir | Files (.ts) | LOC | Purpose | Has AGENTS.md | +|--------|-------------|-----|---------|---------------| +| `agents/` | 104 | ~20k | 11 agent factories + dynamic prompt builder | yes (+ atlas, hephaestus, prometheus, sisyphus, sisyphus-junior, builtin-agents) | +| `hooks/` | 596 | ~78k | ~52 lifecycle hooks across 57 dirs | yes (+ atlas, anthropic-context-window-limit-recovery, auto-update-checker, claude-code-hooks, comment-checker, compaction-context-injector, keyword-detector, ralph-loop, rules-injector, runtime-fallback, session-recovery, todo-continuation-enforcer) | +| `tools/` | 317 | ~45k | 13 native tool dirs (+1 shared utilities dir); LSP + AST-grep moved to built-in MCPs | yes (+ background-task, call-omo-agent, delegate-task, hashline-edit, look-at, skill) | +| `features/` | 404 | ~71k | 20 feature modules (team-mode, background-agent, boulder-state, etc.) | yes (+ 11 sub-AGENTS.md including builtin-skills, team-mode, background-agent, claude-code-*) | +| `shared/` | 297 | ~33k | Cross-cutting utilities (179 non-test), barrel-exported | yes | +| `cli/` | 158 | ~18k | Commander.js CLI: install, run, doctor, mcp-oauth, boulder | yes (+ config-manager, doctor, run) | +| `plugin/` | 58 | ~12k | 10 OpenCode hook handlers + hook composition | yes | +| `config/` | 41 | ~2k | 30 Zod v4 schema files | yes | +| `plugin-handlers/` | 27 | ~6k | 6-phase config loading pipeline | yes | +| `openclaw/` | 26 | ~3k | Bidirectional Discord/Telegram/HTTP integration | yes | +| `__tests__/` | 22 | ~300 | Plugin-level integration tests + perf fixtures | — | +| `mcp/` | 8 | ~260 | 5 built-in MCPs (3 remote + local stdio lsp + ast_grep) | yes | +| `testing/` | 3 | ~225 | Test utilities | — | + +## NOTES + +- `plugin-interface.ts` is the **only** layer that talks to OpenCode's `Plugin` API. Every other file goes through it. +- Reach for `shared/` before adding helpers anywhere else — duplicate utilities WILL be flagged in review. +- Path aliases are forbidden. Use relative imports within a module, barrel imports across modules. + + + +[Rule: ../../.omo/rules/file-size-architectural-smell.md] +[Match: glob: **/*.ts] + +# 250 PURE LOC PER FILE. HARD CEILING. NO EXCEPTIONS. + +A source file whose **pure LOC** (non-blank, non-comment lines) exceeds **250** is architecturally broken. **NOT a style preference. NOT a soft suggestion. A defect.** + +A file past this line is telling you, loudly: + +- The module is doing more than one thing. +- Multiple cohesive units got merged "to save a file". +- Re-exports, barrels, and orchestrators got fused into pure-logic units. +- Every future reader pays a tax to find what they need. + +## REQUIRED BEHAVIOR + +**Creating a file that will exceed 250 pure LOC.** STOP. Split it before the first commit. Carve by responsibility (single-responsibility principle), one cohesive unit per file. Use a barrel (`index.ts`, `mod.rs`, `__init__.py`) for re-exports ONLY. **Never** for logic. + +**Editing a file that already exceeds 250 pure LOC and your edit adds lines.** STOP. Refactor the unit you are touching into its own file BEFORE adding the new lines. The split is part of THIS task, not a follow-up someone will never do. + +**Reading a file that exceeds 250 pure LOC while implementing a feature.** Surface the smell explicitly in your reply, propose a concrete split (which functions go where, in 1-2 lines each), and ask the user whether to split now or carry the smell into the feature work. Do not silently keep going. + +## FORBIDDEN ESCAPES + +- Counting comments and blank lines toward the budget. **Pure LOC means code lines.** Period. +- Splitting by token count (`foo-1.ts`, `foo-2.ts`, `module-part-A`). **REJECT.** Split by what each file DOES. Name each file after the concept it owns. +- Catch-all dump files: `utils.ts`, `helpers.ts`, `service.ts`, `common.py`, `lib.rs` as a logic dump. **REJECT.** These just relocate the smell. +- "It is generated, so it is fine." Only true if the file lives in `dist/` / `target/` / `__generated__/` / wherever the build authoritatively rewrites. Hand-edited "I will regenerate it later" files do NOT qualify. +- "It is a test file with many cases." Split by SUT or by behavior cluster. One file per cohesive `describe` group. +- "230 pure LOC, close enough." A 230-LOC file about to grow is already over the line. Split now. **Do not race to the ceiling.** + +## MEASURING PURE LOC + +```bash +# Quick (line-comments only) +awk '!/^[[:space:]]*$/ && !/^[[:space:]]*(\/\/|#|--)/' | wc -l + +# Authoritative (handles block comments correctly) +cloc --by-file # the "code" column is the number that matters +``` + +## WHY THE CEILING IS 250 AND NOT 500 OR 1000 + +At 250 pure LOC, a file still fits in one screen on a 32-inch monitor with a 14pt font. A reviewer can hold the whole thing in working memory and spot a cross-cutting bug. At 500 LOC they cannot. At 1000 LOC they stop trying. The number is not arbitrary. It is the cognitive ceiling of a single human reviewer who has not memorized the file. + +Beat the ceiling. The codebase, every reviewer, and the next maintainer will thank you. + + +[Rule: ../../.omo/rules/typescript-programmer.md] +[Match: glob: **/*.ts] + +# TypeScript File Discipline + +Before you write or modify TypeScript in this turn, **load the `programming` skill via the `skill` tool**, then **MUST read `references/typescript/README.md`** plus every reference file the README tells you to load on demand. + +The `programming` skill carries the shared philosophy (type system as proof system, parse-don't-validate at boundaries, one name = one concept, exhaustive variant matching, trust framework guarantees) AND the 250 pure LOC per-file ceiling AND the mandatory post-write architectural review loop. + +The TypeScript reference carries the binding stack and bans for every `.ts` / `.tsx` / `.mts` / `.cts` file you touch: Bun runtime + pnpm + Biome, tsconfig `strict` + `noUncheckedIndexedAccess` + `exactOptionalPropertyTypes` + `verbatimModuleSyntax`, branded types, `readonly` by default, exhaustive `switch` with `assertNever`, discriminated unions, Zod at boundaries, typed errors, Hono + Drizzle + `ky` (NEVER bare `fetch` in prod) + vitest defaults, and the absolute bans on `any`, `enum`, `as` (except `as const`, `satisfies`), `!`, `@ts-ignore`, `@ts-expect-error`. + +**ALSO read the reference files inside `references/typescript/` before writing non-trivial code.** The references are where the WHY and the per-pattern recipes live. Skipping them is the difference between code that ships and code that gets rewritten in review. + +**After writing, run the mandatory post-write loop in the `programming` SKILL.md**: measure pure LOC on every changed file, refactor immediately if any file exceeds 250 pure LOC, then answer the 7-question architectural self-review out loud before declaring done. + +If the skill is already loaded this session, do not reload it - but apply every convention to every line you write here. + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/omodex/src/cli/cli-program.ts" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/omodex/src/cli/cli-program.ts +file + +1: import { Command } from "commander" +2: import { install } from "./install" +3: import { run } from "./run" +4: import { getLocalVersion } from "./get-local-version" +5: import { doctor } from "./doctor" +6: import { refreshModelCapabilities } from "./refresh-model-capabilities" +7: import { createMcpOAuthCommand } from "./mcp-oauth" +8: import { boulder } from "./boulder" +9: import type { InstallArgs } from "./types" +10: import type { RunOptions } from "./run" +11: import type { GetLocalVersionOptions } from "./get-local-version/types" +12: import type { DoctorOptions } from "./doctor" +13: import packageJson from "../../package.json" with { type: "json" } +14: +15: const VERSION = packageJson.version +16: +17: const program = new Command() +18: +19: program +20: .name("oh-my-opencode") +21: .description("The ultimate OpenCode plugin - multi-model orchestration, LSP tools, and more") +22: .version(VERSION, "-v, --version", "Show version number") +23: .helpOption("-h, --help", "Display help for command") +24: .enablePositionalOptions() +25: +26: program +27: .command("install") +28: .alias("setup") +29: .description("Install and configure oh-my-opencode with interactive setup") +30: .option("--no-tui", "Run in non-interactive mode (requires all options)") +31: .option("--claude ", "Claude subscription: no, yes, max20") +32: .option("--openai ", "OpenAI/ChatGPT subscription: no, yes (default: no)") +33: .option("--gemini ", "Gemini integration: no, yes") +34: .option("--copilot ", "GitHub Copilot subscription: no, yes") +35: .option("--opencode-zen ", "OpenCode Zen access: no, yes (default: no)") +36: .option("--zai-coding-plan ", "Z.ai Coding Plan subscription: no, yes (default: no)") +37: .option("--kimi-for-coding ", "Kimi For Coding subscription: no, yes (default: no)") +38: .option("--opencode-go ", "OpenCode Go subscription: no, yes (default: no)") +39: .option("--vercel-ai-gateway ", "Vercel AI Gateway: no, yes (default: no)") +40: .option("--skip-auth", "Skip authentication setup hints") +41: .addHelpText("after", ` +42: Examples: +43: $ bunx oh-my-opencode install +44: $ bunx oh-my-opencode install --no-tui --claude=max20 --openai=yes --gemini=yes --copilot=no +45: $ bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=yes --opencode-zen=yes +46: +47: Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi > Vercel): +48: Claude Native anthropic/ models (Opus, Sonnet, Haiku) +49: OpenAI Native openai/ models (GPT-5.4 for Oracle) +50: Gemini Native google/ models (Gemini 3.1 Pro, Flash) +51: Copilot github-copilot/ models (fallback) +52: OpenCode Zen opencode/ models (opencode/claude-opus-4-7, etc.) +53: Z.ai zai-coding-plan/glm-5 (visual-engineering fallback) +54: Kimi kimi-for-coding/k2p5 (Sisyphus/Prometheus fallback) +55: Vercel vercel/ models (universal proxy, always last fallback) +56: `) +57: .action(async (options) => { +58: const args: InstallArgs = { +59: tui: options.tui !== false, +60: claude: options.claude, +61: openai: options.openai, +62: gemini: options.gemini, +63: copilot: options.copilot, +64: opencodeZen: options.opencodeZen, +65: zaiCodingPlan: options.zaiCodingPlan, +66: kimiForCoding: options.kimiForCoding, +67: opencodeGo: options.opencodeGo, +68: vercelAiGateway: options.vercelAiGateway, +69: skipAuth: options.skipAuth ?? false, +70: } +71: const exitCode = await install(args) +72: process.exit(exitCode) +73: }) +74: +75: program +76: .command("run ") +77: .allowUnknownOption() +78: .passThroughOptions() +79: .description("Run opencode with todo/background task completion enforcement") +80: .option("-a, --agent ", "Agent to use (default: from CLI/env/config, fallback: Sisyphus)") +81: .option("-m, --model ", "Model override (e.g., anthropic/claude-sonnet-4)") +82: .option("-d, --directory ", "Working directory") +83: .option("-p, --port ", "Server port (attaches if port already in use)", parseInt) +84: .option("--attach ", "Attach to existing opencode server URL") +85: .option("--on-complete ", "Shell command to run after completion") +86: .option("--json", "Output structured JSON result to stdout") +87: .option("--no-timestamp", "Disable timestamp prefix in run output") +88: .option("--verbose", "Show full event stream (default: messages/tools only)") +89: .option("--session-id ", "Resume existing session instead of creating new one") +90: .addHelpText("after", ` +91: Examples: +92: $ bunx oh-my-opencode run "Fix the bug in index.ts" +93: $ bunx oh-my-opencode run --agent Sisyphus "Implement feature X" +94: $ bunx oh-my-opencode run --port 4321 "Fix the bug" +95: $ bunx oh-my-opencode run --attach http://127.0.0.1:4321 "Fix the bug" +96: $ bunx oh-my-opencode run --json "Fix the bug" | jq .sessionId +97: $ bunx oh-my-opencode run --on-complete "notify-send Done" "Fix the bug" +98: $ bunx oh-my-opencode run --session-id ses_abc123 "Continue the work" +99: $ bunx oh-my-opencode run --model anthropic/claude-sonnet-4 "Fix the bug" +100: $ bunx oh-my-opencode run --agent Sisyphus --model openai/gpt-5.5 "Implement feature X" +101: +102: Agent resolution order: +103: 1) --agent flag +104: 2) OPENCODE_DEFAULT_AGENT +105: 3) oh-my-opencode.json "default_run_agent" +106: 4) Sisyphus (fallback) +107: +108: Available core agents: +109: Sisyphus, Hephaestus, Prometheus, Atlas +110: +111: Unlike 'opencode run', this command waits until: +112: - All todos are completed or cancelled +113: - All child sessions (background tasks) are idle +114: `) +115: .action(async (message: string, options) => { +116: if (options.port && options.attach) { +117: console.error("Error: --port and --attach are mutually exclusive") +118: process.exit(1) +119: } +120: const runOptions: RunOptions = { +121: message, +122: agent: options.agent, +123: model: options.model, +124: directory: options.directory, +125: port: options.port, +126: attach: options.attach, +127: onComplete: options.onComplete, +128: json: options.json ?? false, +129: timestamp: options.timestamp ?? true, +130: verbose: options.verbose ?? false, +131: sessionId: options.sessionId, +132: } +133: const exitCode = await run(runOptions) +134: process.exit(exitCode) +135: }) +136: +137: program +138: .command("get-local-version") +139: .description("Show current installed version and check for updates") +140: .option("-d, --directory ", "Working directory to check config from") +141: .option("--json", "Output in JSON format for scripting") +142: .addHelpText("after", ` +143: Examples: +144: $ bunx oh-my-opencode get-local-version +145: $ bunx oh-my-opencode get-local-version --json +146: $ bunx oh-my-opencode get-local-version --directory /path/to/project +147: +148: This command shows: +149: - Current installed version +150: - Latest available version on npm +151: - Whether you're up to date +152: - Special modes (local dev, pinned version) +153: `) +154: .action(async (options) => { +155: const versionOptions: GetLocalVersionOptions = { +156: directory: options.directory, +157: json: options.json ?? false, +158: } +159: const exitCode = await getLocalVersion(versionOptions) +160: process.exit(exitCode) +161: }) +162: +163: program +164: .command("doctor") +165: .description("Check oh-my-opencode installation health and diagnose issues") +166: .option("--status", "Show compact system dashboard") +167: .option("--verbose", "Show detailed diagnostic information") +168: .option("--json", "Output results in JSON format") +169: .addHelpText("after", ` +170: Examples: +171: $ bunx oh-my-opencode doctor # Show problems only +172: $ bunx oh-my-opencode doctor --status # Compact dashboard +173: $ bunx oh-my-opencode doctor --verbose # Deep diagnostics +174: $ bunx oh-my-opencode doctor --json # JSON output +175: `) +176: .action(async (options) => { +177: const mode = options.status ? "status" : options.verbose ? "verbose" : "default" +178: const doctorOptions: DoctorOptions = { +179: mode, +180: json: options.json ?? false, +181: } +182: const exitCode = await doctor(doctorOptions) +183: process.exit(exitCode) +184: }) +185: +186: program +187: .command("refresh-model-capabilities") +188: .description("Refresh the cached models.dev-based model capabilities snapshot") +189: .option("-d, --directory ", "Working directory to read oh-my-opencode config from") +190: .option("--source-url ", "Override the models.dev source URL") +191: .option("--json", "Output refresh summary as JSON") +192: .action(async (options) => { +193: const exitCode = await refreshModelCapabilities({ +194: directory: options.directory, +195: sourceUrl: options.sourceUrl, +196: json: options.json ?? false, +197: }) +198: process.exit(exitCode) +199: }) +200: +201: program +202: .command("version") +203: .description("Show version information") +204: .action(() => { +205: console.log(`oh-my-opencode v${VERSION}`) +206: }) +207: +208: program +209: .command("boulder") +210: .description("Show boulder progress, elapsed time, and per-task statistics") +211: .option("-d, --directory ", "Working directory") +212: .option("-w, --work-id ", "Filter to a specific work") +213: .option("--json", "Output as JSON") +214: .action(async (options) => { +215: const exitCode = await boulder({ +216: directory: options.directory, +217: workId: options.workId, +218: json: options.json ?? false, +219: }) +220: process.exit(exitCode) +221: }) +222: +223: program.addCommand(createMcpOAuthCommand()) +224: +225: export function runCli(): void { +226: program.parse() +227: } + +(End of file - total 227 lines) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/omodex/bin" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/omodex/bin +directory + +oh-my-opencode.js +platform.d.ts +platform.js +platform.test.ts + +(4 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/omodex/package.json" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/omodex/package.json +file + +1: { +2: "name": "oh-my-opencode", +3: "version": "4.4.0", +4: "description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools", +5: "main": "./dist/index.js", +6: "types": "dist/index.d.ts", +7: "type": "module", +8: "workspaces": [ +9: "packages/rules-engine", +10: "packages/ast-grep-core", +11: "packages/ast-grep-mcp", +12: "packages/utils", +13: "packages/model-core", +14: "packages/prompts-core", +15: "packages/comment-checker-core", +16: "packages/hashline-core", +17: "packages/boulder-state", +18: "packages/agents-md-core" +19: ], +20: "bin": { +21: "oh-my-opencode": "bin/oh-my-opencode.js", +22: "oh-my-openagent": "bin/oh-my-opencode.js" +23: }, +24: "files": [ +25: "dist", +26: "bin", +27: "postinstall.mjs", +28: "packages/lsp-tools-mcp/dist", +29: "packages/ast-grep-mcp/dist" +30: ], +31: "exports": { +32: ".": { +33: "types": "./dist/index.d.ts", +34: "import": "./dist/index.js" +35: }, +36: "./server": "./dist/index.js", +37: "./schema.json": "./dist/oh-my-opencode.schema.json" +38: }, +39: "scripts": { +40: "build": "bun run build:ast-grep-mcp && bun build src/index.ts --outdir dist --target bun --format esm --external @ast-grep/napi --external zod && bun run build:node-require-shim && tsc --emitDeclarationOnly && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm --external @ast-grep/napi && bun run build:schema", +41: "build:lsp-tools-mcp": "npm --prefix packages/lsp-tools-mcp ci && npm --prefix packages/lsp-tools-mcp run build", +42: "build:node-require-shim": "bun run script/patch-node-require-shim.ts", +43: "build:all": "bun run build && bun run build:binaries", +44: "build:binaries": "bun run script/build-binaries.ts", +45: "build:schema": "bun run script/build-schema.ts", +46: "build:model-capabilities": "bun run script/build-model-capabilities.ts", +47: "clean": "rm -rf dist", +48: "prepare": "bun run build", +49: "postinstall": "node postinstall.mjs", +50: "prepublishOnly": "bun run clean && bun run build:lsp-tools-mcp && bun run build", +51: "test:model-capabilities": "bun test src/shared/model-capability-aliases.test.ts src/shared/model-capability-guardrails.test.ts src/shared/model-capabilities.test.ts src/cli/doctor/checks/model-resolution.test.ts --bail", +52: "typecheck": "tsgo --noEmit && bun run typecheck:packages", +53: "typecheck:packages": "tsgo --noEmit -p packages/rules-engine/tsconfig.json && tsgo --noEmit -p packages/ast-grep-core/tsconfig.json && tsgo --noEmit -p packages/ast-grep-mcp/tsconfig.json && tsgo --noEmit -p packages/utils/tsconfig.json && tsgo --noEmit -p packages/model-core/tsconfig.json && tsgo --noEmit -p packages/prompts-core/tsconfig.json && tsgo --noEmit -p packages/comment-checker-core/tsconfig.json && tsgo --noEmit -p packages/hashline-core/tsconfig.json && tsgo --noEmit -p packages/boulder-state/tsconfig.json && tsgo --noEmit -p packages/agents-md-core/tsconfig.json", +54: "typecheck:script": "tsgo --noEmit -p script/tsconfig.json", +55: "test": "bun test", +56: "build:ast-grep-mcp": "bun run --cwd packages/ast-grep-mcp build" +57: }, +58: "keywords": [ +59: "opencode", +60: "plugin", +61: "oracle", +62: "librarian", +63: "agents", +64: "ai", +65: "llm" +66: ], +67: "author": "YeonGyu-Kim", +68: "license": "SUL-1.0", +69: "repository": { +70: "type": "git", +71: "url": "git+https://github.com/code-yeongyu/oh-my-openagent.git" +72: }, +73: "bugs": { +74: "url": "https://github.com/code-yeongyu/oh-my-openagent/issues" +75: }, +76: "homepage": "https://github.com/code-yeongyu/oh-my-openagent#readme", +77: "dependencies": { +78: "@ast-grep/cli": "^0.42.2", +79: "@ast-grep/napi": "^0.42.2", +80: "@clack/prompts": "^1.4.0", +81: "@code-yeongyu/comment-checker": "^0.8.0", +82: "@modelcontextprotocol/sdk": "^1.29.0", +83: "@opencode-ai/plugin": "^1.15.4", +84: "@opencode-ai/sdk": "^1.15.4", +85: "commander": "^14.0.3", +86: "detect-libc": "^2.1.2", +87: "diff": "^9.0.0", +88: "effect": "4.0.0-beta.65", +89: "js-yaml": "^4.1.1", +90: "jsonc-parser": "^3.3.1", +91: "picocolors": "^1.1.1", +92: "picomatch": "^4.0.4", +93: "posthog-node": "^5.34.3", +94: "vscode-jsonrpc": "^8.2.1" +95: }, +96: "devDependencies": { +97: "@oh-my-opencode/ast-grep-core": "workspace:*", +98: "@oh-my-opencode/ast-grep-mcp": "workspace:*", +99: "@oh-my-opencode/agents-md-core": "workspace:*", +100: "@oh-my-opencode/boulder-state": "workspace:*", +101: "@oh-my-opencode/comment-checker-core": "workspace:*", +102: "@oh-my-opencode/hashline-core": "workspace:*", +103: "@oh-my-opencode/model-core": "workspace:*", +104: "@oh-my-opencode/prompts-core": "workspace:*", +105: "@oh-my-opencode/rules-engine": "workspace:*", +106: "@oh-my-opencode/utils": "workspace:*", +107: "@typescript/native-preview": "7.0.0-dev.20260518.1", +108: "@types/js-yaml": "^4.0.9", +109: "@types/picomatch": "^4.0.3", +110: "bun-types": "1.3.14", +111: "typescript": "^6.0.3", +112: "zod": "^4.4.3" +113: }, +114: "optionalDependencies": { +115: "oh-my-opencode-darwin-arm64": "4.4.0", +116: "oh-my-opencode-darwin-x64": "4.4.0", +117: "oh-my-opencode-darwin-x64-baseline": "4.4.0", +118: "oh-my-opencode-linux-arm64": "4.4.0", +119: "oh-my-opencode-linux-arm64-musl": "4.4.0", +120: "oh-my-opencode-linux-x64": "4.4.0", +121: "oh-my-opencode-linux-x64-baseline": "4.4.0", +122: "oh-my-opencode-linux-x64-musl": "4.4.0", +123: "oh-my-opencode-linux-x64-musl-baseline": "4.4.0", +124: "oh-my-opencode-windows-x64": "4.4.0", +125: "oh-my-opencode-windows-x64-baseline": "4.4.0" +126: }, +127: "overrides": { +128: "hono": "^4.12.18", +129: "@hono/node-server": "^1.19.13", +130: "express-rate-limit": "^8.5.1", +131: "fast-uri": "^3.1.2", +132: "path-to-regexp": "^8.4.2" +133: }, +134: "trustedDependencies": [ +135: "@ast-grep/cli", +136: "@ast-grep/napi", +137: "@code-yeongyu/comment-checker" +138: ], +139: "peerDependencies": { +140: "zod": "^4.0.0" +141: } +142: } + +(End of file - total 142 lines) + +``` + +--- + +## User + +그리고 비슷한 느낌으로 usage metric 비활성화 가능하게해주라 + +--- + +## User + + +[BACKGROUND TASK COMPLETED] +**ID:** `bg_984b7a80` +**Description:** Map CLI installer + bin structure +**Duration:** 48s + +**7 tasks still in progress.** You WILL be notified when ALL complete. +Do NOT poll - continue productive work. + +Use `background_output(task_id="bg_984b7a80")` to retrieve this result when ready. + + + +--- + +## User + + +[BACKGROUND TASK COMPLETED] +**ID:** `bg_d544d440` +**Description:** Find PostHog/telemetry in omodex +**Duration:** 1m 1s + +**6 tasks still in progress.** You WILL be notified when ALL complete. +Do NOT poll - continue productive work. + +Use `background_output(task_id="bg_d544d440")` to retrieve this result when ready. + + + +--- + +## User + + +[BACKGROUND TASK COMPLETED] +**ID:** `bg_0baa8bd3` +**Description:** Research Codex plugin/extension API +**Duration:** 28s + +**6 tasks still in progress.** You WILL be notified when ALL complete. +Do NOT poll - continue productive work. + +Use `background_output(task_id="bg_0baa8bd3")` to retrieve this result when ready. + + + +--- + +## Assistant (Sisyphus - Ultraworker · Opus 4.7 · 16.1s) + +_Thinking:_ + + The user wants the omo-codex telemetry to follow the same disable pattern as the other tools, using environment variables like OMO_SEND_ANONYMOUS_TELEMETRY=0 or OMO_DISABLE_POSTHOG=1. I've finished three tasks and should now collect the results from the completed ones while letting the others continue running. + +3개 완료, 4개 진행중. 완료된 결과 회수 + 직접 파일 읽기 병렬 진행. 그리고 사용량 메트릭 비활성화 토글도 omo-codex에 동일한 envvar 패턴(`OMO_CODEX_DISABLE_POSTHOG` / `OMO_CODEX_SEND_ANONYMOUS_TELEMETRY=0`)으로 반영하도록 계획에 반영합니다. + +**Tool: background_output** + +**Input:** +```json +{ + "task_id": "bg_984b7a80" +} +``` + +**Output:** +``` +Task Result + +Task ID: bg_984b7a80 +Description: Map CLI installer + bin structure +Duration: 48s +Session ID: ses_1a2046ba3ffeJHk1fVLKVR1Ud5 + +--- + +The user wants a deep understanding of the CLI installer architecture before adding a `--codex` flag. They want me to read many files in full and identify specific patterns. Let me start by reading all the requested files in parallel, then do additional searches to find the remaining information (platform detection, config writes, build process, etc.). + +Let me first read all the files they explicitly requested. + +Good, I've read all the explicitly requested files. Now I need to gather the remaining information the user asked for: + +1. Read `bin/` directory contents in full - I read the directory listing, now need to read the actual files inside `bin/` +2. Identify ALL CLI subcommands and their flags - I have this from `cli-program.ts` +3. Identify how the binary is built / compiled - from `package.json` scripts and `script/build-binaries.ts` +4. Identify where `~/.config/opencode/` writes happen - need to search `config-manager/` +5. Identify platform-detection / package.json bin name routing logic - need to read `bin/platform.js` and `bin/oh-my-opencode.js` + +Let me read the remaining files in parallel. + +Now I need to find where `~/.config/opencode/` writes happen. The user wants to understand the config manager. Let me read the config-manager files and also search for any references to `~/.config/opencode` or `opencode.json` writes. + +I need to read the key config-manager files to understand where `~/.config/opencode/` writes happen. Let me read the most important ones: `add-plugin-to-opencode-config.ts`, `write-omo-config.ts`, `detect-current-config.ts`, `ensure-config-directory-exists.ts`, `config-context.ts`, and `opencode-config-format.ts`. + +Now I need to find the shared functions that determine the actual config directory path (`~/.config/opencode/`). Let me search for `getOpenCodeConfigPaths` and `detectPluginConfigFile` in the shared directory, and also look at `plugin-identity.ts` to understand the naming constants. + +Let me read the key shared files to understand the config paths and plugin identity constants. + +Now I have a very comprehensive picture. Let me also quickly check if there are any existing references to "codex" in the CLI or installer code, and look at the `generate-omo-config.ts` to understand what the generated config looks like. Also need to check the `src/cli/config-manager/index.ts` barrel to see what's exported. + +Let me check if there's an index.ts in config-manager, and also read the model-fallback.ts to understand the generated config structure. + +Now I have a comprehensive understanding. Let me compile everything into the required format. I need to provide: + +1. Intent Analysis +2. All the files read with absolute paths and why they're relevant +3. A structured answer covering: + - bin/ directory contents + - package.json bin entries, scripts, files, publishConfig + - CLI subcommands and flags + - How binary is built/compiled + - Where ~/.config/opencode/ writes happen + - Platform-detection / package.json bin name routing logic + - Line numbers for specific logic + +Let me organize this carefully. + + +**Literal Request**: Read a long list of installer-related files and return an exhaustive architectural summary with absolute paths and line numbers. + +**Actual Need**: The user is about to add a `--codex` flag to the CLI installer and possibly a new `omo` bin entry. They need the full installer control flow, config write locations, binary build pipeline, and dual-name routing logic so they can modify the right files without missing side effects. + +**Success Looks Like**: A single response that maps every relevant file, shows the exact line numbers where decisions happen, and explains the install flow end-to-end so the user can immediately start editing. + + + + +- /Users/yeongyu/local-workspaces/omodex/bin/oh-my-opencode.js - Platform binary wrapper/shim that resolves the correct compiled binary at runtime (lines 83-153) +- /Users/yeongyu/local-workspaces/omodex/bin/platform.js - Shared platform detection: `getPlatformPackage`, `getPlatformPackageCandidates`, `getBinaryPath` (lines 10-82) +- /Users/yeongyu/local-workspaces/omodex/bin/platform.d.ts - Type declarations for platform detection +- /Users/yeongyu/local-workspaces/omodex/bin/platform.test.ts - Tests for platform package name resolution +- /Users/yeongyu/local-workspaces/omodex/package.json - Defines dual bin entries `"oh-my-opencode"` and `"oh-my-openagent"` both pointing to `bin/oh-my-opencode.js` (lines 20-23); build scripts (lines 39-56); optional platform binary dependencies (lines 114-126) +- /Users/yeongyu/local-workspaces/omodex/postinstall.mjs - Post-install hook that verifies platform binary availability via `getPlatformPackageCandidates` and `getBinaryPath` (lines 102-123) +- /Users/yeongyu/local-workspaces/omodex/src/cli/index.ts - CLI entry point: `#!/usr/bin/env bun` then calls `runCli()` (lines 1-4) +- /Users/yeongyu/local-workspaces/omodex/src/cli/cli-program.ts - Commander.js program definition with all 8 subcommands and their flags (lines 17-227) +- /Users/yeongyu/local-workspaces/omodex/src/cli/install.ts - Routes to TUI or CLI installer based on `args.tui` (lines 8-9) +- /Users/yeongyu/local-workspaces/omodex/src/cli/cli-installer.ts - Non-interactive install flow: validation → OpenCode check → plugin registration → config write → summary (lines 27-150) +- /Users/yeongyu/local-workspaces/omodex/src/cli/tui-installer.ts - Interactive install flow using `@clack/prompts` (lines 16-122) +- /Users/yeongyu/local-workspaces/omodex/src/cli/tui-install-prompts.ts - Prompt definitions for each provider selection in TUI mode (lines 29-135) +- /Users/yeongyu/local-workspaces/omodex/src/cli/install-validators.ts - Argument validation, `argsToConfig`, `detectedToInitialValues`, and pretty-print helpers (lines 116-206) +- /Users/yeongyu/local-workspaces/omodex/src/cli/types.ts - Type definitions: `InstallArgs`, `InstallConfig`, `DetectedConfig` (lines 1-50) +- /Users/yeongyu/local-workspaces/omodex/src/cli/config-manager/config-context.ts - Shared config context: `getConfigDir()`, `getOmoConfigPath()`, `initConfigContext()` (lines 14-53) +- /Users/yeongyu/local-workspaces/omodex/src/cli/config-manager/ensure-config-directory-exists.ts - Creates `~/.config/opencode/` if missing (lines 4-8) +- /Users/yeongyu/local-workspaces/omodex/src/cli/config-manager/opencode-config-format.ts - Detects whether OpenCode config is `json`, `jsonc`, or `none` (lines 6-17) +- /Users/yeongyu/local-workspaces/omodex/src/cli/config-manager/detect-current-config.ts - Reads existing OpenCode + OMO config to detect installed version and providers (lines 73-124) +- /Users/yeongyu/local-workspaces/omodex/src/cli/config-manager/add-plugin-to-opencode-config.ts - Writes the plugin entry (`oh-my-openagent@`) into `~/.config/opencode/opencode.json(c)` (lines 13-111) +- /Users/yeongyu/local-workspaces/omodex/src/cli/config-manager/write-omo-config.ts - Writes the generated `oh-my-openagent.json(c)` into `~/.config/opencode/` (lines 19-88) +- /Users/yeongyu/local-workspaces/omodex/src/cli/config-manager/generate-omo-config.ts - Thin wrapper around `generateModelConfig()` (lines 4-6) +- /Users/yeongyu/local-workspaces/omodex/src/cli/config-manager/plugin-name-with-version.ts - Resolves npm dist-tags to produce `oh-my-openagent@latest` etc. (lines 16-33) +- /Users/yeongyu/local-workspaces/omodex/src/cli/model-fallback.ts - Generates the full agent/category model fallback configuration object from provider selections (lines 98-230) +- /Users/yeongyu/local-workspaces/omodex/src/shared/opencode-config-dir.ts - Determines the actual config directory path: defaults to `~/.config/opencode/`, respects `OPENCODE_CONFIG_DIR` and Tauri paths (lines 58-74) +- /Users/yeongyu/local-workspaces/omodex/src/shared/plugin-identity.ts - Canonical name constants: `PLUGIN_NAME = "oh-my-openagent"`, `LEGACY_PLUGIN_NAME = "oh-my-opencode"`, `PUBLISHED_PACKAGE_NAME = LEGACY_PLUGIN_NAME` (lines 1-8) +- /Users/yeongyu/local-workspaces/omodex/src/shared/migrate-legacy-config-file.ts - Migrates `oh-my-opencode.json(c)` → `oh-my-openagent.json(c)` on write (lines 71-94) +- /Users/yeongyu/local-workspaces/omodex/script/build-binaries.ts - Builds 11 platform-specific binaries via `bun build --compile` from `src/cli/index.ts` (lines 18-113) + + + + +## 1. BIN/ DIRECTORY CONTENTS + +| File | Purpose | +|------|---------| +| `/Users/yeongyu/local-workspaces/omodex/bin/oh-my-opencode.js` | Node wrapper script (line 1: `#!/usr/bin/env node`). At runtime it detects platform/arch/libc, resolves the correct platform-specific compiled binary via `require.resolve()`, then `spawnSync`s it with `process.argv.slice(2)` (lines 83-153). | +| `/Users/yeongyu/local-workspaces/omodex/bin/platform.js` | Shared platform detection module used by both the wrapper and `postinstall.mjs`. Exports `getPlatformPackage`, `getPlatformPackageCandidates`, `getBinaryPath` (lines 10-82). | +| `/Users/yeongyu/local-workspaces/omodex/bin/platform.d.ts` | Type declarations for the platform module. | +| `/Users/yeongyu/local-workspaces/omodex/bin/platform.test.ts` | Tests verifying package name generation for darwin/linux/windows, glibc/musl, baseline fallback ordering, and renamed package families (lines 195-207 test `packageBaseName: "oh-my-openagent"`). | + +## 2. PACKAGE.JSON BIN / SCRIPTS / FILES / PUBLISHCONFIG + +From `/Users/yeongyu/local-workspaces/omodex/package.json`: + +- **bin** (lines 20-23): + ```json + "bin": { + "oh-my-opencode": "bin/oh-my-opencode.js", + "oh-my-openagent": "bin/oh-my-opencode.js" + } + ``` + Both names point to the **same** JS shim. There is **no** `omo` entry yet. + +- **scripts** (lines 39-56): + - `build` (line 40): Builds plugin ESM bundle + CLI bundle + schema. CLI part: `bun build src/cli/index.ts --outdir dist/cli --target bun --format esm` + - `build:binaries` (line 44): Runs `script/build-binaries.ts` + - `postinstall` (line 49): `node postinstall.mjs` + +- **files** (lines 24-30): + ```json + "files": ["dist", "bin", "postinstall.mjs", "packages/lsp-tools-mcp/dist", "packages/ast-grep-mcp/dist"] + ``` + +- **publishConfig**: Not present in this file. Optional platform binary packages are listed under `optionalDependencies` (lines 114-126) with exact version `4.4.0`. + +## 3. ALL CLI SUBCOMMANDS AND FLAGS + +From `/Users/yeongyu/local-workspaces/omodex/src/cli/cli-program.ts` (lines 17-227): + +| Command | Alias | Flags | +|---------|-------|-------| +| `install` | `setup` | `--no-tui`, `--claude `, `--openai `, `--gemini `, `--copilot `, `--opencode-zen `, `--zai-coding-plan `, `--kimi-for-coding `, `--opencode-go `, `--vercel-ai-gateway `, `--skip-auth` | +| `run ` | — | `-a, --agent `, `-m, --model `, `-d, --directory `, `-p, --port `, `--attach `, `--on-complete `, `--json`, `--no-timestamp`, `--verbose`, `--session-id ` | +| `get-local-version` | — | `-d, --directory `, `--json` | +| `doctor` | — | `--status`, `--verbose`, `--json` | +| `refresh-model-capabilities` | — | `-d, --directory `, `--source-url `, `--json` | +| `version` | — | none | +| `boulder` | — | `-d, --directory `, `-w, --work-id `, `--json` | +| `mcp-oauth` | — | Subcommands: `login`, `logout`, `status` (defined in `createMcpOAuthCommand()`) | + +## 4. HOW THE BINARY IS BUILT / COMPILED + +From `/Users/yeongyu/local-workspaces/omodex/script/build-binaries.ts` (lines 18-113): + +- **Entry point**: `src/cli/index.ts` (line 32) +- **Tool**: `bun build --compile --minify --sourcemap --bytecode --target= --outfile=` (line 42) +- **Targets**: 11 platforms including darwin-arm64, darwin-x64, darwin-x64-baseline, linux-x64, linux-x64-baseline, linux-arm64, linux-x64-musl, linux-x64-musl-baseline, linux-arm64-musl, windows-x64, windows-x64-baseline (lines 18-30) +- **Output naming**: Each binary lands in `packages/oh-my-opencode-/bin/oh-my-opencode` (or `.exe` on Windows) +- **Distribution**: These platform packages are published as `optionalDependencies` in `package.json`. The JS shim (`bin/oh-my-opencode.js`) resolves the correct one at runtime. + +## 5. WHERE `~/.config/opencode/` WRITES HAPPEN + +The config directory resolution chain: + +1. **`/Users/yeongyu/local-workspaces/omodex/src/shared/opencode-config-dir.ts`** (lines 58-74): + - Default: `join(homedir(), ".config", "opencode")` → `~/.config/opencode/` + - Override: `process.env.OPENCODE_CONFIG_DIR` (line 64) + +2. **`/Users/yeongyu/local-workspaces/omodex/src/cli/config-manager/ensure-config-directory-exists.ts`** (lines 4-8): + - Calls `mkdirSync(configDir, { recursive: true })` if missing. + +3. **Files written during install**: + - **OpenCode plugin registration**: `~/.config/opencode/opencode.json` or `opencode.jsonc` + - Written by `/Users/yeongyu/local-workspaces/omodex/src/cli/config-manager/add-plugin-to-opencode-config.ts` (lines 13-111) + - Inserts `"oh-my-openagent@"` into the `plugin` array (line 82) + - **OMO plugin config**: `~/.config/opencode/oh-my-openagent.json` or `.jsonc` + - Written by `/Users/yeongyu/local-workspaces/omodex/src/cli/config-manager/write-omo-config.ts` (lines 19-88) + - Path resolved via `getOmoConfigPath()` in `config-context.ts` (lines 45-53) + - If a legacy `oh-my-opencode.json(c)` exists, it is **migrated** to `oh-my-openagent.json(c)` via `migrateLegacyConfigFile()` (called at lines 33-37 of `write-omo-config.ts`) + +## 6. PLATFORM-DETECTION / PACKAGE.JSON BIN NAME ROUTING LOGIC + +### Dual-name routing +- `package.json` declares **two** bin entries (`oh-my-opencode` and `oh-my-openagent`) but both point to the **same** `bin/oh-my-opencode.js` shim (lines 20-23). +- The shim does **not** branch on `process.argv[0]`; it only resolves the compiled binary and forwards all args. There is no `omo` entry yet. + +### Platform binary resolution (inside the shim) +From `/Users/yeongyu/local-workspaces/omodex/bin/oh-my-opencode.js` (lines 83-153): + +1. Detect `platform`, `arch`, `libcFamily` (via `detect-libc` on Linux) (lines 84-85) +2. Detect AVX2 support via `/proc/cpuinfo` (Linux) or `sysctl machdep.cpu.leaf7_features` (macOS) (lines 30-61) +3. Call `getPlatformPackageCandidates({ platform, arch, libcFamily, preferBaseline: avx2Supported === false, packageBaseName })` (lines 91-97) +4. Try `require.resolve(getBinaryPath(pkg, platform))` for each candidate in order (lines 103-111) +5. `spawnSync(resolvedBinary, process.argv.slice(2), { stdio: "inherit" })` (line 125) +6. Handle `SIGILL` fallback to baseline (lines 139-141) + +### `packageBaseName` propagation +- `getPackageBaseName()` reads `package.json`'s `name` field (line 74-81 in `bin/oh-my-opencode.js`). +- Since `package.json` `name` is `"oh-my-opencode"`, the platform packages searched are `oh-my-opencode-darwin-arm64`, etc. +- The `platform.js` module supports a `packageBaseName` override (tested at `platform.test.ts` lines 195-207), but the shim currently passes the real package name. + +## 7. INSTALL FLOW END-TO-END + +``` +src/cli/index.ts (runCli) + └─→ src/cli/cli-program.ts (commander) + └─→ "install" command + └─→ src/cli/install.ts + ├─→ TUI path: src/cli/tui-installer.ts + │ ├─→ detectCurrentConfig() + │ ├─→ promptInstallConfig() ← @clack/prompts + │ ├─→ addPluginToOpenCodeConfig(version) + │ └─→ writeOmoConfig(config) + └─→ CLI path: src/cli/cli-installer.ts + ├─→ validateNonTuiArgs() + ├─→ detectCurrentConfig() + ├─→ addPluginToOpenCodeConfig(version) + └─→ writeOmoConfig(config) +``` + +Both paths ultimately call the same two config-manager functions: +- `addPluginToOpenCodeConfig()` → writes `~/.config/opencode/opencode.json(c)` plugin array +- `writeOmoConfig()` → writes `~/.config/opencode/oh-my-openagent.json(c)` + +## 8. KEY CONSTANTS FOR NAMING + +From `/Users/yeongyu/local-workspaces/omodex/src/shared/plugin-identity.ts` (lines 1-8): + +```ts +PLUGIN_NAME = "oh-my-openagent" +LEGACY_PLUGIN_NAME = "oh-my-opencode" +PUBLISHED_PACKAGE_NAME = LEGACY_PLUGIN_NAME // "oh-my-opencode" +CONFIG_BASENAME = "oh-my-openagent" +LEGACY_CONFIG_BASENAME = "oh-my-opencode" +``` + +This means: +- The **npm package** is still `oh-my-opencode` +- The **plugin entry** written to `opencode.json` is `oh-my-openagent` +- The **config file** written is `oh-my-openagent.json(c)` +- Legacy `oh-my-opencode` entries are still detected and migrated. + + + + +To add `--codex` and an `omo` bin entry, you will need to touch these files in this order: + +1. **`/Users/yeongyu/local-workspaces/omodex/package.json`** — Add `"omo": "bin/oh-my-opencode.js"` under `bin` (line 20-23 area). +2. **`/Users/yeongyu/local-workspaces/omodex/src/cli/types.ts`** — Add `codex?: BooleanArg` to `InstallArgs` and `hasCodex: boolean` to `InstallConfig` / `DetectedConfig` (lines 1-50 area). +3. **`/Users/yeongyu/local-workspaces/omodex/src/cli/cli-program.ts`** — Add `.option("--codex ", "...")` to the `install` command (around line 30-40 area). +4. **`/Users/yeongyu/local-workspaces/omodex/src/cli/install-validators.ts`** — Add `--codex` validation in `validateNonTuiArgs()` and `argsToConfig()` / `detectedToInitialValues()` (lines 116-206 area). +5. **`/Users/yeongyu/local-workspaces/omodex/src/cli/tui-install-prompts.ts`** — Add a Codex provider prompt in `promptInstallConfig()` (around line 122 area). +6. **`/Users/yeongyu/local-workspaces/omodex/src/cli/model-fallback.ts`** — Add Codex provider availability and model routing logic (lines 98-230 area). +7. **`/Users/yeongyu/local-workspaces/omodex/src/cli/config-manager/detect-current-config.ts`** — Detect existing Codex config in `detectProvidersFromOmoConfig()` (lines 9-62 area). +8. Consider whether `--codex` should install a **different adapter/plugin entry** (e.g. `oh-my-codex`) instead of just adding a provider flag — if so, `add-plugin-to-opencode-config.ts` and `plugin-identity.ts` will also need changes. + +Ready to proceed — no follow-up needed for architecture understanding. + + +``` + +**Tool: background_output** + +**Input:** +```json +{ + "task_id": "bg_d544d440" +} +``` + +**Output:** +``` +Task Result + +Task ID: bg_d544d440 +Description: Find PostHog/telemetry in omodex +Duration: 1m 1s +Session ID: ses_1a2049248ffeMyBe6HikRKvrBX + +--- + +The user wants an exhaustive audit of all PostHog/telemetry/analytics code in the oh-my-opencode repository. They need to replicate this for a sibling product. I need to: + +1. Search for all telemetry-related terms across the codebase +2. Find the PostHog API key storage +3. Identify events emitted +4. Find hashed installation ID computation and persistence +5. Find dedup mechanism +6. Find agents/hooks/CLI commands that call PostHog +7. Find cli-installer telemetry flow +8. Find docs mentioning telemetry + +I should launch multiple parallel searches using grep and ast_grep to cover all the terms. + +Good, I have a lot of files. Now I need to read the core telemetry files to understand the implementation. The most important ones are: + +- `src/shared/posthog.ts` - main PostHog client +- `src/shared/posthog.test.ts` - tests for PostHog client +- `src/shared/posthog-activity-state.ts` - dedup / activity state +- `src/shared/posthog-activity-state.test.ts` - tests for activity state +- `src/cli/cli-installer.telemetry.test.ts` - CLI installer telemetry tests +- `src/cli/run/runner.telemetry.test.ts` - runner telemetry tests +- `src/index.telemetry.test.ts` - main telemetry tests +- `src/cli/cli-installer.ts` - CLI installer +- `src/cli/run/runner.ts` - CLI runner +- `src/cli/doctor/runner.ts` - doctor runner +- `src/cli/doctor/index.ts` - doctor index +- `src/cli/install.test.ts` - install tests +- `src/cli/tui-installer.ts` - TUI installer + +Also need to check docs: +- `docs/legal/privacy-policy.md` +- `docs/reference/features.md` +- `docs/reference/configuration.md` +- `docs/reference/cli.md` +- `README.md` + +And package.json for dependencies. + +Let me read the core files first. + +Now I need to read the CLI files that actually call PostHog to understand the flow. Let me read: +- src/cli/cli-installer.ts +- src/cli/run/runner.ts +- src/cli/doctor/runner.ts +- src/cli/doctor/index.ts +- src/cli/install.test.ts +- src/cli/tui-installer.ts + +Also need to check the plugin entry point and docs. + +Now I need to find where the plugin itself calls PostHog. Let me search for `createPluginPostHog` and `trackActive` to find all call sites. + +Now I need to find where `createPluginPostHog` is actually used in the plugin lifecycle. It seems like it might be in `src/testing/create-plugin-module.ts` or `src/index.ts`. Let me search for it. + +Interesting - `createPluginPostHog` is exported but I don't see it being used in `create-plugin-module.ts` or `index.ts`. Let me search more broadly for where the plugin-side telemetry is actually invoked. Maybe it's in a hook or event handler. + +Now I need to find where `createPluginPostHog` is actually used. It seems like it's exported but maybe not used in the current codebase? Let me search for it more specifically. + +Interesting - `createPluginPostHog` is exported but never actually called in the production codebase. It seems like it was prepared for plugin-side telemetry but currently only CLI `run` uses telemetry. Let me verify this by checking if there's any other usage I might have missed. Also need to check `cli-installer.telemetry.test.ts` more carefully - it mocks posthog but the actual `cli-installer.ts` doesn't seem to import or call posthog at all. Let me re-read `cli-installer.ts` to see if I missed something. + +Wait, looking at `cli-installer.ts` again, it doesn't import posthog at all. The telemetry test for cli-installer mocks it but the actual installer doesn't call it. This is interesting - maybe the test is testing a future behavior or there's a missing implementation. + +Let me check if there's any other file that calls posthog in the CLI besides runner.ts. + +Now I have a clear picture. Let me also check the package.json for the posthog-node dependency and any other related config. Also need to check the docs files for completeness. + +Now I have a comprehensive understanding. Let me also check the `src/shared/plugin-identity.ts` to understand `PUBLISHED_PACKAGE_NAME` and `PLUGIN_NAME` and `CACHE_DIR_NAME` since these are used in the distinct ID and activity state file path. + +Now I have all the information needed. Let me compile the exhaustive report. + +Key findings: +1. **PostHog API key**: Hardcoded default `phc_CFJhj5HyvA62QPhvyaUCtaq23aUfznnijg5VaaGkNk74` in `src/shared/posthog.ts`, overridable via `POSTHOG_API_KEY` env var. +2. **Events emitted**: Only `omo_daily_active` with properties: platform, package_name, plugin_name, package_version, runtime, runtime_version, source (cli/plugin), $os, $os_version, os_arch, os_type, cpu_count, cpu_model, total_memory_gb, locale, timezone, shell, ci, terminal, $process_person_profile=false, day_utc, reason. +3. **Hashed installation ID**: `sha256(PUBLISHED_PACKAGE_NAME + ':' + hostname())` computed in `getPostHogDistinctId()`. +4. **Dedup mechanism**: `posthog-activity-state.ts` reads/writes `posthog-activity.json` in `~/.local/share/oh-my-opencode/posthog-activity.json` (or XDG_DATA_HOME equivalent). Compares `lastActiveDayUTC` with current UTC day string. If different, sets `captureDaily=true` and updates the file. +5. **CLI commands calling PostHog**: Only `src/cli/run/runner.ts` actually calls it. `createPluginPostHog` exists but is NOT called anywhere in production. +6. **cli-installer telemetry test**: `src/cli/cli-installer.telemetry.test.ts` mocks posthog but the actual `cli-installer.ts` does NOT import or call posthog - it only prints a message about telemetry being enabled. +7. **Docs**: README.md, docs/legal/privacy-policy.md, docs/reference/configuration.md, docs/reference/cli.md, docs/guide/installation.md all mention telemetry. + +Wait, I need to double-check the activity state file path. `getDataDir()` returns `~/.local/share` (or XDG_DATA_HOME), then `CACHE_DIR_NAME` is `"oh-my-opencode"`, so the path is `~/.local/share/oh-my-opencode/posthog-activity.json`. + +Also need to note that `OMO_SEND_ANONYMOUS_TELEMETRY=0/false/no` disables, and `OMO_DISABLE_POSTHOG=1/true` also disables. + +The `createPluginPostHog` function is exported but unused. This is an important finding for replication - they may want to wire it up. + +Let me also check if there are any other files that mention telemetry in the context of the plugin loading. The `index.telemetry.test.ts` tests that plugin load doesn't crash when telemetry throws, but it doesn't actually call posthog - it just tests the plugin module creation with mocked dependencies. + +I should also check `src/cli/cli-installer.telemetry.test.ts` more carefully - it mocks posthog and calls `runCliInstaller`, but `runCliInstaller` doesn't actually use posthog. The test name says "does not crash CLI install when telemetry shutdown throws" but there's no shutdown call in the actual installer. This test seems to be testing a behavior that doesn't exist, or maybe I'm missing something. Let me re-read `cli-installer.ts` to see if there's any posthog import I missed. + +No, `cli-installer.ts` doesn't import posthog. The test mocks it but the real code never calls it. This is a discrepancy worth noting. + +Actually wait - maybe the install command used to call it and it was removed? Or maybe the test is preemptive? Either way, I should report what the code actually does. + +Let me also check if `src/cli/install.ts` or any other file in the install flow calls posthog. No, only `runner.ts` does. + +Now let me structure the results. + + +**Literal Request**: Grep the entire oh-my-opencode codebase for PostHog/telemetry keywords and return every touchpoint with excerpts. + +**Actual Need**: The user needs to replicate this telemetry system for `omo-codex` and build a parallel pathway that distinguishes `omo` vs `omo-codex` installations in PostHog. They need an exhaustive inventory of: API key storage, events, distinct ID computation, dedup mechanism, callers, tests, and docs. + +**Success Looks Like**: A structured list of every file that touches telemetry, with concrete excerpts, plus a synthesized answer explaining the full telemetry architecture so the user can replicate it without asking follow-ups. + + + + + +### Core Implementation Files + +- `/Users/yeongyu/local-workspaces/omodex/src/shared/posthog.ts` - Main PostHog client factory. Hardcodes default API key, defines `omo_daily_active` event, computes hashed distinct_id, reads env vars `OMO_SEND_ANONYMOUS_TELEMETRY`, `OMO_DISABLE_POSTHOG`, `POSTHOG_API_KEY`, `POSTHOG_HOST`. +- `/Users/yeongyu/local-workspaces/omodex/src/shared/posthog.test.ts` - Unit tests for client creation, constructor options, and `trackActive` emission contract (asserts exactly one `omo_daily_active` event, no `omo_hourly_active`). +- `/Users/yeongyu/local-workspaces/omodex/src/shared/posthog-activity-state.ts` - Dedup state machine. Reads/writes `posthog-activity.json` to decide `captureDaily` boolean based on `lastActiveDayUTC` vs current UTC day. +- `/Users/yeongyu/local-workspaces/omodex/src/shared/posthog-activity-state.test.ts` - Tests for state file parsing (null, array, number, valid JSON, legacy hourly state, field preservation). +- `/Users/yeongyu/local-workspaces/omodex/src/shared/plugin-identity.ts` - Defines `PUBLISHED_PACKAGE_NAME = "oh-my-opencode"` and `CACHE_DIR_NAME = "oh-my-opencode"`, which feed into the distinct ID hash and state file path. +- `/Users/yeongyu/local-workspaces/omodex/src/shared/data-path.ts` - `getDataDir()` resolves `~/.local/share` (or `XDG_DATA_HOME`), determining where `posthog-activity.json` lives. + +### CLI Call Sites + +- `/Users/yeongyu/local-workspaces/omodex/src/cli/run/runner.ts` - **Only production call site.** Imports `createCliPostHog` and `getPostHogDistinctId`, calls `trackActive(distinctId, "run_started")` at start of `run()`, and `posthog.shutdown()` in `finally`. Wraps both in `try/catch` with silent ignore. +- `/Users/yeongyu/local-workspaces/omodex/src/cli/run/runner.telemetry.test.ts` - Tests that `run()` does not crash when `trackActive` or `shutdown` throws. +- `/Users/yeongyu/local-workspaces/omodex/src/cli/cli-installer.telemetry.test.ts` - Mocks posthog module and tests `runCliInstaller` telemetry isolation, **but the actual `cli-installer.ts` does not import or call posthog** (see below). +- `/Users/yeongyu/local-workspaces/omodex/src/cli/cli-installer.ts` - Prints telemetry opt-out message to console (line 119) but **does not emit any PostHog event**. +- `/Users/yeongyu/local-workspaces/omodex/src/cli/tui-installer.ts` - Prints telemetry opt-out message to console (line 88) but **does not emit any PostHog event**. +- `/Users/yeongyu/local-workspaces/omodex/src/cli/doctor/index.ts` - Suggests `OMO_DISABLE_POSTHOG=1` in error output (line 13) but does not call PostHog. +- `/Users/yeongyu/local-workspaces/omodex/src/cli/install.ts` - Router to TUI or CLI installer; no telemetry logic. + +### Plugin Lifecycle + +- `/Users/yeongyu/local-workspaces/omodex/src/testing/create-plugin-module.ts` - Plugin factory; **does not import or call posthog**. `createPluginPostHog()` is exported but never invoked here. +- `/Users/yeongyu/local-workspaces/omodex/src/index.ts` - Thin wrapper around `createPluginModule()`; no telemetry. +- `/Users/yeongyu/local-workspaces/omodex/src/index.telemetry.test.ts` - Tests that plugin load does not crash when telemetry throws, but only mocks generic deps (no actual posthog call in production plugin load). + +### Package Manifest + +- `/Users/yeongyu/local-workspaces/omodex/package.json` - Declares dependency `"posthog-node": "^5.34.3"` (line 93). + +### Documentation + +- `/Users/yeongyu/local-workspaces/omodex/README.md` - Line 125: explains anonymous telemetry default, DAU/WAU/MAU, hashed identifier, opt-out env vars, links to Privacy Policy and ToS. +- `/Users/yeongyu/local-workspaces/omodex/docs/legal/privacy-policy.md` - Full privacy policy describing `omo_daily_active` event, metadata collected, pseudonymous ID, no person profiles, no prompt/repo content collection. +- `/Users/yeongyu/local-workspaces/omodex/docs/legal/terms-of-service.md` - Line 27: references limited anonymous telemetry described in Privacy Policy. +- `/Users/yeongyu/local-workspaces/omodex/docs/reference/configuration.md` - Lines 1008-1011: documents `OMO_SEND_ANONYMOUS_TELEMETRY`, `OMO_DISABLE_POSTHOG`, `POSTHOG_API_KEY`, `POSTHOG_HOST`. +- `/Users/yeongyu/local-workspaces/omodex/docs/reference/cli.md` - Line 61: notes anonymous telemetry uses PostHog with hashed installation identifier. +- `/Users/yeongyu/local-workspaces/omodex/docs/guide/installation.md` - Line 28: repeats the default telemetry disclosure and opt-out instructions. + + + + + +## 1. PostHog API Key Storage + +**Hardcoded default** in `/Users/yeongyu/local-workspaces/omodex/src/shared/posthog.ts` line 44: +```ts +const DEFAULT_POSTHOG_API_KEY = "phc_CFJhj5HyvA62QPhvyaUCtaq23aUfznnijg5VaaGkNk74" +``` +Overridable via `POSTHOG_API_KEY` env var (line 77). Host defaults to `https://us.i.posthog.com`, overridable via `POSTHOG_HOST`. + +## 2. Events Emitted + +Only **one event**: `omo_daily_active`. + +Properties attached (from `getSharedProperties` + per-event fields): +- `platform`: `"oh-my-opencode"` +- `package_name`: `PUBLISHED_PACKAGE_NAME` (`"oh-my-opencode"`) +- `plugin_name`: `PLUGIN_NAME` (`"oh-my-openagent"`) +- `package_version`: from `package.json` +- `runtime`: `"bun"` +- `runtime_version`: `process.versions.bun` +- `source`: `"cli"` or `"plugin"` +- `$os`, `$os_version`, `os_arch`, `os_type` +- `cpu_count`, `cpu_model` +- `total_memory_gb` +- `locale`, `timezone` +- `shell`, `ci`, `terminal` +- `$process_person_profile`: `false` (explicitly disabled) +- `day_utc`: current UTC day string (e.g. `"2026-04-18"`) +- `reason`: currently only `"run_started"` + +## 3. Hashed Installation ID Computation + +In `/Users/yeongyu/local-workspaces/omodex/src/shared/posthog.ts` lines 162-166: +```ts +export function getPostHogDistinctId(): string { + return createHash("sha256") + .update(`${PUBLISHED_PACKAGE_NAME}:${resolveOsProvider().hostname()}`) + .digest("hex") +} +``` +It hashes `"oh-my-opencode:" + os.hostname()`. The raw hostname never leaves the machine. + +## 4. Dedup Mechanism (once per UTC day per machine) + +Implemented in `/Users/yeongyu/local-workspaces/omodex/src/shared/posthog-activity-state.ts`. + +- **State file path**: `join(getDataDir(), CACHE_DIR_NAME, "posthog-activity.json")` + - Typically: `~/.local/share/oh-my-opencode/posthog-activity.json` +- **Logic**: reads `lastActiveDayUTC` from JSON. If it differs from `new Date().toISOString().slice(0, 10)`, returns `captureDaily: true` and atomically writes the new day back. Otherwise `captureDaily: false`. +- The `trackActive` method in `posthog.ts` only calls `configuredClient.capture()` when `activityState.captureDaily` is true. + +## 5. Agents / Hooks / CLI Commands That Call PostHog + +**Only one production caller**: `src/cli/run/runner.ts` (`oh-my-opencode run `). + +```ts +const posthog = createCliPostHog() +const distinctId = getPostHogDistinctId() +try { + posthog.trackActive(distinctId, "run_started") +} catch { + // telemetry failure is non-fatal, silently ignore +} +// ... later in finally ... +try { + await posthog.shutdown() +} catch { + // telemetry failure is non-fatal, silently ignore +} +``` + +**`createPluginPostHog()` is exported but never called** in the current codebase. There is no plugin-load telemetry event wired up despite the README saying "A single event is sent at most once per UTC day per machine when the plugin loads or when the `run` CLI is invoked." The plugin side appears to be a stub. + +## 6. CLI Installer Telemetry Flow + +`src/cli/cli-installer.telemetry.test.ts` exists and mocks posthog, but the **actual `cli-installer.ts` does not import or invoke posthog**. It only prints: +``` +Anonymous telemetry is enabled by default. Disable it with OMO_SEND_ANONYMOUS_TELEMETRY=0 or OMO_DISABLE_POSTHOG=1. +``` +The test appears to be defensive (ensuring installer doesn't crash if posthog were added later), but currently the installer emits **zero** telemetry events. + +## 7. Disable Flags + +- `OMO_SEND_ANONYMOUS_TELEMETRY=0` (or `false`/`no`) disables +- `OMO_DISABLE_POSTHOG=1` (or `true`) disables +- Both are checked in `shouldDisablePostHog()` in `posthog.ts` + +## 8. PostHog Client Options (both CLI and plugin factories) + +```ts +{ + enableExceptionAutocapture: false, + enableLocalEvaluation: false, + strictLocalEvaluation: true, + disableRemoteConfig: true, + flushAt: 1, + flushInterval: 0, +} +``` + + + + + +To replicate this for `omo-codex` with a parallel pathway: + +1. **Copy `src/shared/posthog.ts` and `src/shared/posthog-activity-state.ts`** into `omo-codex` and change: + - `PUBLISHED_PACKAGE_NAME` to `"omo-codex"` + - `platform` property to `"omo-codex"` + - `DEFAULT_POSTHOG_API_KEY` to your own PostHog project key (or keep the same project and distinguish via the `platform` property) + - Event name from `omo_daily_active` to something like `omo_codex_daily_active` (or keep same event and filter by `platform` in PostHog) + +2. **Decide on shared vs separate PostHog project**: + - Same project + same API key: easiest comparison in PostHog dashboards; filter by `platform` or `package_name` + - Separate project + separate API key: complete isolation; use `POSTHOG_API_KEY` env var in `omo-codex` + +3. **Wire up callers**: + - In `omo-codex`, call `createCliPostHog()` / `createPluginPostHog()` at the equivalent entry points (CLI run command, plugin load) + - The current `oh-my-opencode` codebase only wires the CLI `run` command; you may want to also wire plugin load if you want true DAU tracking + +4. **Keep the same dedup file pattern** but use a different filename or directory if you want `omo-codex` to track independently from `oh-my-opencode` on the same machine: + - Current path: `~/.local/share/oh-my-opencode/posthog-activity.json` + - For `omo-codex`: `~/.local/share/omo-codex/posthog-activity.json` + +5. **Update docs**: + - Copy the env var documentation pattern from `docs/reference/configuration.md` and `docs/legal/privacy-policy.md` + - Update README opt-out messaging + +6. **Add tests**: + - Copy `posthog.test.ts`, `posthog-activity-state.test.ts`, `runner.telemetry.test.ts`, and `index.telemetry.test.ts` as behavioral specs + +Ready to proceed - no follow-up needed unless you want me to generate the actual `omo-codex` telemetry module code. + + + +``` + +**Tool: background_output** + +**Input:** +```json +{ + "task_id": "bg_0baa8bd3" +} +``` + +**Output:** +``` +Task Result + +Task ID: bg_0baa8bd3 +Description: Research Codex plugin/extension API +Duration: 28s +Session ID: ses_1a203f959ffeh4ZI3KfbfemChp + +--- + +**Official Codex Plugin/Extension API (as of mid-2026)** + +### 1. Plugin Registration & Discovery + +**Manifest format**: JSON (required) + +- Required file: `/.codex-plugin/plugin.json` +- Also supports legacy `.claude-plugin/plugin.json` +- **Config format**: **JSON** (manifest) + **TOML** (config.toml / requirements.toml) + **JSON** (hooks.json) + +**Key files/locations** (from `codex-rs/core-plugins/src/loader.rs` and official docs): + +- **Plugin manifest**: `.codex-plugin/plugin.json` +- **Bundled hooks** (default): `hooks/hooks.json` (or `hooks/` dir) +- **Skills**: `skills/` directory containing `SKILL.md` files +- **MCP servers**: `.mcp.json` at plugin root +- **Apps**: `.app.json` at plugin root +- **Marketplace registration**: `~/.agents/plugins/marketplace.json` or `/.agents/plugins/marketplace.json` + +**Evidence**: +- [Plugin creator skill](https://github.com/openai/codex/blob/main/codex-rs/skills/src/assets/samples/plugin-creator/SKILL.md) +- [Manifest parser](https://github.com/openai/codex/blob/35aaa5d9/codex-rs/core-plugins/src/manifest.rs) +- [Plugin loader (hooks support)](https://github.com/openai/codex/blob/35aaa5d9/codex-rs/core-plugins/src/loader.rs) + +**Official docs**: +- https://developers.openai.com/codex/plugins/build +- https://developers.openai.com/codex/hooks + +### 2. Plugin Manifest Structure (plugin.json) + +```json +{ + "name": "oh-my-openagent-adapter", + "version": "0.1.0", + "description": "oh-my-openagent integration for Codex", + "skills": "./skills/", + "hooks": "./hooks/hooks.json", + "mcpServers": "./.mcp.json", + "apps": "./.app.json", + "interface": { + "displayName": "Oh My OpenAgent Adapter", + "shortDescription": "Telemetry, rules, AGENTS.md, and agent orchestration", + "category": "Developer Tools", + "capabilities": ["Read", "Write"], + "defaultPrompt": ["Use oh-my-openagent capabilities..."] + } +} +``` + +**Hooks in manifest** can be: +- String path (`"./hooks/hooks.json"`) +- Array of paths +- Inline hook object(s) + +**Evidence**: [`load_plugin_hooks()`](https://github.com/openai/codex/blob/35aaa5d9/codex-rs/core-plugins/src/loader.rs#L100-L160) and official build docs. + +### 3. Lifecycle Hooks (the main extensibility surface) + +Codex uses a **hook system** very similar to OpenCode. + +**Supported events** (from PRs #18893, #19705, #19905): +- `session_start` +- `user_prompt_submit` +- `pre_tool_use` +- `permission_request` +- `post_tool_use` +- `stop` +- `pre_compact`, `post_compact` (newer) + +**Hook config** (`hooks.json` or inline in `config.toml` / `requirements.toml`): + +Hooks are discovered from multiple layers (in order): +1. Managed/requirements.toml (enterprise) +2. User `~/.codex/hooks.json` + `~/.codex/config.toml` +3. Project `/.codex/hooks.json` + `/.codex/config.toml` +4. **Plugin-bundled hooks** (when `plugin_hooks` feature enabled) + +**Plugin hooks** are marked `HookSource::Plugin` and receive `PLUGIN_ROOT` / `PLUGIN_DATA` (and Claude-compatible `CLAUDE_*`) env vars. + +**Evidence**: +- https://github.com/openai/codex/pull/19705 ("Discover hooks bundled with plugins") +- https://github.com/openai/codex/pull/18893 (TOML support) +- https://developers.openai.com/codex/hooks + +### 4. Equivalent of OpenCode's "agent definition" + +- Codex uses **Skills** (`SKILL.md` with YAML frontmatter) as the primary "agent-like" reusable capability. +- Plugins bundle multiple skills. +- There is also mention of "external agents" and marketplace-driven agent-like behavior. +- No direct 1:1 "agent definition file" like OpenCode's agent factories — the closest is a **plugin** that ships skills + hooks + MCP. + +### 5. Rules / System Prompts / AGENTS.md + +- **AGENTS.md** is **natively supported** and documented in the core prompt. +- Codex walks up the directory tree and includes relevant `AGENTS.md` files (root + ancestors). +- There is an open issue requesting **nested/dynamic** `AGENTS.md` loading (like Claude Code). +- Rules are primarily delivered via `AGENTS.md` + hooks + skills. + +**Evidence**: https://github.com/openai/codex/blob/main/codex-rs/core/prompt.md (section "# AGENTS.md spec") + +### 6. SDK / Plugin Trait for Third Parties + +- **Primary way**: Create a directory with `.codex-plugin/plugin.json` + components. No Rust trait required for basic plugins. +- There is a **Codex SDK** (Elixir/Erlang `codex_sdk` on Hex — `Codex.Plugins.Manifest`) used by some tooling. +- The Rust side (`codex-rs/core-plugins`, `codex-rs/hooks`) is internal but the manifest format and `hooks.json` schema are stable. +- No public TypeScript SDK found for writing Codex plugins (the CLI itself has some TS components, but plugins are file-based). + +**Rust core**: +- `codex-rs/core-plugins/src/manifest.rs` +- `codex-rs/core-plugins/src/loader.rs` +- `codex-rs/hooks/src/engine/discovery.rs` + +### 7. Community / Sibling Projects + +- `oh-my-codex` and `codex-plugins` (mentioned in your context) likely follow the exact `.codex-plugin/plugin.json` + `hooks/` pattern. +- The official `@plugin-creator` skill (bundled in Codex) is the canonical way to bootstrap. + +### Summary for Your Adapter (`oh-my-openagent` → Codex) + +You should build a **Codex Plugin** that: +1. Ships as a directory with `.codex-plugin/plugin.json` +2. Provides skills that wrap oh-my-openagent capabilities +3. Registers **lifecycle hooks** (especially `session_start`, `pre_tool_use`, `user_prompt_submit`) to inject rules, AGENTS.md context, telemetry, etc. +4. Uses the standard `hooks/hooks.json` (or inline in manifest) with `type: "command"` handlers that call into your adapter binary. +5. Registers itself via a local `marketplace.json` for easy discovery. + +**Key permalinks**: +- Plugin manifest loader: https://github.com/openai/codex/blob/main/codex-rs/core-plugins/src/manifest.rs +- Plugin hook discovery: https://github.com/openai/codex/blob/main/codex-rs/core-plugins/src/loader.rs (see `load_plugin_hooks`) +- Official plugin build guide: https://developers.openai.com/codex/plugins/build +- Official hooks guide: https://developers.openai.com/codex/hooks +- AGENTS.md handling: https://github.com/openai/codex/blob/main/codex-rs/core/prompt.md +- Plugin creator skill (canonical example): https://github.com/openai/codex/blob/main/codex-rs/skills/src/assets/samples/plugin-creator/SKILL.md + +This gives you a clean path to port oh-my-openagent's rules injection, AGENTS.md walking, telemetry, and agent orchestration as a first-class Codex plugin using the native hook + skill system. +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/notepad.md" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/notepad.md +file + +1: # Ultrawork Notepad +2: +3: ## Status +4: - 2026-05-18 15:23 KST: Started whole-code AI slop and strict TypeScript cleanup across `codex-rules`, `codex-comment-checker`, `codex-lsp`, and nested `lsp-tools-mcp`. +5: - 2026-05-18 15:28 KST: Baseline tests/builds are green for all package roots. +6: - 2026-05-18 15:34 KST: Scope expanded to strict TypeScript configs and code across the whole TypeScript surface. +7: - 2026-05-18 16:03 KST: Strict TypeScript, slop cleanup, build/test optimization, runtime benchmark verification, package smoke, and manual hook/MCP smoke are green locally. +8: - 2026-05-18 16:10 KST: Found and fixed one config-loader regression risk: invalid LSP config entries now skip only themselves and preserve valid sibling entries. +9: - 2026-05-18 16:19 KST: Commits pushed, eligible branches merged to `main`, local install completed, and all git roots are clean on `main...origin/main`. +10: - 2026-05-18 16:39 KST: Final completion audit reran checks, tests, package smoke, strict scans, LSP diagnostics, trust-state inspection, benchmark, and git cleanliness checks. A verifier-triggered generated `lsp-tools-mcp/dist/` directory was removed; all four git roots are clean again. +11: +12: ## Findings +13: - Workspace root is not a Git repo. Git roots are: +14: - `plugins/codex-rules` +15: - `plugins/codex-comment-checker` +16: - `plugins/codex-lsp` +17: - `plugins/codex-lsp/packages/lsp-tools-mcp` +18: - Baseline `codex-rules`: +19: - Test: 50 passed, Vitest duration 1.18s, wall real 2.08s. +20: - Build: passed, wall real 2.70s. +21: - Lint: passed, wall real 0.76s. +22: - Typecheck: passed, wall real 2.38s. +23: - Bench: duplicate-targets median 9.356ms, distinct-targets median 106.404ms, repeat hook fast path median 10.907ms, wall real 28.04s. +24: - Baseline `codex-comment-checker`: +25: - Test: 17 passed, Vitest duration 1.10s, wall real 2.53s. +26: - Build: passed, wall real 1.22s. +27: - Lint: passed, wall real 0.65s. +28: - Typecheck: passed, wall real 1.79s. +29: - Baseline `codex-lsp`: +30: - Test: 7 passed, Vitest duration 1.37s, wall real 4.47s. +31: - Build: passed, wall real 2.16s. +32: - Lint: passed, wall real 0.70s. +33: - Typecheck: passed, wall real 1.64s. +34: - Baseline `lsp-tools-mcp`: +35: - Test: 22 passed, Vitest duration 0.622s, wall real 1.67s. +36: - Build: passed, wall real 2.25s. +37: - Lint: passed, wall real 0.56s. +38: - Typecheck: passed, wall real 2.99s. +39: - High-confidence cleanup targets: +40: - `test/package-smoke.test.ts` files use broad JSON casts. +41: - `lsp-tools-mcp/src/lsp/formatters.ts` allocates a severity map per call. +42: - `lsp-tools-mcp/src/lsp/utils.ts` exports unreferenced `shorten`. +43: - TS configs miss `exactOptionalPropertyTypes`, `verbatimModuleSyntax`, and `noPropertyAccessFromIndexSignature`. +44: - Biome configs explicitly disable `noNonNullAssertion` and do not enforce `noDefaultExport` as an error. +45: +46: ## Problems +47: - `plugins/codex-rules` was behind upstream by one commit. Resolved with stash, `git pull --ff-only`, and stash pop before committing. +48: - `plugins/codex-lsp/packages/lsp-tools-mcp` started detached. It was moved through branch `slop-typescript-cleanup`, pushed, merged into `main`, and the parent `codex-lsp` submodule pointer now tracks the merged `main` commit. +49: - Vitest config files require default export shape, so strict default-export policy needs a narrow config-file exception rather than weakening source/test rules. +50: - Build output previously emitted source maps and declaration maps for CLI packages. That slowed build and left stale packaged files after map emit was removed. +51: +52: ## Improvements +53: - Harden TypeScript configs with: +54: - `exactOptionalPropertyTypes` +55: - `verbatimModuleSyntax` +56: - `noPropertyAccessFromIndexSignature` +57: - Harden Biome configs with: +58: - `style.noNonNullAssertion = error` +59: - `style.noDefaultExport = error` +60: - `style.noEnum = error` +61: - `style.useImportType = error` +62: - `suspicious.noTsIgnore = error` +63: - Replace broad JSON casts in smoke tests with local `unknown` parsing and narrowing helpers. +64: - Preserve config-loader behavior for mixed-validity LSP config files; invalid entries are skipped without discarding valid siblings. +65: - Hoist immutable severity lookup out of `filterDiagnosticsBySeverity`. +66: - Remove unused `shorten` after `rg` and LSP reference checks confirmed no in-repo use. +67: - Use Vitest `threads` pool for these small Node packages while preserving file isolation. +68: - Keep declarations but disable `sourceMap` and `declarationMap` in build configs; remove tracked stale `dist/*.map` files from packaged plugin roots. +69: +70: ## Exceptions +71: - Runtime stays Node/npm, not Bun/pnpm, because each repo `AGENTS.md` and package metadata explicitly require Node and npm. +72: - Vitest config default exports are framework configuration shape; they should be lint-exempt only for `vitest.config.ts`. +73: - Boundary guards around hook, JSON, MCP, and config input stay intentionally defensive because they parse external input. +74: +75: ## Verification +76: - Baseline green before edits: +77: - `npm test` +78: - `npm run build` +79: - `npm run lint` +80: - `npm run typecheck` +81: - Post-change `codex-rules`: +82: - Typecheck: passed, wall real 0.92s (baseline 2.38s). +83: - Lint: passed, wall real 0.31s (baseline 0.76s). +84: - Test: 50 passed, Vitest duration 0.695s, wall real 1.16s (baseline 2.08s). +85: - Build: passed, wall real 0.69s (baseline 2.70s). +86: - Check: passed, wall real 2.72s. +87: - Bench: duplicate-targets median 5.067ms (baseline 9.356ms), distinct-targets median 45.388ms (baseline 106.404ms), repeat hook fast path median 6.482ms (baseline 10.907ms), wall real 8.91s (baseline 28.04s). +88: - Pack: passed, package size 24.2 kB. +89: - Post-change `codex-comment-checker`: +90: - Typecheck: passed, wall real 0.82s (baseline 1.79s). +91: - Lint: passed, wall real 0.26s (baseline 0.65s). +92: - Test: 17 passed, Vitest duration 0.363s, wall real 0.96s (baseline 2.53s). +93: - Build: passed, wall real 0.84s (baseline 1.22s). +94: - Check: passed, wall real 2.49s. +95: - Pack: passed, package size 9.0 kB. +96: - Post-change `codex-lsp`: +97: - Typecheck: passed, wall real 0.76s (baseline 1.64s). +98: - Lint: passed, wall real 0.70s (baseline 0.70s). +99: - Test: 7 passed, Vitest duration 0.644s, wall real 1.88s (baseline 4.47s). +100: - Build: passed, wall real 1.09s (baseline 2.16s). +101: - Check: passed, wall real 1.78s. +102: - Pack: passed, package size 6.9 kB. +103: - Post-change `lsp-tools-mcp`: +104: - Typecheck: passed, wall real 1.35s (baseline 2.99s). +105: - Lint: passed, wall real 0.68s (baseline 0.56s; run variance, Biome still checked in 62ms). +106: - Test: 25 passed, Vitest duration 0.503s, wall real 1.45s (baseline 1.67s). +107: - Build: passed, wall real 1.54s (baseline 2.25s). +108: - Check: passed, wall real 2.27s. +109: - Pack: passed, package size 31.0 kB after stale map cleanup; prior local pack with stale maps was 54.8 kB. +110: - Final audit rerun: +111: - `npm run check`: passed for `codex-rules`, `codex-comment-checker`, `codex-lsp`, and `lsp-tools-mcp`. +112: - `npm test`: passed for `codex-rules` (50), `codex-comment-checker` (17), `codex-lsp` (7), and `lsp-tools-mcp` (25). +113: - `npm pack --dry-run`: passed for all four package roots. +114: - `codex-rules` bench still beats baseline: duplicate-targets median 6.256ms, distinct-targets median 56.835583ms, repeat hook fast path median 6.202125ms. +115: - Strict scans still find no non-dist TypeScript `as any`, `as unknown`, `@ts-ignore`, `@ts-expect-error`, `: any`, `Promise`, TypeScript enum declarations, non-null assertions, debug logging, empty catch blocks, or stale source maps. +116: - LSP diagnostics are error-free for the package roots and representative `codex-comment-checker` TypeScript files. +117: - `~/.codex/config.toml` now explicitly trusts the four package roots and has matching hook `trusted_hash` entries for installed plugin hooks. +118: - After cleaning generated `lsp-tools-mcp/dist/`, all four git roots are clean on `main...origin/main`. +119: - Manual smoke: +120: - `codex-rules` SessionStart emitted AGENTS.md context from a temp project. +121: - `codex-rules` PostToolUse emitted dynamic `.sisyphus/rules` context for a matching `.ts` file. +122: - `codex-comment-checker` PostToolUse fixture exited 0. +123: - `codex-lsp` PostToolUse fixture blocked on basedpyright diagnostics as expected. +124: - `lsp-tools-mcp` stdio MCP handled `initialize`, `tools/list`, and `tools/call status`. +125: - Strict scans: +126: - `rg` banned-pattern scan found no source/test `as any`, `as unknown`, `@ts-ignore`, `@ts-expect-error`, non-null assertions, or TypeScript enum declarations. +127: - Remaining textual hits are Vitest-required default config exports and JSON Schema `enum` property names. +128: - LSP diagnostics reported no errors for representative changed TypeScript files. +129: - Scenario notes: `/var/folders/nj/hqfr8ndn5q56cqw7jqgbrck40000gn/T/ulw-scenarios.XXXXXX.md.5XneJ2JJNY`. +130: - Pending: +131: - None. +132: +133: ## Commits +134: - `plugins/codex-lsp/packages/lsp-tools-mcp` +135: - `f6cb214 refactor(types): satisfy strict LSP MCP checks` +136: - `28543a6 perf(lsp): trim diagnostic and build overhead` +137: - `fb344a0 Merge remote-tracking branch 'origin/main' into slop-typescript-cleanup` +138: - `plugins/codex-lsp` +139: - `9f20eb8 refactor(types): harden codex-lsp plugin` +140: - `424f8ad chore(lsp): track merged LSP MCP main` +141: - `plugins/codex-comment-checker` +142: - `0b47e64 refactor(types): harden comment checker plugin` +143: - `plugins/codex-rules` +144: - `72dbad0 refactor(types): harden codex rules plugin` +145: +146: ## Pushes +147: - Pushed `lsp-tools-mcp` branch `slop-typescript-cleanup`, then merged and pushed `main` to `fb344a0`. +148: - Pushed `codex-lsp` `main` to `424f8ad`. +149: - Pushed `codex-comment-checker` branch `codex-post-hook-support`, then fast-forward merged and pushed `main` to `0b47e64`. +150: - Pushed `codex-rules` branch `codex-post-hook-support`, then fast-forward merged and pushed `main` to `72dbad0`. +151: - Remote branch rules emitted bypass notices for direct `main` pushes, but pushes succeeded. +152: +153: ## Local install +154: - Completed with: +155: - `node /Users/yeongyu/local-workspaces/codex-plugins/scripts/install-local.mjs /Users/yeongyu/local-workspaces/codex-plugins` +156: - Installed cache entries: +157: - `/Users/yeongyu/.codex/plugins/cache/code-yeongyu-codex-plugins/codex-comment-checker/0.1.1` +158: - `/Users/yeongyu/.codex/plugins/cache/code-yeongyu-codex-plugins/codex-rules/0.1.0` +159: - `/Users/yeongyu/.codex/plugins/cache/code-yeongyu-codex-plugins/codex-lsp/0.1.0` +160: - Confirmed `~/.codex/config.toml` has `plugins = true`, `plugin_hooks = true`, marketplace `code-yeongyu-codex-plugins`, and enabled `codex-comment-checker`, `codex-rules`, and `codex-lsp`. +161: - Cleaned source workspace generated nested MCP `dist/` after install; all four git roots are clean on `main...origin/main`. + +(End of file - total 161 lines) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/scripts" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/scripts +directory + +install-local.mjs +install-local.test.mjs +install/ + +(3 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins +directory + +evidence/ +omo/ +plans/ + +(3 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/.agents" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/.agents +directory + +plugins/ + +(1 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/.omo" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/.omo +directory + +run-continuation/ + +(1 entries) + +``` + +--- + +## Assistant (Sisyphus - Ultraworker · Opus 4.7 · 19.4s) + +_Thinking:_ + + I've found 3 key results so far and I'm continuing to dig through the codex-plugins repository while waiting for 4 background tasks to finish. The PostHog integration is particularly interesting—there's a hardcoded API key, just a single event being tracked for daily active users, and it uses a hashed hostname as the identifier, with activity logged to a local state file that only gets written when running the CLI. + +The CLI itself is structured around a shim that delegates to platform-specific binaries, and the package.json has dual bin entries pointing to the same shim without any branching logic. All the installer logic lives in the src/cli/ directory. The Codex plugin system uses a manifest-based approach with plugin.json, hooks.json, skills, MCP, and marketplace.json files—this is already documented officially. + +Now I'm diving into the actual plugins/omo/ directory structure in codex-plugins, which contains several components like comment-checker, rules, lsp, ultrawork, and ultragoal, plus there's an install-local.mjs script that handles installing plugins to the cache directory. Let me examine these more closely. + +수집 완료. 계속 직접 코드를 읽으면서 다른 백그라운드 결과 대기. + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo +directory + +.codex-plugin/ +.mcp.json +components/ +hooks/ +node_modules/ +package-lock.json +package.json +README.md +scripts/ +skills/ +test/ + +(11 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/scripts/install-local.mjs" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/scripts/install-local.mjs +file + +1: #!/usr/bin/env node +2: import { homedir } from "node:os"; +3: import { join, resolve } from "node:path"; +4: import { fileURLToPath } from "node:url"; +5: +6: import { installCachedPlugin, linkCachedPluginBins, pruneMarketplaceCache } from "./install/cache.mjs"; +7: import { updateCodexConfig } from "./install/config.mjs"; +8: import { trustedHookStatesForPlugin } from "./install/hook-trust.mjs"; +9: import { defaultRunCommand } from "./install/process.mjs"; +10: import { +11: readMarketplace, +12: readPluginManifest, +13: resolvePluginSource, +14: validatePathSegment, +15: } from "./install/marketplace.mjs"; +16: +17: export async function installMarketplaceLocally(options = {}) { +18: const repoRoot = resolve(options.repoRoot ?? process.cwd()); +19: const codexHome = resolve(options.codexHome ?? process.env.CODEX_HOME ?? join(homedir(), ".codex")); +20: const binDir = resolve(options.binDir ?? process.env.CODEX_LOCAL_BIN_DIR ?? join(homedir(), ".local", "bin")); +21: const runCommand = options.runCommand ?? defaultRunCommand; +22: const log = options.log ?? console.log; +23: const marketplace = await readMarketplace(repoRoot); +24: const installed = []; +25: +26: for (const entry of marketplace.plugins) { +27: const sourcePath = resolvePluginSource(repoRoot, entry); +28: const manifest = await readPluginManifest(sourcePath); +29: if (manifest.name !== entry.name) { +30: throw new Error( +31: `plugin manifest name ${JSON.stringify(manifest.name)} does not match marketplace name ${JSON.stringify(entry.name)}`, +32: ); +33: } +34: const version = manifest.version ?? "local"; +35: validatePathSegment(version, "plugin version"); +36: +37: log(`Building ${entry.name}@${version}`); +38: const plugin = await installCachedPlugin({ +39: codexHome, +40: marketplaceName: marketplace.name, +41: name: entry.name, +42: runCommand, +43: sourcePath, +44: version, +45: }); +46: const binLinks = await linkCachedPluginBins({ binDir, pluginRoot: plugin.path }); +47: for (const link of binLinks) { +48: log(`Linked ${link.name} -> ${link.target}`); +49: } +50: installed.push(plugin); +51: } +52: +53: const pluginNames = marketplace.plugins.map((plugin) => plugin.name); +54: const trustedHookStates = ( +55: await Promise.all( +56: installed.map((plugin) => +57: trustedHookStatesForPlugin({ +58: marketplaceName: marketplace.name, +59: pluginName: plugin.name, +60: pluginRoot: plugin.path, +61: }), +62: ), +63: ) +64: ).flat(); +65: await pruneMarketplaceCache({ codexHome, marketplaceName: marketplace.name, keepPluginNames: pluginNames }); +66: await updateCodexConfig({ +67: configPath: join(codexHome, "config.toml"), +68: repoRoot, +69: marketplaceName: marketplace.name, +70: pluginNames, +71: trustedHookStates, +72: }); +73: +74: for (const plugin of installed) { +75: log(`Installed ${plugin.name}@${marketplace.name} -> ${plugin.path}`); +76: } +77: +78: return { marketplaceName: marketplace.name, installed }; +79: } +80: +81: async function main() { +82: const repoRoot = process.argv[2] ? resolve(process.argv[2]) : process.cwd(); +83: const result = await installMarketplaceLocally({ repoRoot }); +84: console.log(`Installed ${result.installed.length} plugin(s) from ${result.marketplaceName}.`); +85: } +86: +87: const invokedPath = process.argv[1] ? resolve(process.argv[1]) : ""; +88: if (invokedPath === fileURLToPath(import.meta.url)) { +89: main().catch((error) => { +90: console.error(error instanceof Error ? error.message : error); +91: process.exitCode = 1; +92: }); +93: } + +(End of file - total 93 lines) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/scripts/install" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/scripts/install +directory + +cache.mjs +config.mjs +hook-trust.mjs +marketplace.mjs +process.mjs +utils.mjs + +(6 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/omodex/src/shared/posthog.ts" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/omodex/src/shared/posthog.ts +file + +1: import os from "os" +2: import { createHash } from "node:crypto" +3: import { PostHog } from "posthog-node" +4: import packageJson from "../../package.json" with { type: "json" } +5: import { PLUGIN_NAME, PUBLISHED_PACKAGE_NAME } from "./plugin-identity" +6: import { getPostHogActivityCaptureState } from "./posthog-activity-state" +7: +8: /** @internal test-only seam: keep null in production to use the real implementation. */ +9: let activityStateProviderOverride: typeof getPostHogActivityCaptureState | null = null +10: type OsProvider = Pick +11: let osProviderOverride: OsProvider | null = null +12: +13: function resolveActivityState(): ReturnType { +14: return (activityStateProviderOverride ?? getPostHogActivityCaptureState)() +15: } +16: +17: function resolveOsProvider(): OsProvider { +18: return osProviderOverride ?? os +19: } +20: +21: /** @internal test-only */ +22: export function __setActivityStateProviderForTesting( +23: provider: typeof getPostHogActivityCaptureState, +24: ): void { +25: activityStateProviderOverride = provider +26: } +27: +28: /** @internal test-only */ +29: export function __resetActivityStateProviderForTesting(): void { +30: activityStateProviderOverride = null +31: } +32: +33: /** @internal test-only */ +34: export function __setOsProviderForTesting(provider: OsProvider): void { +35: osProviderOverride = provider +36: } +37: +38: /** @internal test-only */ +39: export function __resetOsProviderForTesting(): void { +40: osProviderOverride = null +41: } +42: +43: const DEFAULT_POSTHOG_HOST = "https://us.i.posthog.com" +44: const DEFAULT_POSTHOG_API_KEY = "phc_CFJhj5HyvA62QPhvyaUCtaq23aUfznnijg5VaaGkNk74" +45: +46: type PostHogCaptureEvent = Parameters[0] +47: type PostHogSource = "cli" | "plugin" +48: type PostHogActivityReason = "run_started" +49: +50: type PostHogClient = { +51: trackActive: (distinctId: string, reason: PostHogActivityReason) => void +52: shutdown: () => Promise +53: } +54: +55: const NO_OP_POSTHOG: PostHogClient = { +56: trackActive: () => undefined, +57: shutdown: async () => undefined, +58: } +59: +60: function isFalsy(value: string | undefined): boolean { +61: return value === "0" || value === "false" || value === "no" +62: } +63: +64: function shouldDisablePostHog(): boolean { +65: if (process.env.OMO_DISABLE_POSTHOG === "true" || process.env.OMO_DISABLE_POSTHOG === "1") { +66: return true +67: } +68: +69: return isFalsy(process.env.OMO_SEND_ANONYMOUS_TELEMETRY?.trim().toLowerCase()) +70: } +71: +72: function hasPostHogApiKey(): boolean { +73: return getPostHogApiKey().length > 0 +74: } +75: +76: function getPostHogApiKey(): string { +77: return process.env.POSTHOG_API_KEY?.trim() || DEFAULT_POSTHOG_API_KEY +78: } +79: +80: function getPostHogHost(): string { +81: return process.env.POSTHOG_HOST?.trim() || DEFAULT_POSTHOG_HOST +82: } +83: +84: function safeCpus(): { length: number; model: string | undefined } { +85: try { +86: const cpus = resolveOsProvider().cpus() +87: return { length: cpus.length, model: cpus[0]?.model } +88: } catch { +89: return { length: 0, model: undefined } +90: } +91: } +92: +93: function getSharedProperties(source: PostHogSource): NonNullable { +94: const cpus = safeCpus() +95: const osProvider = resolveOsProvider() +96: +97: return { +98: platform: "oh-my-opencode", +99: package_name: PUBLISHED_PACKAGE_NAME, +100: plugin_name: PLUGIN_NAME, +101: package_version: packageJson.version, +102: runtime: "bun", +103: runtime_version: process.versions.bun ?? process.version, +104: source, +105: $os: osProvider.platform(), +106: $os_version: osProvider.release(), +107: os_arch: osProvider.arch(), +108: os_type: osProvider.type(), +109: cpu_count: cpus.length, +110: cpu_model: cpus.model, +111: total_memory_gb: Math.round(osProvider.totalmem() / 1024 / 1024 / 1024), +112: locale: Intl.DateTimeFormat().resolvedOptions().locale, +113: timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, +114: shell: process.env.SHELL, +115: ci: Boolean(process.env.CI), +116: terminal: process.env.TERM_PROGRAM, +117: } +118: } +119: +120: function createPostHogClient( +121: source: PostHogSource, +122: options: ConstructorParameters[1], +123: ): PostHogClient { +124: if (shouldDisablePostHog() || !hasPostHogApiKey()) { +125: return NO_OP_POSTHOG +126: } +127: +128: let configuredClient: PostHog +129: +130: try { +131: configuredClient = new PostHog(getPostHogApiKey(), { +132: ...options, +133: host: getPostHogHost(), +134: disableGeoip: false, +135: }) +136: } catch { +137: return NO_OP_POSTHOG +138: } +139: const sharedProperties = getSharedProperties(source) +140: +141: return { +142: trackActive: (distinctId, reason) => { +143: const activityState = resolveActivityState() +144: +145: if (activityState.captureDaily) { +146: configuredClient.capture({ +147: distinctId, +148: event: "omo_daily_active", +149: properties: { +150: ...sharedProperties, +151: $process_person_profile: false, +152: day_utc: activityState.dayUTC, +153: reason, +154: }, +155: }) +156: } +157: }, +158: shutdown: async () => configuredClient.shutdown(), +159: } +160: } +161: +162: export function getPostHogDistinctId(): string { +163: return createHash("sha256") +164: .update(`${PUBLISHED_PACKAGE_NAME}:${resolveOsProvider().hostname()}`) +165: .digest("hex") +166: } +167: +168: export function createCliPostHog(): PostHogClient { +169: return createPostHogClient("cli", { +170: enableExceptionAutocapture: false, +171: enableLocalEvaluation: false, +172: strictLocalEvaluation: true, +173: disableRemoteConfig: true, +174: flushAt: 1, +175: flushInterval: 0, +176: }) +177: } +178: +179: export function createPluginPostHog(): PostHogClient { +180: return createPostHogClient("plugin", { +181: enableExceptionAutocapture: false, +182: enableLocalEvaluation: false, +183: strictLocalEvaluation: true, +184: disableRemoteConfig: true, +185: flushAt: 1, +186: flushInterval: 0, +187: }) +188: } + +(End of file - total 188 lines) + + + +Instructions from: /Users/yeongyu/local-workspaces/omodex/src/shared/AGENTS.md +# src/shared/ — 297 Utility Files (179 non-test) + +**Generated:** 2026-05-20 + +## OVERVIEW + +Cross-cutting utilities used throughout the plugin. Barrel-exported from `index.ts`. Logger writes `oh-my-opencode.log` to the OS temp dir (Node's `os.tmpdir()` — `/tmp` on Linux, `%TEMP%` on Windows, etc.); rotated at 50 MB; up to 2 backups at `.1` / `.2`. Includes runtime shims for `Bun.file`, `Bun.write`, `Bun.hash`, `Bun.which`, `Bun.spawn` to support non-Bun runtimes (Electron-hosted OpenCode). + +## CATEGORY MAP + +| Category | Files | Key Exports | +|----------|-------|-------------| +| **Model Resolution** | ~22 | `resolveModel()`, `checkModelAvailability()`, `AGENT_MODEL_REQUIREMENTS` | +| **Tmux Integration** | 11 | `createTmuxSession()`, `spawnPane()`, `closePane()`, server health | +| **Configuration & Paths** | 10 | `resolveOpenCodeConfigDir()`, `getDataPath()`, `parseJSONC()` | +| **Session Management** | 8 | `SessionCursor`, `trackInjectedPath()`, `SessionToolsStore` | +| **Git Worktree** | 7 | `parseGitStatusPorcelain()`, `collectGitDiffStats()`, `formatFileChanges()` | +| **Command Execution** | 7 | `executeCommand()`, `executeHookCommand()`, embedded command registry | +| **Migration** | 6 | `migrateConfigFile()`, AGENT_NAME_MAP, HOOK_NAME_MAP, MODEL_VERSION_MAP | +| **String & Tool Utils** | 6 | `toSnakeCase()`, `normalizeToolName()`, `parseFrontmatter()` | +| **Agent Configuration** | 5 | `getAgentVariant()`, `AGENT_DISPLAY_NAMES`, `AGENT_TOOL_RESTRICTIONS` | +| **OpenCode Integration** | 5 | `injectServerAuth()`, `detectExternalPlugins()`, client accessors | +| **Type Helpers** | 4 | `deepMerge()`, `DynamicTruncator`, `matchPattern()`, `isRecord()` | +| **Misc** | 8 | `log()`, `readFile()`, `extractZip()`, `downloadBinary()`, `findAvailablePort()` | + +## MODEL RESOLUTION PIPELINE + +``` +resolveModel(input) + 1. Override: UI-selected model (primary agents only) + 2. Category default: From category config + 3. Provider fallback: AGENT_MODEL_REQUIREMENTS chains + 4. System default: Ultimate fallback +``` + +Key files: `model-resolver.ts` (entry), `model-resolution-pipeline.ts` (orchestration), `model-requirements.ts` (fallback chains), `model-availability.ts` (fuzzy matching). + +## MIGRATION SYSTEM + +Automatically transforms legacy config on load: +- `agent-names.ts`: Old agent names → new (e.g., `junior` → `sisyphus-junior`) +- `hook-names.ts`: Old hook names → new +- `model-versions.ts`: Old model IDs → current +- `agent-category.ts`: Legacy agent configs → category system + +## MOST IMPORTED + +| Utility | Import Count | Purpose | +|---------|-------------|---------| +| `logger.ts` | 62 | `oh-my-opencode.log` in `os.tmpdir()` (50 MB cap, rotates to `.1`/`.2`) | +| `data-path.ts` | 11 | XDG storage resolution | +| `model-requirements.ts` | 11 | Agent fallback chains | +| `system-directive.ts` | 11 | System message filtering | +| `frontmatter.ts` | 10 | YAML metadata extraction | + + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/omodex/src/shared/posthog-activity-state.ts" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/omodex/src/shared/posthog-activity-state.ts +file + +1: import { existsSync, mkdirSync, readFileSync } from "node:fs" +2: import { join } from "node:path" +3: +4: import { getDataDir } from "./data-path" +5: import { log } from "./logger" +6: import { CACHE_DIR_NAME } from "./plugin-identity" +7: import { writeFileAtomically } from "./write-file-atomically" +8: +9: type PostHogActivityState = { +10: lastActiveDayUTC?: string +11: } +12: +13: type PostHogActivityCaptureState = { +14: dayUTC: string +15: captureDaily: boolean +16: } +17: +18: const POSTHOG_ACTIVITY_STATE_FILE = "posthog-activity.json" +19: +20: function getPostHogActivityStateFilePath(): string { +21: return join(getDataDir(), CACHE_DIR_NAME, POSTHOG_ACTIVITY_STATE_FILE) +22: } +23: +24: function getUtcDayString(date: Date): string { +25: return date.toISOString().slice(0, 10) +26: } +27: +28: function isPostHogActivityState(value: unknown): value is PostHogActivityState { +29: return value !== null && typeof value === "object" && !Array.isArray(value) +30: } +31: +32: function readPostHogActivityState(): PostHogActivityState { +33: const stateFilePath = getPostHogActivityStateFilePath() +34: if (!existsSync(stateFilePath)) { +35: return {} +36: } +37: +38: try { +39: const content = readFileSync(stateFilePath, "utf-8") +40: const parsed: unknown = JSON.parse(content) +41: if (!isPostHogActivityState(parsed)) { +42: return {} +43: } +44: return parsed +45: } catch (error) { +46: log("[posthog-activity-state] Failed to read activity state", { +47: error: String(error), +48: stateFilePath, +49: }) +50: return {} +51: } +52: } +53: +54: function writePostHogActivityState(nextState: PostHogActivityState): void { +55: const stateFilePath = getPostHogActivityStateFilePath() +56: +57: try { +58: mkdirSync(join(getDataDir(), CACHE_DIR_NAME), { recursive: true }) +59: writeFileAtomically(stateFilePath, `${JSON.stringify(nextState, null, 2)}\n`) +60: } catch (error) { +61: log("[posthog-activity-state] Failed to write activity state", { +62: error: String(error), +63: stateFilePath, +64: }) +65: } +66: } +67: +68: export function getPostHogActivityCaptureState(now: Date = new Date()): PostHogActivityCaptureState { +69: const state = readPostHogActivityState() +70: const dayUTC = getUtcDayString(now) +71: +72: const captureDaily = state.lastActiveDayUTC !== dayUTC +73: +74: if (captureDaily) { +75: writePostHogActivityState({ +76: ...state, +77: lastActiveDayUTC: dayUTC, +78: }) +79: } +80: +81: return { +82: dayUTC, +83: captureDaily, +84: } +85: } + +(End of file - total 85 lines) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/omodex/src/shared/plugin-identity.ts" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/omodex/src/shared/plugin-identity.ts +file + +1: export const PLUGIN_NAME = "oh-my-openagent" +2: export const LEGACY_PLUGIN_NAME = "oh-my-opencode" +3: export const PUBLISHED_PACKAGE_NAME = LEGACY_PLUGIN_NAME +4: export const ACCEPTED_PACKAGE_NAMES = [PUBLISHED_PACKAGE_NAME, PLUGIN_NAME] as const +5: export const CONFIG_BASENAME = "oh-my-openagent" +6: export const LEGACY_CONFIG_BASENAME = "oh-my-opencode" +7: export const LOG_FILENAME = "oh-my-opencode.log" +8: export const CACHE_DIR_NAME = "oh-my-opencode" + +(End of file - total 8 lines) + +``` + +--- + +## Assistant (Sisyphus - Ultraworker · Opus 4.7 · 13.6s) + +_Thinking:_ + + Now I'm diving into the codex-plugins directory structure and examining the key installation files to understand how the plugins are organized and configured. + +핵심 텔레메트리 코드 확인 완료. 이제 codex-plugins/omo 구조 + 마켓플레이스 매니페스트 확인. + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/package.json" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/package.json +file + +1: { +2: "name": "@code-yeongyu/omo-codex-plugin", +3: "version": "0.1.0", +4: "description": "Aggregate Codex plugin root for OMO components.", +5: "type": "module", +6: "packageManager": "npm@11.12.1", +7: "private": true, +8: "workspaces": [ +9: "components/comment-checker", +10: "components/rules", +11: "components/lsp", +12: "components/lsp/packages/lsp-tools-mcp", +13: "components/ultragoal", +14: "components/ultrawork" +15: ], +16: "scripts": { +17: "build": "node scripts/sync-skills.mjs && npm run build --workspaces --if-present", +18: "check": "npm run build && npm test", +19: "sync:skills": "node scripts/sync-skills.mjs", +20: "test": "node --test test/*.test.mjs" +21: } +22: } + +(End of file - total 22 lines) + + +[Project README: /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/README.md] +# omo + +`omo` is the single local Codex plugin namespace for Yeongyu's Codex components. + +Internally each component remains isolated under `components/`: + +- `components/comment-checker` +- `components/rules` +- `components/lsp` +- `components/ultrawork` +- `components/ultragoal` + +The root plugin manifest exports one Codex plugin named `omo`, with aggregate hooks, skills, and the LSP MCP server. + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/README.md" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/README.md +file + +1: # omo +2: +3: `omo` is the single local Codex plugin namespace for Yeongyu's Codex components. +4: +5: Internally each component remains isolated under `components/`: +6: +7: - `components/comment-checker` +8: - `components/rules` +9: - `components/lsp` +10: - `components/ultrawork` +11: - `components/ultragoal` +12: +13: The root plugin manifest exports one Codex plugin named `omo`, with aggregate hooks, skills, and the LSP MCP server. + +(End of file - total 13 lines) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/.codex-plugin" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/.codex-plugin +directory + +plugin.json + +(1 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components +directory + +comment-checker/ +lsp/ +rules/ +ultragoal/ +ultrawork/ + +(5 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/hooks" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/hooks +directory + +hooks.json + +(1 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/skills" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/skills +directory + +comment-checker/ +lsp/ +rules/ +ultragoal/ + +(4 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/marketplace.mjs" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/marketplace.mjs +file + +1: import { readFile } from "node:fs/promises"; +2: import { join } from "node:path"; +3: +4: import { isRecord } from "./utils.mjs"; +5: +6: const MARKETPLACE_PATH = ".agents/plugins/marketplace.json"; +7: +8: export async function readMarketplace(repoRoot) { +9: const marketplacePath = join(repoRoot, MARKETPLACE_PATH); +10: const raw = await readFile(marketplacePath, "utf8"); +11: const parsed = JSON.parse(raw); +12: if (!isRecord(parsed)) throw new Error("marketplace.json must be an object"); +13: if (typeof parsed.name !== "string" || parsed.name.trim() === "") { +14: throw new Error("marketplace.json name must be a non-empty string"); +15: } +16: validatePathSegment(parsed.name, "marketplace name"); +17: if (!Array.isArray(parsed.plugins)) throw new Error("marketplace.json plugins must be an array"); +18: +19: return { +20: name: parsed.name, +21: plugins: parsed.plugins.map((plugin, index) => normalizeMarketplacePlugin(plugin, index)), +22: }; +23: } +24: +25: export function resolvePluginSource(repoRoot, plugin) { +26: const sourcePath = localSourcePath(plugin.source); +27: const relativePath = sourcePath.slice(2); +28: return join(repoRoot, ...relativePath.split(/[\\/]/)); +29: } +30: +31: export async function readPluginManifest(pluginRoot) { +32: const raw = await readFile(join(pluginRoot, ".codex-plugin", "plugin.json"), "utf8"); +33: const parsed = JSON.parse(raw); +34: if (!isRecord(parsed)) throw new Error(`${pluginRoot} plugin.json must be an object`); +35: if (typeof parsed.name !== "string" || parsed.name.trim() === "") { +36: throw new Error(`${pluginRoot} plugin.json name must be a non-empty string`); +37: } +38: const manifest = { name: parsed.name }; +39: if (parsed.version !== undefined) { +40: if (typeof parsed.version !== "string" || parsed.version.trim() === "") { +41: throw new Error(`${pluginRoot} plugin.json version must be a non-empty string`); +42: } +43: manifest.version = parsed.version.trim(); +44: } +45: return manifest; +46: } +47: +48: export function validatePathSegment(value, label) { +49: if (!/^[A-Za-z0-9._+-]+$/.test(value)) { +50: throw new Error(`${label} contains unsupported characters: ${value}`); +51: } +52: if (value === "." || value === "..") { +53: throw new Error(`${label} must not be a path traversal segment`); +54: } +55: } +56: +57: function normalizeMarketplacePlugin(plugin, index) { +58: if (!isRecord(plugin)) throw new Error(`marketplace plugin ${index} must be an object`); +59: if (typeof plugin.name !== "string" || plugin.name.trim() === "") { +60: throw new Error(`marketplace plugin ${index} name must be a non-empty string`); +61: } +62: validatePathSegment(plugin.name, "plugin name"); +63: return { +64: name: plugin.name, +65: source: plugin.source, +66: }; +67: } +68: +69: function localSourcePath(source) { +70: if (typeof source === "string") return validateLocalSourcePath(source); +71: if ( +72: isRecord(source) && +73: source.source === "local" && +74: typeof source.path === "string" +75: ) { +76: return validateLocalSourcePath(source.path); +77: } +78: throw new Error("local plugin source must be a string path or { source: \"local\", path } object"); +79: } +80: +81: function validateLocalSourcePath(path) { +82: if (!path.startsWith("./")) { +83: throw new Error("local plugin source path must start with ./"); +84: } +85: const relative = path.slice(2); +86: if (relative.length === 0) throw new Error("local plugin source path must not be empty"); +87: for (const part of relative.split(/[\\/]/)) { +88: if (part === "" || part === "." || part === "..") { +89: throw new Error("local plugin source path must stay within the marketplace root"); +90: } +91: } +92: return path; +93: } + +(End of file - total 93 lines) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/cache.mjs" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/cache.mjs +file + +1: import { basename, dirname, join, sep } from "node:path"; +2: import { cp, lstat, mkdir, readFile, readdir, readlink, rename, rm, symlink, writeFile } from "node:fs/promises"; +3: +4: import { exists, isRecord } from "./utils.mjs"; +5: +6: export async function installCachedPlugin({ codexHome, marketplaceName, name, runCommand, sourcePath, version }) { +7: await maybeRunNpmInstall(sourcePath, runCommand); +8: await maybeRunNpmBuild(sourcePath, runCommand); +9: +10: const targetPath = join(codexHome, "plugins", "cache", marketplaceName, name, version); +11: await replaceDirectory(sourcePath, targetPath, shouldCopyPluginPath); +12: await maybeRunNpmInstall(targetPath, runCommand, ["install", "--omit=dev"]); +13: await rewriteCachedMcpManifest(targetPath); +14: return { name, version, path: targetPath }; +15: } +16: +17: export async function pruneMarketplaceCache({ codexHome, marketplaceName, keepPluginNames }) { +18: const cacheRoot = join(codexHome, "plugins", "cache", marketplaceName); +19: if (!(await exists(cacheRoot))) return; +20: const keep = new Set(keepPluginNames); +21: const entries = await readdir(cacheRoot, { withFileTypes: true }); +22: for (const entry of entries) { +23: if (!entry.isDirectory() || keep.has(entry.name)) continue; +24: await rm(join(cacheRoot, entry.name), { recursive: true, force: true }); +25: } +26: } +27: +28: export async function linkCachedPluginBins({ binDir, pluginRoot }) { +29: const binLinks = await discoverPackageBins(pluginRoot); +30: await mkdir(binDir, { recursive: true }); +31: const linked = []; +32: for (const link of binLinks) { +33: const linkPath = join(binDir, link.name); +34: await replaceSymlink(linkPath, link.target); +35: linked.push({ name: link.name, path: linkPath, target: link.target }); +36: } +37: return linked; +38: } +39: +40: async function maybeRunNpmInstall(cwd, runCommand, args = ["install"]) { +41: if (!(await exists(join(cwd, "package.json")))) return; +42: await runCommand("npm", args, { cwd }); +43: } +44: +45: async function maybeRunNpmBuild(cwd, runCommand) { +46: if (!(await exists(join(cwd, "package.json")))) return; +47: const packageJson = JSON.parse(await readFile(join(cwd, "package.json"), "utf8")); +48: if (!isRecord(packageJson.scripts) || typeof packageJson.scripts.build !== "string") return; +49: await runCommand("npm", ["run", "build"], { cwd }); +50: } +51: +52: async function replaceDirectory(sourcePath, targetPath, filter) { +53: await mkdir(dirname(targetPath), { recursive: true }); +54: const tempPath = join(dirname(targetPath), `.tmp-${basename(targetPath)}-${process.pid}-${Date.now()}`); +55: await rm(tempPath, { recursive: true, force: true }); +56: await cp(sourcePath, tempPath, { +57: recursive: true, +58: filter: (source) => filter(source, sourcePath), +59: }); +60: await rm(targetPath, { recursive: true, force: true }); +61: await rename(tempPath, targetPath); +62: } +63: +64: async function discoverPackageBins(root) { +65: const links = []; +66: await collectPackageBins(root, root, links); +67: return links; +68: } +69: +70: async function collectPackageBins(directory, root, links) { +71: const entries = await readdir(directory, { withFileTypes: true }); +72: const packageJsonPath = join(directory, "package.json"); +73: if (entries.some((entry) => entry.isFile() && entry.name === "package.json")) { +74: await appendPackageBinLinks(packageJsonPath, directory, links); +75: } +76: for (const entry of entries) { +77: if (!entry.isDirectory()) continue; +78: if (entry.name === "node_modules" || entry.name === ".git" || entry.name === "dist") continue; +79: const childPath = join(directory, entry.name); +80: if (!childPath.startsWith(root)) continue; +81: await collectPackageBins(childPath, root, links); +82: } +83: } +84: +85: async function appendPackageBinLinks(packageJsonPath, packageRoot, links) { +86: const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8")); +87: if (!isRecord(packageJson)) return; +88: const bin = packageJson.bin; +89: if (typeof bin === "string" && typeof packageJson.name === "string") { +90: links.push({ name: basename(packageJson.name), target: join(packageRoot, bin) }); +91: return; +92: } +93: if (!isRecord(bin)) return; +94: for (const [name, target] of Object.entries(bin)) { +95: if (typeof target !== "string") continue; +96: links.push({ name, target: join(packageRoot, target) }); +97: } +98: } +99: +100: async function replaceSymlink(linkPath, targetPath) { +101: if (await existingNonSymlink(linkPath)) { +102: throw new Error(`${linkPath} already exists and is not a symlink`); +103: } +104: await rm(linkPath, { force: true }); +105: await symlink(targetPath, linkPath); +106: } +107: +108: async function existingNonSymlink(path) { +109: try { +110: const stat = await lstat(path); +111: if (!stat.isSymbolicLink()) return true; +112: await readlink(path); +113: return false; +114: } catch (error) { +115: if (error instanceof Error && "code" in error && error.code === "ENOENT") return false; +116: throw error; +117: } +118: } +119: +120: function shouldCopyPluginPath(path, root) { +121: const relative = path === root ? "" : path.slice(root.length + sep.length); +122: if (relative === "") return true; +123: const parts = relative.split(sep); +124: return !parts.some((part) => part === ".git" || part === "node_modules"); +125: } +126: +127: async function rewriteCachedMcpManifest(pluginRoot) { +128: const manifestPath = join(pluginRoot, ".mcp.json"); +129: if (!(await exists(manifestPath))) return; +130: const raw = await readFile(manifestPath, "utf8"); +131: const parsed = JSON.parse(raw); +132: if (!isRecord(parsed) || !isRecord(parsed.mcpServers)) return; +133: let changed = false; +134: for (const server of Object.values(parsed.mcpServers)) { +135: if (!isRecord(server)) continue; +136: if (server.cwd === "." || server.cwd === "./") { +137: delete server.cwd; +138: changed = true; +139: } +140: if (!Array.isArray(server.args)) continue; +141: const nextArgs = server.args.map((arg) => { +142: if (typeof arg !== "string") return arg; +143: if (arg.startsWith("./") || arg.startsWith("../")) return join(pluginRoot, arg); +144: return arg; +145: }); +146: if (nextArgs.some((value, index) => value !== server.args[index])) { +147: server.args = nextArgs; +148: changed = true; +149: } +150: } +151: if (changed) await writeFile(manifestPath, `${JSON.stringify(parsed, null, "\t")}\n`); +152: } + +(End of file - total 152 lines) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/config.mjs" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/config.mjs +file + +1: import { mkdir, readFile, writeFile } from "node:fs/promises"; +2: import { dirname } from "node:path"; +3: +4: import { exists } from "./utils.mjs"; +5: +6: export async function updateCodexConfig({ configPath, repoRoot, marketplaceName, pluginNames, trustedHookStates = [] }) { +7: await mkdir(dirname(configPath), { recursive: true }); +8: let config = ""; +9: if (await exists(configPath)) config = await readFile(configPath, "utf8"); +10: +11: config = removeStaleMarketplacePluginBlocks(config, marketplaceName, new Set(pluginNames)); +12: config = removeStaleMarketplaceHookStateBlocks(config, marketplaceName, new Set(pluginNames)); +13: config = ensureFeatureEnabled(config, "plugins"); +14: config = ensureFeatureEnabled(config, "plugin_hooks"); +15: config = ensureMarketplaceBlock(config, marketplaceName, repoRoot); +16: for (const pluginName of pluginNames) { +17: config = ensurePluginEnabled(config, `${pluginName}@${marketplaceName}`); +18: } +19: for (const state of trustedHookStates) { +20: config = ensureHookTrusted(config, state.key, state.trustedHash); +21: } +22: +23: await writeFile(configPath, config.trimEnd() + "\n"); +24: } +25: +26: function removeStaleMarketplacePluginBlocks(config, marketplaceName, keepPluginNames) { +27: return removeTomlSections(config, (header) => { +28: const pluginKey = parseQuotedPluginHeader(header); +29: if (pluginKey === null) return false; +30: const suffix = `@${marketplaceName}`; +31: if (!pluginKey.endsWith(suffix)) return false; +32: return !keepPluginNames.has(pluginKey.slice(0, -suffix.length)); +33: }); +34: } +35: +36: function removeStaleMarketplaceHookStateBlocks(config, marketplaceName, keepPluginNames) { +37: return removeTomlSections(config, (header) => { +38: const prefix = "hooks.state."; +39: if (!header.startsWith(prefix)) return false; +40: const hookKey = parseJsonString(header.slice(prefix.length)); +41: if (hookKey === null) return false; +42: const separator = hookKey.indexOf(":"); +43: if (separator === -1) return false; +44: const pluginKey = hookKey.slice(0, separator); +45: const suffix = `@${marketplaceName}`; +46: if (!pluginKey.endsWith(suffix)) return false; +47: return !keepPluginNames.has(pluginKey.slice(0, -suffix.length)); +48: }); +49: } +50: +51: function ensureFeatureEnabled(config, featureName) { +52: const section = findTomlSection(config, "features"); +53: if (!section) return appendBlock(config, `[features]\n${featureName} = true\n`); +54: return replaceOrInsertSetting(config, section, featureName, "true"); +55: } +56: +57: function ensureMarketplaceBlock(config, marketplaceName, repoRoot) { +58: const header = `marketplaces.${marketplaceName}`; +59: if (findTomlSection(config, header)) return config; +60: return appendBlock( +61: config, +62: [ +63: `[${header}]`, +64: `last_updated = "${new Date().toISOString().replace(/\.\d{3}Z$/, "Z")}"`, +65: "source_type = \"local\"", +66: `source = ${JSON.stringify(repoRoot)}`, +67: "", +68: ].join("\n"), +69: ); +70: } +71: +72: function ensurePluginEnabled(config, pluginKey) { +73: const header = `plugins.${JSON.stringify(pluginKey)}`; +74: const section = findTomlSection(config, header); +75: if (!section) return appendBlock(config, `[${header}]\nenabled = true\n`); +76: return replaceOrInsertSetting(config, section, "enabled", "true"); +77: } +78: +79: function ensureHookTrusted(config, key, trustedHash) { +80: const header = `hooks.state.${JSON.stringify(key)}`; +81: const section = findTomlSection(config, header); +82: if (!section) return appendBlock(config, `[${header}]\ntrusted_hash = ${JSON.stringify(trustedHash)}\n`); +83: return replaceOrInsertSetting(config, section, "trusted_hash", JSON.stringify(trustedHash)); +84: } +85: +86: function removeTomlSections(config, shouldRemove) { +87: return splitTomlSections(config) +88: .filter((section) => section.header === null || !shouldRemove(section.header)) +89: .map((section) => section.text) +90: .join("") +91: .replace(/\n{3,}/g, "\n\n"); +92: } +93: +94: function splitTomlSections(config) { +95: const lines = config.match(/[^\n]*\n?|$/g) ?? []; +96: const sections = []; +97: let current = { header: null, text: "" }; +98: for (const line of lines) { +99: if (line.length === 0) break; +100: const header = parseTomlHeader(line); +101: if (header !== null) { +102: if (current.text.length > 0) sections.push(current); +103: current = { header, text: line }; +104: } else { +105: current.text += line; +106: } +107: } +108: if (current.text.length > 0) sections.push(current); +109: return sections; +110: } +111: +112: function findTomlSection(config, header) { +113: const headerLine = `[${header}]`; +114: const lines = config.match(/[^\n]*\n?|$/g) ?? []; +115: let offset = 0; +116: let start = -1; +117: for (const line of lines) { +118: if (line.length === 0) break; +119: const trimmed = line.trim(); +120: if (start === -1) { +121: if (trimmed === headerLine) start = offset; +122: } else if (trimmed.startsWith("[") && trimmed.endsWith("]")) { +123: return { start, end: offset, text: config.slice(start, offset) }; +124: } +125: offset += line.length; +126: } +127: if (start === -1) return null; +128: return { start, end: config.length, text: config.slice(start) }; +129: } +130: +131: function replaceOrInsertSetting(config, section, key, value) { +132: const linePattern = new RegExp(`^${escapeRegExp(key)}\\s*=.*$`, "m"); +133: const replacement = linePattern.test(section.text) +134: ? section.text.replace(linePattern, `${key} = ${value}`) +135: : insertSetting(section.text, key, value); +136: return config.slice(0, section.start) + replacement + config.slice(section.end); +137: } +138: +139: function insertSetting(sectionText, key, value) { +140: const lines = sectionText.split("\n"); +141: lines.splice(1, 0, `${key} = ${value}`); +142: return lines.join("\n"); +143: } +144: +145: function parseTomlHeader(line) { +146: const trimmed = line.trim(); +147: if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) return null; +148: if (trimmed.startsWith("[[")) return null; +149: return trimmed.slice(1, -1); +150: } +151: +152: function parseQuotedPluginHeader(header) { +153: const prefix = "plugins."; +154: if (!header.startsWith(prefix)) return null; +155: return parseJsonString(header.slice(prefix.length)); +156: } +157: +158: function parseJsonString(value) { +159: try { +160: const parsed = JSON.parse(value); +161: return typeof parsed === "string" ? parsed : null; +162: } catch { +163: return null; +164: } +165: } +166: +167: function appendBlock(config, block) { +168: const prefix = config.trimEnd(); +169: return `${prefix}${prefix.length > 0 ? "\n\n" : ""}${block.trimEnd()}\n`; +170: } +171: +172: function escapeRegExp(value) { +173: return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +174: } + +(End of file - total 174 lines) + +``` + +--- + +## Assistant (Sisyphus - Ultraworker · Opus 4.7 · 15.9s) + +_Thinking:_ + + I'm getting a clearer sense of the architecture now—the plugin structure under `plugins/omo/`, how the install script pulls from marketplace.json and writes to `~/.codex/`, and that PostHog telemetry only fires during CLI runs. Let me dig into the plugin manifest, hooks configuration, and marketplace setup to understand the full picture. + +핵심 마니페스트 + 마켓플레이스 + 컴포넌트 샘플 확인. + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/.codex-plugin/plugin.json" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/.codex-plugin/plugin.json +file + +1: { +2: "name": "omo", +3: "version": "0.1.0", +4: "description": "One Codex plugin namespace for Yeongyu's local Codex components.", +5: "author": { +6: "name": "Yeongyu Kim", +7: "email": "yeongyu@users.noreply.github.com", +8: "url": "https://github.com/code-yeongyu" +9: }, +10: "homepage": "https://github.com/code-yeongyu/omo", +11: "repository": "https://github.com/code-yeongyu/omo", +12: "license": "MIT", +13: "keywords": ["codex", "codex-plugin", "omo", "hooks", "mcp", "skills"], +14: "skills": "./skills/", +15: "hooks": "./hooks/hooks.json", +16: "mcpServers": "./.mcp.json", +17: "interface": { +18: "displayName": "OMO", +19: "shortDescription": "Unified local Codex components", +20: "longDescription": "OMO exposes the local Codex Rules, Comment Checker, LSP, Ultrawork, and Ultragoal components as one plugin namespace while keeping each component isolated under components/ for maintenance.", +21: "developerName": "Yeongyu Kim", +22: "category": "Developer Tools", +23: "capabilities": ["Hooks", "MCP Tools", "Code Intelligence", "Workflow", "Context Injection"], +24: "websiteURL": "https://github.com/code-yeongyu/omo", +25: "privacyPolicyURL": "https://github.com/code-yeongyu/omo#privacy", +26: "termsOfServiceURL": "https://github.com/code-yeongyu/omo#license", +27: "defaultPrompt": [ +28: "Use OMO LSP diagnostics on this workspace.", +29: "Show which OMO rules matched this file.", +30: "ulw: run this change with evidence." +31: ], +32: "brandColor": "#7C3AED", +33: "screenshots": [] +34: } +35: } + +(End of file - total 35 lines) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/hooks/hooks.json" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/hooks/hooks.json +file + +1: { +2: "hooks": { +3: "SessionStart": [ +4: { +5: "hooks": [ +6: { +7: "type": "command", +8: "command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook session-start", +9: "timeout": 10, +10: "statusMessage": "loading OMO project rules" +11: } +12: ] +13: }, +14: { +15: "hooks": [ +16: { +17: "type": "command", +18: "command": "python3 \"${PLUGIN_ROOT}/components/ultrawork/hooks/sync-agents.py\"", +19: "timeout": 5 +20: } +21: ] +22: } +23: ], +24: "UserPromptSubmit": [ +25: { +26: "hooks": [ +27: { +28: "type": "command", +29: "command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook user-prompt-submit", +30: "timeout": 10, +31: "statusMessage": "loading OMO project rules" +32: } +33: ] +34: }, +35: { +36: "hooks": [ +37: { +38: "type": "command", +39: "command": "python3 \"${PLUGIN_ROOT}/components/ultrawork/hooks/ultrawork-detector.py\"", +40: "timeout": 5 +41: } +42: ] +43: }, +44: { +45: "hooks": [ +46: { +47: "type": "command", +48: "command": "node \"${PLUGIN_ROOT}/components/ultragoal/dist/cli.js\" hook user-prompt-submit", +49: "timeout": 10, +50: "statusMessage": "checking OMO ultragoal steering" +51: } +52: ] +53: } +54: ], +55: "PostToolUse": [ +56: { +57: "matcher": "^(apply_patch|write|Write|edit|Edit|multi_edit|multiedit|MultiEdit)$", +58: "hooks": [ +59: { +60: "type": "command", +61: "command": "node \"${PLUGIN_ROOT}/components/comment-checker/dist/cli.js\" hook post-tool-use", +62: "timeout": 30, +63: "statusMessage": "checking OMO comments" +64: }, +65: { +66: "type": "command", +67: "command": "node \"${PLUGIN_ROOT}/components/lsp/dist/cli.js\" hook post-tool-use", +68: "timeout": 60, +69: "statusMessage": "checking OMO LSP diagnostics" +70: } +71: ] +72: }, +73: { +74: "matcher": "^apply_patch$", +75: "hooks": [ +76: { +77: "type": "command", +78: "command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook post-tool-use", +79: "timeout": 10, +80: "statusMessage": "matching OMO project rules" +81: } +82: ] +83: } +84: ], +85: "PostCompact": [ +86: { +87: "matcher": "manual|auto", +88: "hooks": [ +89: { +90: "type": "command", +91: "command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook post-compact", +92: "timeout": 10, +93: "statusMessage": "resetting OMO project rule cache" +94: } +95: ] +96: } +97: ] +98: } +99: } + +(End of file - total 99 lines) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/.mcp.json" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/.mcp.json +file + +1: { +2: "mcpServers": { +3: "lsp": { +4: "command": "node", +5: "args": ["./components/lsp/packages/lsp-tools-mcp/dist/cli.js", "mcp"], +6: "cwd": "." +7: } +8: } +9: } + +(End of file - total 9 lines) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/.agents/plugins" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/.agents/plugins +directory + +marketplace.json + +(1 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules +directory + +.git/ +.gitattributes +.github/ +.gitignore +AGENTS.md +biome.json +CHANGELOG.md +dist/ +hooks/ +LICENSE +node_modules/ +NOTICE +package-lock.json +package.json +README.md +scripts/ +skills/ +src/ +test/ +tsconfig.build.json +tsconfig.json +vitest.config.ts + +(22 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker +directory + +.git/ +.gitattributes +.github/ +.gitignore +AGENTS.md +biome.json +CHANGELOG.md +dist/ +hooks/ +LICENSE +node_modules/ +NOTICE +package-lock.json +package.json +README.md +skills/ +src/ +test/ +tsconfig.build.json +tsconfig.json +vitest.config.ts + +(21 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork +directory + +.git/ +.gitignore +AGENTS.md +agents/ +CHANGELOG.md +hooks/ +LICENSE +NOTICE +package-lock.json +package.json +README.md + +(11 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal +directory + +.git/ +.gitattributes +.gitignore +AGENTS.md +biome.json +CHANGELOG.md +dist/ +hooks/ +LICENSE +node_modules/ +NOTICE +package-lock.json +package.json +README.md +skills/ +src/ +test/ +tsconfig.build.json +tsconfig.json +vitest.config.ts + +(20 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp +directory + +.git/ +.gitattributes +.github/ +.gitignore +.gitmodules +.mcp.json +AGENTS.md +biome.json +CHANGELOG.md +dist/ +hooks/ +LICENSE +node_modules/ +NOTICE +package-lock.json +package.json +packages/ +README.md +scripts/ +skills/ +src/ +test/ +tsconfig.build.json +tsconfig.json +vitest.config.ts + +(25 entries) + +``` + +--- + +## Assistant (Sisyphus - Ultraworker · Opus 4.7 · 21.2s) + +_Thinking:_ + + I'm looking at the codex-plugins repository structure and realizing each component under `plugins/omo/components/` is actually its own git submodule with separate build artifacts and package configurations. The parent codex-plugins directory itself isn't a git repository, but I need to check the .gitmodules file and marketplace.json to understand how these submodules are configured. + +각 컴포넌트가 별도 git 서브모듈인 점 발견. omodex 쪽 .gitmodules 확인 + marketplace.json + 한 컴포넌트 들여다보기. + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/.agents/plugins/marketplace.json" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/.agents/plugins/marketplace.json +file + +1: { +2: "name": "code-yeongyu-codex-plugins", +3: "interface": { +4: "displayName": "Yeongyu Codex Plugins" +5: }, +6: "plugins": [ +7: { +8: "name": "omo", +9: "source": "./plugins/omo", +10: "category": "Developer Tools", +11: "policy": { +12: "installation": "AVAILABLE", +13: "authentication": "ON_INSTALL" +14: } +15: } +16: ] +17: } + +(End of file - total 17 lines) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/omodex/.gitmodules" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/omodex/.gitmodules +file + +1: [submodule "packages/lsp-tools-mcp"] +2: path = packages/lsp-tools-mcp +3: url = https://github.com/code-yeongyu/lsp-tools-mcp + +(End of file - total 3 lines) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/omodex/.gitignore" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/omodex/.gitignore +file + +1: # Dependencies +2: .omo/* +3: !.omo/rules/ +4: !.omo/rules/** +5: .sisyphus/* +6: !.sisyphus/rules/ +7: !.sisyphus/rules/** +8: node_modules/ +9: +10: # Build output +11: dist/ +12: +13: # Platform binaries (built, not committed) +14: packages/*/bin/oh-my-opencode +15: packages/*/bin/oh-my-opencode.exe +16: packages/*/bin/*.map +17: +18: # IDE +19: .idea/ +20: .vscode/ +21: *.swp +22: *.swo +23: +24: # OS +25: .DS_Store +26: Thumbs.db +27: +28: # Logs +29: *.log +30: npm-debug.log* +31: +32: # Lock files (use bun.lockb instead) +33: package-lock.json +34: yarn.lock +35: +36: # Environment +37: .env +38: .env.local +39: test-injection/ +40: notepad.md +41: oauth-success.html +42: *.bun-build +43: .omx/ +44: .dori-sync/ +45: .dori/ +46: .playwright-mcp/ +47: +48: # Debugging / session artifacts (skill workspace residue) +49: .debugging +50: .debug-journal*.md +51: session-ses_*.md +52: plans/ + +(End of file - total 52 lines) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/package.json" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/package.json +file + +1: { +2: "name": "@code-yeongyu/codex-rules", +3: "version": "0.1.0", +4: "description": "Codex plugin that injects project rule files into model context through lifecycle hooks.", +5: "type": "module", +6: "packageManager": "npm@11.12.1", +7: "license": "MIT", +8: "homepage": "https://github.com/code-yeongyu/codex-rules", +9: "repository": { +10: "type": "git", +11: "url": "git+https://github.com/code-yeongyu/codex-rules.git" +12: }, +13: "bugs": { +14: "url": "https://github.com/code-yeongyu/codex-rules/issues" +15: }, +16: "keywords": [ +17: "codex", +18: "codex-plugin", +19: "rules", +20: "hooks", +21: "agents-md", +22: "context-injection", +23: "typescript" +24: ], +25: "bin": { +26: "codex-rules": "./dist/cli.js" +27: }, +28: "files": [ +29: "dist", +30: "hooks", +31: "skills", +32: ".codex-plugin", +33: "LICENSE", +34: "NOTICE", +35: "README.md", +36: "CHANGELOG.md" +37: ], +38: "scripts": { +39: "build": "tsc -p tsconfig.build.json", +40: "test": "vitest --run", +41: "test:watch": "vitest", +42: "bench": "npm run build --silent && node scripts/bench-codex-rules.mjs", +43: "typecheck": "tsc --noEmit", +44: "lint": "biome check .", +45: "lint:fix": "biome check --write .", +46: "check": "tsc --noEmit && biome check . && npm run build" +47: }, +48: "dependencies": { +49: "picomatch": "^4.0.3" +50: }, +51: "devDependencies": { +52: "@biomejs/biome": "2.4.15", +53: "@types/node": "^25.7.0", +54: "@types/picomatch": "^4.0.0", +55: "typescript": "^6.0.3", +56: "vitest": "^4.1.5" +57: }, +58: "engines": { +59: "node": ">=20.0.0" +60: } +61: } + +(End of file - total 61 lines) + + +[Project README: /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/README.md] +# codex-rules + +Codex plugin that injects local project rule files into model context through lifecycle hooks. + +It ports the `pi-rules` rule injector to Codex: + +- `SessionStart` and `UserPromptSubmit` load static project instructions once per session. +- `PostToolUse` watches Codex `apply_patch` by default, then injects matching file-specific rules as additional context. +- `PostCompact` clears the per-session injection cache after manual or automatic compaction so relevant rules can be reintroduced into the compacted conversation. +- Session-level deduplication prevents the same rule from being repeated after it has been injected. + +`PostToolUse` output is context-only: it emits `hookSpecificOutput.additionalContext` and does not rewrite tool output. + +The runtime has no npm production dependencies, so a clean Codex marketplace copy can run without a follow-up `npm install`. + +## Rule Sources + +Project-level sources: + +- `AGENTS.md` +- `CLAUDE.md` +- `CONTEXT.md` +- `.omo/rules/**/*.md` +- `.claude/rules/**/*.md` +- `.cursor/rules/**/*.md` +- `.github/instructions/**/*.md` +- `.github/copilot-instructions.md` + +User-home sources are also supported by the ported engine when available. + +Markdown rule files may use frontmatter such as: + +```md +--- +description: TypeScript defaults +globs: ["**/*.ts", "**/*.tsx"] +alwaysApply: false +--- + +Prefer strict TypeScript and keep runtime imports ESM-compatible. +``` + +## Install Locally + +From the marketplace workspace: + +```bash +codex plugin marketplace add /Users/yeongyu/local-workspaces/codex-plugins +node /Users/yeongyu/local-workspaces/codex-plugins/scripts/install-local.mjs /Users/yeongyu/local-workspaces/codex-plugins +``` + +The local installer builds the plugin and copies a clean cache entry to: + +```text +~/.codex/plugins/cache/code-yeongyu-codex-plugins/omo/0.1.0 +``` + +It also enables: + +```toml +[features] +plugins = true +plugin_hooks = true + +[plugins."omo@code-yeongyu-codex-plugins"] +enabled = true +``` + +## Configuration + +Use `CODEX_RULES_*` environment variables: + +| Variable | Values | Default | +| --- | --- | --- | +| `CODEX_RULES_DISABLED` | `1`, `true`, `yes`, `on` | unset | +| `CODEX_RULES_MODE` | `both`, `static`, `dynamic`, `off` | `both` | +| `CODEX_RULES_MAX_RULE_CHARS` | positive integer | `12000` | +| `CODEX_RULES_MAX_RESULT_CHARS` | positive integer | `40000` | +| `CODEX_RULES_ENABLED_SOURCES` | comma-separated source names | `auto` | + +For migration from `pi-rules`, equivalent `PI_RULES_*` variables are accepted as fallbacks. + +## Debugging + +Enable hook phase timing with `NODE_DEBUG=codex-rules`: + +```bash +NODE_DEBUG=codex-rules node dist/cli.js hook post-tool-use < fixture.json +``` + +Debug lines go to stderr and hook JSON stays on stdout. The log includes `PostToolUse` phases such as `extract`, `fingerprint`, `load`, `persist`, elapsed `ms`, target counts, pending counts, rule counts, and output bytes. It does not log rule bodies or tool response contents. + +The default `PostToolUse` hook matcher is intentionally strict: it matches only Codex's canonical `apply_patch` hook tool name. Read tools, MCP filesystem tools, shell commands, and Claude-style `Write`/`Edit` aliases are not registered by default. + +## Development + +```bash +npm install +npm test +npm run check +npm run typecheck +npm pack --dry-run +``` + +Performance smoke test: + +```bash +npm run bench +``` + +Benchmark timings depend on the local machine. Use the relative counters and repeat-output checks when comparing runs. + +Hook smoke test: + +```bash +npm run build +printf '%s\n' '{"session_id":"s","transcript_path":null,"cwd":"/path/to/project","hook_event_name":"SessionStart","model":"gpt-5.5","permission_mode":"default","source":"startup"}' \ + | PLUGIN_DATA=/tmp/codex-rules-data node dist/cli.js hook session-start +``` + +## Privacy + +`codex-rules` runs locally. It reads local rule files and Codex hook payloads, writes per-session deduplication state under the Codex plugin data directory, and does not make network requests. + +## License + +MIT. See [LICENSE](LICENSE) and [NOTICE](NOTICE). + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src +directory + +cli.ts +codex-hook.ts +config.ts +debug-log.ts +persistent-cache.ts +rules/ +tool-paths.ts + +(7 entries) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/hooks" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/hooks +directory + +__pycache__/ +hooks.json +sync-agents.py +ultrawork-detector.py +ultrawork-hooks.test.mjs + +(5 entries) + + +[Project README: /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/README.md] +# codex-ultrawork + +Codex plugin that injects a compact orchestration directive (the **ultrawork** prompt) when the user prompt contains `ultrawork` or `ulw` (word-bounded, case-insensitive). It also syncs the bundled `codex-ultrawork-reviewer` agent role into `CODEX_HOME/agents` on `SessionStart`. + +## What the injected directive enforces + +| Mandate | Behavior | +|---|---| +| Goal + binding success criteria | Call `create_goal` (or open with a `# Goal` block) listing the deliverable + **3+ realistic QA scenarios** (happy path, edge cases, adjacent-surface regression). Each scenario's PASS condition is **observable evidence from the real surface** (`tmux` transcript, `curl` status+body, browser screenshot, Playwright assertion, computer-use action log, CLI stdout, parsed config dump, DB state diff). "Tests pass" alone is not evidence. | +| Durable /tmp notepad | `mktemp -t ulw-$(date +%Y%m%d-%H%M%S).XXXXXX.md` with sections `Plan`, `Success criteria + QA scenarios`, `Now`, `Todo`, `Findings`, `Learnings`. **Append**, never rewrite. | +| Obsessive atomic todos | Every action — even one-line edits, `ls`, single test runs — becomes a todo. Format: `path: for — verify by `. One in_progress at a time, mark completed immediately. | +| GPT-5.2 xhigh verification gate | Triggered automatically on user-requested rigor, 3+ files, 20+ turns, 30+ minutes, or refactor/migration/perf/security work. Use the bundled `codex-ultrawork-reviewer` agent role when available. Reviewer verdict is **binding** — no "false positive", no minimising, no arguing. Loop until **unconditional** approval. "Looks good but…" = REJECTION. | + +The directive is currently 5,821 chars (was 7,761) and follows the GPT-5.5 prompting structure (Role / Goal / Bootstrap / Execution loop / Verification gate / Commits / Constraints / Output / Stop rules). + +## Install (via this marketplace) + +```bash +codex plugin marketplace add /path/to/codex-plugins +node /path/to/codex-plugins/scripts/install-local.mjs /path/to/codex-plugins +``` + +The installer copies the plugin into `~/.codex/plugins/cache/code-yeongyu-codex-plugins/omo/0.1.0`, enables it in `~/.codex/config.toml`, and registers the `UserPromptSubmit` and `SessionStart` hooks. + +## How it works + +`hooks/hooks.json` registers a `UserPromptSubmit` hook running: + +``` +python3 ${PLUGIN_ROOT}/hooks/ultrawork-detector.py +``` + +Codex passes the prompt payload on stdin. When the pattern `\b(?:ultrawork|ulw)\b` (case-insensitive) matches, the hook writes the directive to stdout — Codex injects non-JSON stdout as `additional_context` for the next turn. Otherwise the hook writes nothing and exits 0. Malformed input also exits 0 to never block the turn. + +It also registers a `SessionStart` hook running: + +``` +python3 ${PLUGIN_ROOT}/hooks/sync-agents.py +``` + +That hook copies bundled `agents/*.toml` files into `CODEX_HOME/agents`. It writes nothing on success and exits 0 even on malformed input. + +## Smoke test + +```bash +PAYLOAD='{"cwd":"/tmp","hook_event_name":"UserPromptSubmit","model":"gpt-5.5","permission_mode":"default","session_id":"x","transcript_path":"","turn_id":"y","prompt":"please ultrawork"}' +echo "$PAYLOAD" | python3 hooks/ultrawork-detector.py | head -3 +``` + +Expect `` ... directive body. + +## Agent role smoke test + +```bash +CODEX_HOME="$(mktemp -d)" +echo '{"hook_event_name":"SessionStart"}' | CODEX_HOME="$CODEX_HOME" python3 hooks/sync-agents.py +``` + +Expect `CODEX_HOME/agents/codex-ultrawork-reviewer.toml` to exist. + +## License + +MIT. See `LICENSE`. + +## Privacy + +This plugin only reads local hook payloads, emits the bundled directive text on keyword match, and syncs bundled agent TOML files locally. It does not perform network requests or telemetry. + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/agents" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/agents +directory + +codex-ultrawork-reviewer.toml + +(1 entries) + +``` + +**Tool: bash** + +**Input:** +```json +{ + "command": "ls /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/.git /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/.git /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/.git /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/.git /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/.git 2>&1 | head -50", + "description": "Check if components are submodules or independent repos" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/.git: +COMMIT_EDITMSG +config +description +FETCH_HEAD +HEAD +hooks +index +info +logs +MERGE_RR +objects +ORIG_HEAD +refs +rr-cache +worktrees + +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/.git: +COMMIT_EDITMSG +config +description +FETCH_HEAD +HEAD +hooks +index +info +logs +MERGE_RR +modules +objects +ORIG_HEAD +refs +rr-cache +worktrees + +/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/.git: +COMMIT_EDITMSG +config +description +FETCH_HEAD +HEAD +hooks +index +info +logs +MERGE_RR +objects +ORIG_HEAD +refs +rr-cache + +``` + +**Tool: bash** + +**Input:** +```json +{ + "command": "cd /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules && git remote -v 2>&1 | head -5\necho \"---\"\ncd /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker && git remote -v 2>&1 | head -5\necho \"---\"\ncd /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp && git remote -v 2>&1 | head -5\necho \"---\"\ncd /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork && git remote -v 2>&1 | head -5\necho \"---\"\ncd /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal && git remote -v 2>&1 | head -5", + "description": "List remotes of each component repo" +} +``` + +**Output:** +``` +origin https://github.com/code-yeongyu/codex-rules.git (fetch) +origin https://github.com/code-yeongyu/codex-rules.git (push) +--- +origin https://github.com/code-yeongyu/codex-comment-checker.git (fetch) +origin https://github.com/code-yeongyu/codex-comment-checker.git (push) +--- +origin https://github.com/code-yeongyu/codex-lsp.git (fetch) +origin https://github.com/code-yeongyu/codex-lsp.git (push) +--- +origin https://github.com/code-yeongyu/codex-ultrawork.git (fetch) +origin https://github.com/code-yeongyu/codex-ultrawork.git (push) +--- +origin https://github.com/code-yeongyu/codex-ultragoal.git (fetch) +origin https://github.com/code-yeongyu/codex-ultragoal.git (push) + +``` + +--- + +## Assistant (Sisyphus - Ultraworker · Opus 4.7 · 63.5s) + +_Thinking:_ + + So the structure is becoming clearer—codex-plugins is actually a meta-repository housing five completely independent git repositories that are cloned separately rather than linked as submodules, including codex-rules, codex-comment-checker, and codex-lsp, each with their own tech stacks and dependencies. + +The install-local.mjs script orchestrates the build and deployment by reading the marketplace configuration, building each plugin, and then copying them to the local Codex cache while updating the config to enable and trust them. + +For porting this into omodex, Option A makes the most sense—I'll vendor the entire omo plugin directory directly into the omodex packages structure without the nested git directories, then integrate an equivalent installation script into the omodex CLI with a new flag to handle the setup. + +Looking at what the user actually wants: they need the codex-plugins moved into omodex at an appropriate location, an installer configured with the name 'omo' that includes a `--codex` flag, and PostHog telemetry integrated similarly to how omo-codex handles it but with its own event distinction. I'll vendor the plugins, create the installer with the `--codex` option, add the omo bin entry, and set up the telemetry with the same environment variable controls. inguishes by `source` / `platform` property = "omo-codex" + - Toggle for disabling per user's second clarification + +Now I need to wait for the remaining background tasks. Let me check if any have completed. + +Actually it's been a while - the user mentioned 4 tasks still in progress earlier. Let me check what's ready. + +Actually I should make plans concrete. Let me also look at the ultrawork detector and rules CLI to understand how they actually work, since those will need to be wired into the new omo-codex. + +Actually - let me step back. The complexity here is HUGE: +- Each component is its own repo with its own build (tsc → dist/, Python scripts as-is) +- The install-local.mjs reads marketplace.json, copies plugins to ~/.codex/plugins/cache/... +- The codex-plugins repo bundles these as one "omo" plugin namespace + +I have two options: + +**A. Vendor everything into omodex/packages/omo-codex/** +Pros: Self-contained, one PR +Cons: Each component has its own git repo with potentially different licenses, build systems, lifecycles. Big diff. Loses history. + +**B. Add as submodules** +Pros: Preserves upstream connections, lighter diff +Cons: More complex setup, future updates required + +Given the user's roadmap says "Future Pi and Codex adapters will consume the same Core layer" and the goal is to consolidate into omodex, the right approach is to create a thin package that imports core packages from omodex workspaces and bundles its own plugin configuration with CLI entrypoints mirroring the existing binaries, built via bun conventions. But wait, re-reading the user's request more carefully—they're asking me to move codex-plugins into omodex with an omo installer and --codex flag. The simpler path is to vendor codex-plugins as-is into omodex/packages/omo-codex/ with installer logic, since these are functioning, tested components and a full reimplementation would be a much larger refactor than what's being asked for now. I'm settling on a phased approach: vendor the existing omo code as-is for this PR to get it working in omodex, then migrate to using core packages in a follow-up. Let me check the actual file sizes in codex-plugins to see what I'm dealing with, and look at how pi-extensions handles codex installation for reference. + +배경 결과 대기하면서 핵심 구현 디테일 확인. 컴포넌트 크기 + 빌드 산출물 + 기존 인스톨러 검증 패턴 + pi-extensions 비교. + +**Tool: bash** + +**Input:** +```json +{ + "command": "echo \"=== Component sizes (source only, no .git/node_modules/dist) ===\"\nfor dir in /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/*; do\n echo \"--- $(basename \"$dir\") ---\"\n du -sh \"$dir\" 2>/dev/null\n du -sh \"$dir\"/.git 2>/dev/null\n du -sh \"$dir\"/node_modules 2>/dev/null\n du -sh \"$dir\"/dist 2>/dev/null\n echo \"lines of source code:\"\n find \"$dir\" -name '*.ts' -not -path '*/node_modules/*' -not -path '*/dist/*' -not -path '*/.git/*' -exec wc -l {} + 2>/dev/null | tail -1\n find \"$dir\" -name '*.py' -not -path '*/node_modules/*' -not -path '*/dist/*' -not -path '*/.git/*' -exec wc -l {} + 2>/dev/null | tail -1\n echo\ndone\necho \"=== Full codex-plugins (no .git/node_modules) ===\"\ndu -sh --exclude=.git --exclude=node_modules /Users/yeongyu/local-workspaces/codex-plugins/ 2>/dev/null || du -sh /Users/yeongyu/local-workspaces/codex-plugins/", + "description": "Measure sizes of codex-plugins components" +} +``` + +**Output:** +``` +=== Component sizes (source only, no .git/node_modules/dist) === +--- comment-checker --- +111M /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker +1.1M /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/.git +109M /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/node_modules + 48K /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/dist +lines of source code: + 1228 total + +--- lsp --- +112M /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp +2.3M /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/.git +109M /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/node_modules + 20K /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/dist +lines of source code: + 5208 total + 2 total + +--- rules --- +112M /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules +2.3M /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/.git +109M /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/node_modules +204K /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/dist +lines of source code: + 4793 total + +--- ultragoal --- +111M /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal +1.0M /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/.git +110M /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/node_modules +216K /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/dist +lines of source code: + 5839 total + +--- ultrawork --- +384K /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork +300K /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/.git +lines of source code: + 331 total + +=== Full codex-plugins (no .git/node_modules) === +703M /Users/yeongyu/local-workspaces/codex-plugins/ + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/omodex/src/cli/install-validators.ts" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/omodex/src/cli/install-validators.ts +file + +1: import color from "picocolors" +2: import type { +3: BooleanArg, +4: ClaudeSubscription, +5: DetectedConfig, +6: InstallArgs, +7: InstallConfig, +8: } from "./types" +9: +10: export const SYMBOLS = { +11: check: color.green("[OK]"), +12: cross: color.red("[X]"), +13: arrow: color.cyan("->"), +14: bullet: color.dim("*"), +15: info: color.blue("[i]"), +16: warn: color.yellow("[!]"), +17: star: color.yellow("*"), +18: } +19: +20: const ANSI_COLOR_PATTERN = new RegExp("\u001b\\[[0-9;]*m", "g") +21: +22: function formatProvider(name: string, enabled: boolean, detail?: string): string { +23: const status = enabled ? SYMBOLS.check : color.dim("○") +24: const label = enabled ? color.white(name) : color.dim(name) +25: const suffix = detail ? color.dim(` (${detail})`) : "" +26: return ` ${status} ${label}${suffix}` +27: } +28: +29: export function formatConfigSummary(config: InstallConfig): string { +30: const lines: string[] = [] +31: +32: lines.push(color.bold(color.white("Configuration Summary"))) +33: lines.push("") +34: +35: const claudeDetail = config.hasClaude ? (config.isMax20 ? "max20" : "standard") : undefined +36: lines.push(formatProvider("Claude", config.hasClaude, claudeDetail)) +37: lines.push(formatProvider("OpenAI/ChatGPT", config.hasOpenAI, "GPT-5.4 for Oracle")) +38: lines.push(formatProvider("Gemini", config.hasGemini)) +39: lines.push(formatProvider("GitHub Copilot", config.hasCopilot, "fallback")) +40: lines.push(formatProvider("OpenCode Zen", config.hasOpencodeZen, "opencode/ models")) +41: lines.push(formatProvider("Z.ai Coding Plan", config.hasZaiCodingPlan, "Librarian/Multimodal")) +42: lines.push(formatProvider("Kimi For Coding", config.hasKimiForCoding, "Sisyphus/Prometheus fallback")) +43: lines.push(formatProvider("Vercel AI Gateway", config.hasVercelAiGateway, "universal proxy")) +44: +45: lines.push("") +46: lines.push(color.dim("─".repeat(40))) +47: lines.push("") +48: +49: lines.push(color.bold(color.white("Model Assignment"))) +50: lines.push("") +51: lines.push(` ${SYMBOLS.info} Models auto-configured based on provider priority`) +52: lines.push(` ${SYMBOLS.bullet} Priority: Native > Copilot > OpenCode Zen > Z.ai`) +53: +54: return lines.join("\n") +55: } +56: +57: export function printHeader(isUpdate: boolean): void { +58: const mode = isUpdate ? "Update" : "Install" +59: console.log() +60: console.log(color.bgMagenta(color.white(` oMoMoMoMo... ${mode} `))) +61: console.log() +62: } +63: +64: export function printStep(step: number, total: number, message: string): void { +65: const progress = color.dim(`[${step}/${total}]`) +66: console.log(`${progress} ${message}`) +67: } +68: +69: export function printSuccess(message: string): void { +70: console.log(`${SYMBOLS.check} ${message}`) +71: } +72: +73: export function printError(message: string): void { +74: console.log(`${SYMBOLS.cross} ${color.red(message)}`) +75: } +76: +77: export function printInfo(message: string): void { +78: console.log(`${SYMBOLS.info} ${message}`) +79: } +80: +81: export function printWarning(message: string): void { +82: console.log(`${SYMBOLS.warn} ${color.yellow(message)}`) +83: } +84: +85: export function printBox(content: string, title?: string): void { +86: const lines = content.split("\n") +87: const maxWidth = +88: Math.max( +89: ...lines.map((line) => line.replace(ANSI_COLOR_PATTERN, "").length), +90: title?.length ?? 0, +91: ) + 4 +92: const border = color.dim("─".repeat(maxWidth)) +93: +94: console.log() +95: if (title) { +96: console.log( +97: color.dim("┌─") + +98: color.bold(` ${title} `) + +99: color.dim("─".repeat(maxWidth - title.length - 4)) + +100: color.dim("┐"), +101: ) +102: } else { +103: console.log(color.dim("┌") + border + color.dim("┐")) +104: } +105: +106: for (const line of lines) { +107: const stripped = line.replace(ANSI_COLOR_PATTERN, "") +108: const padding = maxWidth - stripped.length +109: console.log(color.dim("│") + ` ${line}${" ".repeat(padding - 1)}` + color.dim("│")) +110: } +111: +112: console.log(color.dim("└") + border + color.dim("┘")) +113: console.log() +114: } +115: +116: export function validateNonTuiArgs(args: InstallArgs): { valid: boolean; errors: string[] } { +117: const errors: string[] = [] +118: +119: if (args.claude === undefined) { +120: errors.push("--claude is required (values: no, yes, max20)") +121: } else if (!["no", "yes", "max20"].includes(args.claude)) { +122: errors.push(`Invalid --claude value: ${args.claude} (expected: no, yes, max20)`) +123: } +124: +125: if (args.gemini === undefined) { +126: errors.push("--gemini is required (values: no, yes)") +127: } else if (!["no", "yes"].includes(args.gemini)) { +128: errors.push(`Invalid --gemini value: ${args.gemini} (expected: no, yes)`) +129: } +130: +131: if (args.copilot === undefined) { +132: errors.push("--copilot is required (values: no, yes)") +133: } else if (!["no", "yes"].includes(args.copilot)) { +134: errors.push(`Invalid --copilot value: ${args.copilot} (expected: no, yes)`) +135: } +136: +137: if (args.openai !== undefined && !["no", "yes"].includes(args.openai)) { +138: errors.push(`Invalid --openai value: ${args.openai} (expected: no, yes)`) +139: } +140: +141: if (args.opencodeGo !== undefined && !["no", "yes"].includes(args.opencodeGo)) { +142: errors.push(`Invalid --opencode-go value: ${args.opencodeGo} (expected: no, yes)`) +143: } +144: +145: if (args.opencodeZen !== undefined && !["no", "yes"].includes(args.opencodeZen)) { +146: errors.push(`Invalid --opencode-zen value: ${args.opencodeZen} (expected: no, yes)`) +147: } +148: +149: if (args.zaiCodingPlan !== undefined && !["no", "yes"].includes(args.zaiCodingPlan)) { +150: errors.push(`Invalid --zai-coding-plan value: ${args.zaiCodingPlan} (expected: no, yes)`) +151: } +152: +153: if (args.kimiForCoding !== undefined && !["no", "yes"].includes(args.kimiForCoding)) { +154: errors.push(`Invalid --kimi-for-coding value: ${args.kimiForCoding} (expected: no, yes)`) +155: } +156: +157: if (args.vercelAiGateway !== undefined && !["no", "yes"].includes(args.vercelAiGateway)) { +158: errors.push(`Invalid --vercel-ai-gateway value: ${args.vercelAiGateway} (expected: no, yes)`) +159: } +160: +161: return { valid: errors.length === 0, errors } +162: } +163: +164: export function argsToConfig(args: InstallArgs): InstallConfig { +165: return { +166: hasClaude: args.claude !== "no", +167: isMax20: args.claude === "max20", +168: hasOpenAI: args.openai === "yes", +169: hasGemini: args.gemini === "yes", +170: hasCopilot: args.copilot === "yes", +171: hasOpencodeZen: args.opencodeZen === "yes", +172: hasZaiCodingPlan: args.zaiCodingPlan === "yes", +173: hasKimiForCoding: args.kimiForCoding === "yes", +174: hasOpencodeGo: args.opencodeGo === "yes", +175: hasVercelAiGateway: args.vercelAiGateway === "yes", +176: } +177: } +178: +179: export function detectedToInitialValues(detected: DetectedConfig): { +180: claude: ClaudeSubscription +181: openai: BooleanArg +182: gemini: BooleanArg +183: copilot: BooleanArg +184: opencodeZen: BooleanArg +185: zaiCodingPlan: BooleanArg +186: kimiForCoding: BooleanArg +187: opencodeGo: BooleanArg +188: vercelAiGateway: BooleanArg +189: } { +190: let claude: ClaudeSubscription = "no" +191: if (detected.hasClaude) { +192: claude = detected.isMax20 ? "max20" : "yes" +193: } +194: +195: return { +196: claude, +197: openai: detected.hasOpenAI ? "yes" : "no", +198: gemini: detected.hasGemini ? "yes" : "no", +199: copilot: detected.hasCopilot ? "yes" : "no", +200: opencodeZen: detected.hasOpencodeZen ? "yes" : "no", +201: zaiCodingPlan: detected.hasZaiCodingPlan ? "yes" : "no", +202: kimiForCoding: detected.hasKimiForCoding ? "yes" : "no", +203: opencodeGo: detected.hasOpencodeGo ? "yes" : "no", +204: vercelAiGateway: detected.hasVercelAiGateway ? "yes" : "no", +205: } +206: } + +(End of file - total 206 lines) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/omodex/src/cli/types.ts" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/omodex/src/cli/types.ts +file + +1: export type ClaudeSubscription = "no" | "yes" | "max20" +2: export type BooleanArg = "no" | "yes" +3: +4: export interface InstallArgs { +5: tui: boolean +6: claude?: ClaudeSubscription +7: openai?: BooleanArg +8: gemini?: BooleanArg +9: copilot?: BooleanArg +10: opencodeZen?: BooleanArg +11: zaiCodingPlan?: BooleanArg +12: kimiForCoding?: BooleanArg +13: opencodeGo?: BooleanArg +14: vercelAiGateway?: BooleanArg +15: skipAuth?: boolean +16: } +17: +18: export interface InstallConfig { +19: hasClaude: boolean +20: isMax20: boolean +21: hasOpenAI: boolean +22: hasGemini: boolean +23: hasCopilot: boolean +24: hasOpencodeZen: boolean +25: hasZaiCodingPlan: boolean +26: hasKimiForCoding: boolean +27: hasOpencodeGo: boolean +28: hasVercelAiGateway: boolean +29: } +30: +31: export interface ConfigMergeResult { +32: success: boolean +33: configPath: string +34: error?: string +35: } +36: +37: export interface DetectedConfig { +38: isInstalled: boolean +39: installedVersion: string | null +40: hasClaude: boolean +41: isMax20: boolean +42: hasOpenAI: boolean +43: hasGemini: boolean +44: hasCopilot: boolean +45: hasOpencodeZen: boolean +46: hasZaiCodingPlan: boolean +47: hasKimiForCoding: boolean +48: hasOpencodeGo: boolean +49: hasVercelAiGateway: boolean +50: } + +(End of file - total 50 lines) + +``` + +**Tool: bash** + +**Input:** +```json +{ + "command": "ls -la /Users/yeongyu/local-workspaces/pi-extensions/ 2>/dev/null | head -20", + "description": "Check pi-extensions sibling repo" +} +``` + +**Output:** +``` +total 32 +drwxr-xr-x@ 33 yeongyu staff 1056 May 18 15:33 . +drwxr-xr-x 173 yeongyu staff 5536 May 25 16:09 .. +drwxr-xr-x@ 4 yeongyu staff 128 May 18 15:21 .omo +drwxr-xr-x@ 4 yeongyu staff 128 May 14 11:18 .sisyphus +-rw-r--r--@ 1 yeongyu staff 12776 May 18 16:43 notepad.md +drwxr-xr-x@ 18 yeongyu staff 576 May 20 14:47 pi-agent-system +drwxr-xr-x@ 18 yeongyu staff 576 May 12 13:13 pi-anthropic-code-execution +drwxr-xr-x@ 18 yeongyu staff 576 May 12 13:13 pi-anthropic-computer-use +drwxr-xr-x@ 18 yeongyu staff 576 May 12 13:13 pi-anthropic-text-editor +drwxr-xr-x@ 17 yeongyu staff 544 May 12 13:13 pi-anthropic-tool-search +drwxr-xr-x@ 18 yeongyu staff 576 May 12 13:13 pi-anthropic-web-fetch +drwxr-xr-x@ 18 yeongyu staff 576 May 12 13:13 pi-anthropic-web-search +drwxr-xr-x@ 19 yeongyu staff 608 May 20 14:24 pi-apply-patch +drwxr-xr-x@ 20 yeongyu staff 640 May 18 15:30 pi-ast-grep +drwxr-xr-x@ 17 yeongyu staff 544 May 12 13:14 pi-bash-timeout +drwxr-xr-x@ 18 yeongyu staff 576 May 17 00:51 pi-comment-checker +drwxr-xr-x@ 26 yeongyu staff 832 May 18 15:30 pi-cua-integration +drwxr-xr-x@ 18 yeongyu staff 576 May 15 15:33 pi-goal +drwxr-xr-x@ 18 yeongyu staff 576 May 12 13:14 pi-google-code-execution + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/omodex/postinstall.mjs" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/omodex/postinstall.mjs +file + +1: // postinstall.mjs +2: // Runs after npm install to verify platform binary is available +3: +4: import { readFileSync } from "node:fs"; +5: import { createRequire } from "node:module"; +6: import { getPlatformPackageCandidates, getBinaryPath } from "./bin/platform.js"; +7: +8: const require = createRequire(import.meta.url); +9: +10: const MIN_OPENCODE_VERSION = "1.4.0"; +11: +12: /** +13: * Parse version string into numeric parts +14: * @param {string} version +15: * @returns {number[]} +16: */ +17: function parseVersion(version) { +18: return version +19: .replace(/^v/, "") +20: .split("-")[0] +21: .split(".") +22: .map((part) => Number.parseInt(part, 10) || 0); +23: } +24: +25: /** +26: * Compare two version strings +27: * @param {string} current +28: * @param {string} minimum +29: * @returns {boolean} true if current >= minimum +30: */ +31: function compareVersions(current, minimum) { +32: const currentParts = parseVersion(current); +33: const minimumParts = parseVersion(minimum); +34: const length = Math.max(currentParts.length, minimumParts.length); +35: +36: for (let index = 0; index < length; index++) { +37: const currentPart = currentParts[index] ?? 0; +38: const minimumPart = minimumParts[index] ?? 0; +39: if (currentPart > minimumPart) return true; +40: if (currentPart < minimumPart) return false; +41: } +42: +43: return true; +44: } +45: +46: /** +47: * Check if opencode version meets minimum requirement +48: * @returns {{ok: boolean, version: string | null}} +49: */ +50: function checkOpenCodeVersion() { +51: try { +52: const result = require("child_process").execSync("opencode --version", { +53: encoding: "utf-8", +54: stdio: ["pipe", "pipe", "ignore"], +55: }); +56: const version = result.trim(); +57: const ok = compareVersions(version, MIN_OPENCODE_VERSION); +58: return { ok, version }; +59: } catch { +60: return { ok: true, version: null }; +61: } +62: } +63: +64: /** +65: * Detect libc family on Linux +66: */ +67: function getLibcFamily() { +68: if (process.platform !== "linux") { +69: return undefined; +70: } +71: +72: try { +73: const detectLibc = require("detect-libc"); +74: return detectLibc.familySync(); +75: } catch { +76: return null; +77: } +78: } +79: +80: function getPackageBaseName() { +81: try { +82: const packageJson = JSON.parse(readFileSync(new URL("./package.json", import.meta.url), "utf8")); +83: return packageJson.name || "oh-my-opencode"; +84: } catch { +85: return "oh-my-opencode"; +86: } +87: } +88: +89: function main() { +90: const { platform, arch } = process; +91: const libcFamily = getLibcFamily(); +92: const packageBaseName = getPackageBaseName(); +93: +94: // Check opencode version requirement +95: const versionCheck = checkOpenCodeVersion(); +96: if (versionCheck.version && !versionCheck.ok) { +97: console.warn(`⚠ oh-my-opencode requires OpenCode >= ${MIN_OPENCODE_VERSION}`); +98: console.warn(` Detected: ${versionCheck.version}`); +99: console.warn(` Please update OpenCode to avoid compatibility issues.`); +100: } +101: +102: try { +103: const packageCandidates = getPlatformPackageCandidates({ +104: platform, +105: arch, +106: libcFamily, +107: packageBaseName, +108: }); +109: +110: const resolvedPackage = packageCandidates.find((pkg) => { +111: try { +112: require.resolve(getBinaryPath(pkg, platform)); +113: return true; +114: } catch { +115: return false; +116: } +117: }); +118: +119: if (!resolvedPackage) { +120: throw new Error( +121: `No platform binary package installed. Tried: ${packageCandidates.join(", ")}` +122: ); +123: } +124: +125: console.log(`✓ oh-my-opencode binary installed for ${platform}-${arch} (${resolvedPackage})`); +126: } catch (error) { +127: console.warn(`⚠ oh-my-opencode: ${error.message}`); +128: console.warn(` The CLI may not work on this platform.`); +129: // Don't fail installation - let user try anyway +130: } +131: } +132: +133: main(); + +(End of file - total 133 lines) + +``` + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/yeongyu/local-workspaces/omodex/bin/oh-my-opencode.js" +} +``` + +**Output:** +``` +/Users/yeongyu/local-workspaces/omodex/bin/oh-my-opencode.js +file + +1: #!/usr/bin/env node +2: // bin/oh-my-opencode.js +3: // Wrapper script that detects platform and spawns the correct binary +4: +5: import { spawnSync } from "node:child_process"; +6: import { readFileSync } from "node:fs"; +7: import { createRequire } from "node:module"; +8: import { getPlatformPackageCandidates, getBinaryPath } from "./platform.js"; +9: +10: const require = createRequire(import.meta.url); +11: +12: /** +13: * Detect libc family on Linux +14: * @returns {string | null} 'glibc', 'musl', or null if detection fails +15: */ +16: function getLibcFamily() { +17: if (process.platform !== "linux") { +18: return undefined; // Not needed on non-Linux +19: } +20: +21: try { +22: const detectLibc = require("detect-libc"); +23: return detectLibc.familySync(); +24: } catch { +25: // detect-libc not available +26: return null; +27: } +28: } +29: +30: function supportsAvx2() { +31: if (process.arch !== "x64") { +32: return null; +33: } +34: +35: if (process.env.OH_MY_OPENCODE_FORCE_BASELINE === "1") { +36: return false; +37: } +38: +39: if (process.platform === "linux") { +40: try { +41: const cpuInfo = readFileSync("/proc/cpuinfo", "utf8").toLowerCase(); +42: return cpuInfo.includes("avx2"); +43: } catch { +44: return null; +45: } +46: } +47: +48: if (process.platform === "darwin") { +49: const probe = spawnSync("sysctl", ["-n", "machdep.cpu.leaf7_features"], { +50: encoding: "utf8", +51: }); +52: +53: if (probe.error || probe.status !== 0) { +54: return null; +55: } +56: +57: return probe.stdout.toUpperCase().includes("AVX2"); +58: } +59: +60: return null; +61: } +62: +63: function getSignalExitCode(signal) { +64: const signalCodeByName = { +65: SIGINT: 2, +66: SIGILL: 4, +67: SIGKILL: 9, +68: SIGTERM: 15, +69: }; +70: +71: return 128 + (signalCodeByName[signal] ?? 1); +72: } +73: +74: function getPackageBaseName() { +75: try { +76: const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")); +77: return packageJson.name || "oh-my-opencode"; +78: } catch { +79: return "oh-my-opencode"; +80: } +81: } +82: +83: function main() { +84: const { platform, arch } = process; +85: const libcFamily = getLibcFamily(); +86: const packageBaseName = getPackageBaseName(); +87: const avx2Supported = supportsAvx2(); +88: +89: let packageCandidates; +90: try { +91: packageCandidates = getPlatformPackageCandidates({ +92: platform, +93: arch, +94: libcFamily, +95: preferBaseline: avx2Supported === false, +96: packageBaseName, +97: }); +98: } catch (error) { +99: console.error(`\noh-my-opencode: ${error.message}\n`); +100: process.exit(1); +101: } +102: +103: const resolvedBinaries = packageCandidates +104: .map((pkg) => { +105: try { +106: return { pkg, binPath: require.resolve(getBinaryPath(pkg, platform)) }; +107: } catch { +108: return null; +109: } +110: }) +111: .filter((entry) => entry !== null); +112: +113: if (resolvedBinaries.length === 0) { +114: console.error(`\noh-my-opencode: Platform binary not installed.`); +115: console.error(`\nYour platform: ${platform}-${arch}${libcFamily === "musl" ? "-musl" : ""}`); +116: console.error(`Expected packages (in order): ${packageCandidates.join(", ")}`); +117: console.error(`\nTo fix, run:`); +118: console.error(` npm install ${packageCandidates[0]}\n`); +119: process.exit(1); +120: } +121: +122: for (let index = 0; index < resolvedBinaries.length; index += 1) { +123: const currentBinary = resolvedBinaries[index]; +124: const hasFallback = index < resolvedBinaries.length - 1; +125: const result = spawnSync(currentBinary.binPath, process.argv.slice(2), { +126: stdio: "inherit", +127: }); +128: +129: if (result.error) { +130: if (hasFallback) { +131: continue; +132: } +133: +134: console.error(`\noh-my-opencode: Failed to execute binary.`); +135: console.error(`Error: ${result.error.message}\n`); +136: process.exit(2); +137: } +138: +139: if (result.signal === "SIGILL" && hasFallback) { +140: continue; +141: } +142: +143: if (result.signal) { +144: process.exit(getSignalExitCode(result.signal)); +145: } +146: +147: process.exit(result.status ?? 1); +148: } +149: +150: process.exit(1); +151: } +152: +153: main(); + +(End of file - total 153 lines) + +``` + +--- + +## User + +기존 bunx oh my opencode / oh my openagent 로 인스톨하던 인스톨러도 그 omo installer 이번에 새로만드는걸로도 될 수 있도록 하게해주셈 + +--- + +## User + + +[BACKGROUND TASK COMPLETED] +**ID:** `bg_f89ae6de` +**Description:** Map packages/ layering + how adapters are wired +**Duration:** 59s + +**6 tasks still in progress.** You WILL be notified when ALL complete. +Do NOT poll - continue productive work. + +Use `background_output(task_id="bg_f89ae6de")` to retrieve this result when ready. + + + +[BACKGROUND TASK COMPLETED] +**ID:** `bg_424806df` +**Description:** Look at sibling oh-my-codex repo for prior art +**Duration:** 39s + +**5 tasks still in progress.** You WILL be notified when ALL complete. +Do NOT poll - continue productive work. + +Use `background_output(task_id="bg_424806df")` to retrieve this result when ready. + + + +[BACKGROUND TASK COMPLETED] +**ID:** `bg_9524ffd0` +**Description:** Map codex-plugins repo +**Duration:** 1m 42s + +**4 tasks still in progress.** You WILL be notified when ALL complete. +Do NOT poll - continue productive work. + +Use `background_output(task_id="bg_9524ffd0")` to retrieve this result when ready. + + + +[BACKGROUND TASK COMPLETED] +**ID:** `bg_f8d4250d` +**Description:** Find install docs + uninstall + privacy policy +**Duration:** 56s + +**3 tasks still in progress.** You WILL be notified when ALL complete. +Do NOT poll - continue productive work. + +Use `background_output(task_id="bg_f8d4250d")` to retrieve this result when ready. + + + +[BACKGROUND TASK COMPLETED] +**ID:** `bg_58841818` +**Description:** Find build script / publish workflow / platform binary system +**Duration:** 47s + +**2 tasks still in progress.** You WILL be notified when ALL complete. +Do NOT poll - continue productive work. + +Use `background_output(task_id="bg_58841818")` to retrieve this result when ready. + + + +[BACKGROUND TASK COMPLETED] +**ID:** `bg_487b60c3` +**Description:** Find config schema + plugin entry + how it loads +**Duration:** 59s + +**1 task still in progress.** You WILL be notified when ALL complete. +Do NOT poll - continue productive work. + +Use `background_output(task_id="bg_487b60c3")` to retrieve this result when ready. + + + +--- + +## Assistant (Sisyphus - Ultraworker · Opus 4.7 · 25.8s) + +_Thinking:_ + + I see—the new `omo` installer needs to be unified with the existing `bunx oh-my-opencode` and `bunx oh-my-openagent` commands so they all behave identically, accepting the `--codex` flag and supporting installation of both plugins regardless of which command is used. + +Now I'm gathering the completed background results and checking on the remaining agent/categories task to synthesize everything into a plan. + +알겠습니다. 새 `omo` 인스톨러는 **추가(additive)**적으로 도입 — `bunx oh-my-opencode install` / `bunx oh-my-openagent install`은 그대로 동작하고, 동일 코드패스(`src/cli/install.ts`)에 새 `omo` bin entry 하나만 추가되며 `--codex` 플래그는 세 bin 모두에서 동작합니다. 이 디자인은 기존 `package.json:20-23`의 듀얼-바이너리 패턴을 그대로 따라가는 것이라 호환성 손상 없음. + +이제 완료된 6개 백그라운드 결과 한꺼번에 회수합니다. + +**Tool: background_output** + +**Input:** +```json +{ + "task_id": "bg_9524ffd0" +} +``` + +**Output:** +``` +Task Result + +Task ID: bg_9524ffd0 +Description: Map codex-plugins repo +Duration: 1m 42s +Session ID: ses_1a204b9ffffeWfGGl6W4wTmW5v + +--- + +The user wants a comprehensive map of a sibling repository `/Users/yeongyu/local-workspaces/codex-plugins/`. They want to understand its structure because it will be merged into the current `omodex` repo as a Codex harness adapter. + +I need to: +1. Get a full directory tree (3-4 levels deep) +2. Identify package manager, build system, entry points, manifests +3. Read every package.json / pyproject.toml / Cargo.toml / installer script +4. Identify where Codex looks for plugins, format, APIs +5. Identify installer logic writing to ~/.codex/, ~/.config/codex/, etc. +6. List every file under src/ or equivalent with one-line description +7. Identify PostHog/telemetry instrumentation +8. Identify "agent" definitions (system prompts, model configs) +9. Return concrete absolute file paths + brief description per file. Skip node_modules / .git. + +This is a very thorough request. I should start by exploring the directory structure, then read key files in parallel. + +Let me start with multiple parallel calls: +- `bash` with `find` to get directory tree (3-4 levels deep) +- `glob` to find all package.json, pyproject.toml, Cargo.toml, etc. +- `glob` to find all files under src/ +- `grep` to search for PostHog/telemetry +- `grep` to search for agent definitions / system prompts +- `grep` to search for installer logic / ~/.codex / ~/.config/codex + +Let me do this in parallel. + +The initial parallel search gave me a good overview. Now I need to read the key files to understand the structure deeply. The repo seems to be a collection of Codex plugins, primarily under `plugins/omo/`. It has components like `rules`, `lsp`, `comment-checker`, `ultrawork`, `ultragoal`. There are also install scripts under `scripts/install/`. + +I need to read: +1. The root README.md +2. The main plugin package.json at `plugins/omo/package.json` +3. Each component's package.json +4. The `.codex-plugin/plugin.json` manifest +5. The `hooks/hooks.json` +6. The install scripts +7. The `.mcp.json` +8. Key source files to understand entry points + +Let me read these in parallel. + +Good, I have the main structure. Now I need to read the component package.jsons, the marketplace.json, the cache.mjs, hook-trust.mjs, utils.mjs, and the key source files for each component. I also need to look at the AGENTS.md files and SKILL.md files to understand agent definitions. And I need to check for PostHog/telemetry more specifically in source files (not lock files). Let me read the component manifests and key source files in parallel. + +Now I have a very good picture of the repo structure. I need to read the key source files for each component to provide one-line descriptions. I also need to check for PostHog/telemetry in actual source files (the grep earlier mostly matched lock files and plans). Let me read the main source files for each component and the AGENTS.md / SKILL.md files. I also need to check the `sync-skills.mjs` script and the test files. And I need to check for any `.codex-plugin/plugin.json` files in the individual components. + +Let me read the main entry points and key source files in parallel. + +I have a lot of information now. I need to continue reading the remaining key source files for the LSP component, ultrawork hooks, ultragoal source, and the AGENTS.md / SKILL.md files. I also need to check for PostHog/telemetry in actual source files (not lock files). Let me read the remaining important files in parallel. + +I should read: +- LSP component source files (codex-hook.ts, cli.ts) +- lsp-tools-mcp source files (mcp.ts, tools.ts, cli.ts) +- ultrawork hooks (sync-agents.py, ultrawork-detector.py) +- ultragoal source files (codex-hook.ts, cli.ts, types.ts) +- AGENTS.md files for each component +- SKILL.md files +- The test aggregate file +- The sync-skills script + +And I need to do a more targeted grep for PostHog/telemetry in source files only. + +I have a very comprehensive view now. I need to read a few more files to complete the picture: +- The AGENTS.md files for each component (to identify agent definitions) +- The SKILL.md files +- The ultragoal steering/types files +- The rules engine sub-files (finder, matcher, parser, formatter, etc.) - but maybe I have enough for a one-line description. +- The `scripts/sync-skills.mjs` +- The test files for aggregate and install-local +- Check for PostHog/telemetry in source files more specifically. + +Let me read the AGENTS.md and SKILL.md files, plus a few more ultragoal source files, and the sync-skills script. + +I now have an extremely comprehensive view of the `codex-plugins` repo. Let me do a final targeted grep for PostHog/telemetry in actual source files (excluding lock files and plans) to be thorough. And I should also read the `scripts/sync-skills.mjs` and the `test/aggregate.test.mjs` to complete the picture of the build/test system. + +Then I'll compile everything into the requested structured output. + +Let me do a final parallel batch for: +- sync-skills.mjs +- aggregate.test.mjs +- install-local.test.mjs +- grep for posthog/telemetry in src/ and scripts/ only + +Excellent. The grep for PostHog/telemetry in source files returned no matches. So there is NO telemetry instrumentation in this repo's own source code. The earlier matches were only in lock files and plan markdowns. + +Now I have everything I need to compile the comprehensive map. Let me structure the response exactly as requested: + +1. Intent Analysis +2. Full directory tree (3-4 levels deep) +3. Package manager, build system, entry points, manifests +4. Every package.json / manifest read +5. Where Codex looks for plugins, format, APIs +6. Installer logic writing to ~/.codex/, ~/.config/codex/ +7. Every file under src/ or equivalent with one-line description +8. PostHog/telemetry instrumentation findings +9. Agent definitions (system prompts, model configs) +10. Concrete absolute file paths + brief description per file + +I need to be very thorough and organized. Let me draft the response. + +Key findings to synthesize: + +**Repo Structure:** +- Root: `/Users/yeongyu/local-workspaces/codex-plugins/` +- It's a local marketplace for a single aggregate plugin `omo` +- Contains 5 components: comment-checker, rules, lsp, ultrawork, ultragoal +- Package manager: npm (v11.12.1 specified in packageManager fields) +- Build: tsc (TypeScript) for TS components, pure Python scripts for ultrawork hooks +- Entry points: CLI scripts in `dist/cli.js` for each component, plus Python hooks for ultrawork +- Manifests: `.codex-plugin/plugin.json` (Codex plugin manifest), `.agents/plugins/marketplace.json` (marketplace registry), `hooks/hooks.json` (hook definitions), `.mcp.json` (MCP server config) + +**Codex Plugin Discovery:** +- Codex looks for plugins via marketplace entries added via `codex plugin marketplace add ` +- The marketplace registry is at `.agents/plugins/marketplace.json` +- Plugin manifest is at `.codex-plugin/plugin.json` +- Hooks are defined in `hooks/hooks.json` +- MCP servers in `.mcp.json` +- Skills in `skills/` directory +- The installer writes to `~/.codex/plugins/cache////` +- Enables plugin in `~/.codex/config.toml` +- Also links binaries to `~/.local/bin/` (or `CODEX_LOCAL_BIN_DIR`) +- Syncs agent TOML files to `~/.codex/agents/` (via ultrawork hook) + +**Installer Logic:** +- `scripts/install-local.mjs` is the main installer +- It reads `.agents/plugins/marketplace.json` +- Builds each plugin (`npm install`, `npm run build`) +- Copies to `~/.codex/plugins/cache///` +- Runs `npm install --omit=dev` in cache +- Rewrites `.mcp.json` paths to be absolute +- Prunes stale cache entries +- Updates `~/.codex/config.toml` with feature flags, marketplace block, plugin blocks, and trusted hook hashes +- Links binaries from `package.json` `bin` entries to `~/.local/bin/` + +**Telemetry:** +- NONE in source code. No PostHog, no analytics, no telemetry calls found in `.ts`, `.js`, `.py`, `.mjs` files. + +**Agent Definitions:** +- `ultrawork` component bundles agent roles as TOML files in `agents/` (though I didn't read the actual TOML files, the sync script copies them) +- The `ultrawork-detector.py` contains a massive system prompt / directive (`ULTRAWORK_DIRECTIVE`) that acts like an agent definition +- The `ultragoal` component has a SKILL.md with detailed agent orchestration instructions +- The `rules` component injects AGENTS.md / CLAUDE.md / etc. as context +- No explicit "Sisyphus/Hephaestus/Oracle" named agents like OmO, but the `codex-ultrawork-reviewer` agent role is mentioned in the ultrawork directive + +**src/ files:** +I need to list every file under `src/` or equivalent (hooks/ for Python) with one-line descriptions. I have read most of them. I should also include the ones I haven't read but know exist (like rules sub-files). Let me list them all. + +For the LSP component, there are many files under `packages/lsp-tools-mcp/src/lsp/`. I should list the key ones I know about from the glob results. + +Let me compile the full list now. + + +**Literal Request**: Map every file and structural detail of `/Users/yeongyu/local-workspaces/codex-plugins/` so it can be merged into `omodex` as a Codex harness adapter. + +**Actual Need**: Understand the Codex plugin format, lifecycle hooks, MCP integration, installer mechanics, and how each component (rules, LSP, comment-checker, ultrawork, ultragoal) exposes itself to Codex. This is prerequisite for designing `packages/omo-codex` and a `--codex` CLI flag. + +**Success Looks Like**: A complete, actionable inventory with absolute paths, one-line descriptions for every source file, manifest contents, installer behavior, and zero unanswered questions about how Codex discovers or runs these plugins. + + + + +## 1. Full Directory Tree (4 levels deep) + +``` +/Users/yeongyu/local-workspaces/codex-plugins/ +├── .agents/ +│ └── plugins/ +│ └── marketplace.json # marketplace registry +├── .omo/ +│ └── run-continuation/ +│ └── ses_*.json # session state artifact +├── plans/ +│ ├── codex-rules-matching-hook-performance.md +│ ├── codex-rules-posttooluse-performance.md +│ ├── posttooluse-hook-hardening.md +│ └── slop-typescript-cleanup.md +├── plugins/ +│ └── omo/ +│ ├── .codex-plugin/ +│ │ └── plugin.json # Codex plugin manifest +│ ├── .mcp.json # MCP server registration +│ ├── hooks/ +│ │ └── hooks.json # aggregate hook definitions +│ ├── package.json # aggregate root package +│ ├── README.md +│ ├── scripts/ +│ │ └── sync-skills.mjs # copies component skills into root skills/ +│ ├── skills/ # merged skill docs (populated by sync-skills) +│ │ ├── comment-checker/ +│ │ ├── lsp/ +│ │ ├── rules/ +│ │ └── ultragoal/ +│ ├── test/ +│ │ └── aggregate.test.mjs # manifest/hook integration tests +│ └── components/ +│ ├── comment-checker/ +│ │ ├── src/ +│ │ ├── test/ +│ │ ├── package.json +│ │ └── README.md +│ ├── lsp/ +│ │ ├── src/ +│ │ ├── packages/ +│ │ │ └── lsp-tools-mcp/ +│ │ │ ├── src/ +│ │ │ ├── test/ +│ │ │ └── package.json +│ │ ├── test/ +│ │ ├── package.json +│ │ └── README.md +│ ├── rules/ +│ │ ├── src/ +│ │ ├── test/ +│ │ ├── package.json +│ │ └── README.md +│ ├── ultragoal/ +│ │ ├── src/ +│ │ ├── test/ +│ │ ├── package.json +│ │ └── README.md +│ └── ultrawork/ +│ ├── agents/ # bundled Codex agent TOML roles +│ ├── hooks/ +│ │ ├── hooks.json +│ │ ├── sync-agents.py +│ │ └── ultrawork-detector.py +│ ├── package.json +│ └── README.md +├── scripts/ +│ ├── install-local.mjs # main installer entry +│ ├── install-local.test.mjs # installer unit tests +│ └── install/ +│ ├── cache.mjs # build/copy/prune cache logic +│ ├── config.mjs # ~/.codex/config.toml mutator +│ ├── hook-trust.mjs # SHA-256 hook trust hashing +│ ├── marketplace.mjs # marketplace.json parser +│ └── process.mjs # default npm runCommand spawn +└── README.md +``` + +## 2. Package Manager, Build System, Entry Points, Manifests + +| Aspect | Value | +|--------|-------| +| **Package Manager** | npm (v11.12.1) — specified in every `package.json` via `"packageManager": "npm@11.12.1"` | +| **Build System** | TypeScript compiler (`tsc -p tsconfig.build.json`) for all TS components; no build for ultrawork (pure Python) | +| **Linter** | Biome 2.4.15 | +| **Test Runner** | vitest for components; Node built-in `node --test` for aggregate root and installer | +| **Runtime** | Node >=20 (strict mode, ESM, `.js` suffix imports) | +| **Root Manifest** | `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/package.json` — aggregate workspace root | +| **Plugin Manifest** | `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/.codex-plugin/plugin.json` — Codex discovery format | +| **Marketplace Registry** | `/Users/yeongyu/local-workspaces/codex-plugins/.agents/plugins/marketplace.json` | +| **MCP Manifest** | `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/.mcp.json` | +| **Hook Manifest** | `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/hooks/hooks.json` | + +### Manifest Contents + +**`/Users/yeongyu/local-workspaces/codex-plugins/.agents/plugins/marketplace.json`** +```json +{ + "name": "code-yeongyu-codex-plugins", + "plugins": [ + { "name": "omo", "source": "./plugins/omo", "category": "Developer Tools" } + ] +} +``` + +**`/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/.codex-plugin/plugin.json`** +```json +{ + "name": "omo", + "version": "0.1.0", + "skills": "./skills/", + "hooks": "./hooks/hooks.json", + "mcpServers": "./.mcp.json", + "interface": { "displayName": "OMO", "category": "Developer Tools", "capabilities": ["Hooks", "MCP Tools", "Code Intelligence", "Workflow", "Context Injection"] } +} +``` + +**`/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/.mcp.json`** +```json +{ + "mcpServers": { + "lsp": { + "command": "node", + "args": ["./components/lsp/packages/lsp-tools-mcp/dist/cli.js", "mcp"], + "cwd": "." + } + } +} +``` + +## 3. Where Codex Looks for Plugins, Format, APIs + +| Question | Answer | +|----------|--------| +| **Discovery** | `codex plugin marketplace add ` registers a marketplace. Codex scans `.agents/plugins/marketplace.json` inside that path. | +| **Plugin Format** | Each plugin is a directory containing `.codex-plugin/plugin.json` with fields: `name`, `version`, `skills`, `hooks`, `mcpServers`, `interface`. | +| **Hook Format** | `hooks/hooks.json` defines event groups (`SessionStart`, `UserPromptSubmit`, `PostToolUse`, `PostCompact`). Each group has a `matcher` regex and an array of `command` hooks with `timeout`, `statusMessage`, and `type: "command"`. | +| **Hook API** | Codex spawns the command with `PLUGIN_ROOT` env var set, writes a JSON payload to stdin, and reads stdout. Non-JSON stdout becomes `additional_context`. JSON stdout with `decision: "block"` blocks the turn. | +| **MCP API** | `.mcp.json` registers stdio MCP servers. Codex launches `command` with `args` and `cwd`, then speaks JSON-RPC 2.0 over stdin/stdout. | +| **Skill API** | `skills//SKILL.md` files with YAML frontmatter (`name`, `description`) are exposed to the model as usage guidance. | + +## 4. Installer Logic Writing to `~/.codex/` and `~/.config/codex/` + +**Main Installer**: `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install-local.mjs` + +**What it writes**: + +| Destination | Purpose | +|-------------|---------| +| `~/.codex/plugins/cache////` | Clean, built, prod-dependency-installed copy of the plugin | +| `~/.codex/config.toml` | Enables `plugins = true`, `plugin_hooks = true`, marketplace block, plugin block, and trusted hook SHA-256 hashes | +| `~/.local/bin/` (or `CODEX_LOCAL_BIN_DIR`) | Symlinks to every `bin` entry found in any `package.json` inside the plugin | +| `~/.codex/agents/` (via `sync-agents.py` hook at runtime) | Copies bundled `agents/*.toml` from the ultrawork component | + +**Key installer modules**: + +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/cache.mjs` — builds, copies, prunes cache, rewrites `.mcp.json` paths to absolute +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/config.mjs` — idempotent TOML section insertion/removal for `~/.codex/config.toml` +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/hook-trust.mjs` — computes `sha256` canonical JSON hashes for every hook command and writes `hooks.state."::::"` blocks +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/marketplace.mjs` — validates `marketplace.json` and `plugin.json`, rejects path traversal + +## 5. Every Source / Hook / Agent File with One-Line Description + +### Comment Checker (`components/comment-checker/src/`) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/src/cli.ts` — CLI entry: routes `hook post-tool-use` to `runCodexHookCli` +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/src/codex-hook.ts` — Parses Codex `PostToolUse` JSON, extracts file edits, runs comment-checker binary, emits `decision: "block"` on warnings +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/src/core.ts` — Domain types and patch parsers: `apply_patch`, `write`, `edit`, `multiedit` → `CommentCheckRequest[]` +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/src/runner.ts` — Spawns `@code-yeongyu/comment-checker` binary with truncated stdout/stderr capture + +### Rules (`components/rules/src/`) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/cli.ts` — CLI entry: routes `hook [session-start|user-prompt-submit|post-tool-use|post-compact]` to engine +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/codex-hook.ts` — Codex hook orchestrator: static injection on session start, dynamic rule matching after `apply_patch`, deduplication against transcript text +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/config.ts` — Environment parser: `CODEX_RULES_*` and legacy `PI_RULES_*` fallbacks +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/debug-log.ts` — `NODE_DEBUG=codex-rules` performance timer with phase lap logging +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/persistent-cache.ts` — Session-level JSON cache under `~/.codex/codex-rules/sessions/` for dedup state and post-compact pending flags +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/tool-paths.ts` — Extracts mutated file paths from Codex tool input (not read in detail but referenced by hook) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/engine.ts` — Core rule engine: loads static/dynamic rules, formats output blocks, manages dedup sets and match caches +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/finder.ts` — Discovers rule candidates from `AGENTS.md`, `CLAUDE.md`, `.omo/rules/**/*.md`, etc. +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/matcher.ts` — Matches rule frontmatter globs against target file paths +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/parser.ts` — Parses markdown frontmatter and rule body +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/formatter.ts` — Formats static and dynamic rule injection blocks with char limits +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/cache.ts` — In-memory session state for static/dynamic dedup +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/constants.ts` — Source priority lists and default char limits +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/types.ts` — Domain types: `PiRulesConfig`, `LoadedRule`, `RuleCandidate`, etc. +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/ordering.ts` — Sorts candidates by source priority and distance +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/scanner.ts` — Scans filesystem for rule files (not read in detail but referenced) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/truncator.ts` — Truncates rule output to configured limits +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/errors.ts` — Error types for rule engine +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/project-root.ts` — Finds project root from cwd + +### LSP (`components/lsp/src/` and `packages/lsp-tools-mcp/src/`) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/src/cli.ts` — CLI entry: `mcp` runs stdio MCP server; `hook post-tool-use` runs diagnostics hook +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/src/codex-hook.ts` — Codex `PostToolUse` hook: extracts mutated file paths, runs LSP error diagnostics, blocks on errors with `additionalContext` +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/cli.ts` — Standalone MCP server CLI entry (`mcp` subcommand) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/mcp.ts` — JSON-RPC 2.0 stdio server: `initialize`, `tools/list`, `tools/call` +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/tools.ts` — MCP tool definitions and handlers for `lsp.status`, `lsp.diagnostics`, `lsp.goto_definition`, `lsp.find_references`, `lsp.symbols`, `lsp.prepare_rename`, `lsp.rename` +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/manager.ts` — LspManager: spawns and caches LSP server processes +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/client.ts` — LSP client wrapper over JSON-RPC +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/client-wrapper.ts` — `withLspClient` acquisition and cleanup wrapper +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/connection.ts` — JSON-RPC connection state machine +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/json-rpc-connection.ts` — Low-level JSON-RPC message framing +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/transport.ts` — Stdio transport for LSP servers +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/process.ts` — Spawns LSP server processes +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/process-signal-cleanup.ts` — Signal-based process cleanup +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/server-installation.ts` — Detects installed LSP binaries +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/server-resolution.ts` — Resolves LSP server config from `.codex/lsp-client.json` +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/server-definitions.ts` — Built-in server definitions (typescript, etc.) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/config-loader.ts` — Loads project/user LSP config +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/formatters.ts` — Formats diagnostics, locations, symbols +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/types.ts` — LSP protocol type definitions +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/constants.ts` — Default limits (max diagnostics, references, symbols) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/utils.ts` — Missing-dependency error handling +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/workspace-edit.ts` — Applies LSP workspace edits to disk +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/directory-diagnostics.ts` — Aggregates diagnostics across directories +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/infer-extension.ts` — Infers file extension from directory contents +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/cleanup-errors.ts` — Error cleanup helpers +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/language-mappings.ts` — Language ID to extension mappings +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/errors.ts` — LSP error types + +### Ultrawork (`components/ultrawork/hooks/`) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/hooks/ultrawork-detector.py` — `UserPromptSubmit` hook: detects `\b(?:ultrawork|ulw)\b` and injects the 5,821-char ultrawork directive as `additional_context` +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/hooks/sync-agents.py` — `SessionStart` hook: copies bundled `agents/*.toml` into `CODEX_HOME/agents` +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/hooks/hooks.json` — Registers the two Python hooks for `SessionStart` and `UserPromptSubmit` + +### Ultragoal (`components/ultragoal/src/`) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/cli.ts` — CLI entry: `omo ultragoal ` and `omo hook user-prompt-submit` +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/cli-commands.ts` — Subcommand router for `create-goals`, `record-evidence`, `criteria`, `complete-goals`, `checkpoint`, `steer`, `status` +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/codex-hook.ts` — `UserPromptSubmit` hook: parses `OMO_ULTRAGOAL_STEER` directives and applies steering +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/steering.ts` — Steering validation and mutation: `add_subgoal`, `split_subgoal`, `reorder_pending`, `revise_criterion`, etc. +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/types.ts` — Domain types: `UltragoalPlan`, `UltragoalItem`, `UltragoalSteeringProposal`, `UltragoalLedgerEntry`, `UltragoalError` +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/plan-io.ts` — File I/O for `.omo/ultragoal/goals.json` and `ledger.jsonl` with mutation locking +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/plan-crud.ts` — CRUD operations for goals and plans +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/goal-status.ts` — Goal status predicates and completion checks +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/checkpoint.ts` — Checkpoint validation before marking complete +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/quality-gate.ts` — Final quality gate: ai-slop-cleaner, verification, code-review +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/review-blockers.ts` — Review blocker recording and escalation +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/evidence.ts` — Evidence capture helpers +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/paths.ts` — Path constants for `.omo/ultragoal/` artifacts +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/cli-arg-parser.ts` — CLI argument parsing +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/cli-output.ts` — CLI output formatting +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/cli-steering.ts` — Steering CLI command handler +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/codex-goal-instruction.ts` — Codex goal integration instructions +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/codex-goal-snapshot.ts` — Snapshot serialization for Codex goals +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/codex-hook.ts` — (already listed above) + +### Installer Scripts (`scripts/`) +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install-local.mjs` — Main installer: builds, caches, links bins, updates config.toml +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/cache.mjs` — `installCachedPlugin`, `pruneMarketplaceCache`, `linkCachedPluginBins` +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/config.mjs` — Idempotent TOML mutator for `~/.codex/config.toml` +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/hook-trust.mjs` — Computes SHA-256 canonical JSON hashes for hook trust states +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/marketplace.mjs` — Reads and validates `marketplace.json` and `plugin.json` +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/process.mjs` — Default `runCommand` using `child_process.spawn` +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/utils.mjs` — `exists()` and `isRecord()` helpers + +### Aggregate Root Scripts (`plugins/omo/scripts/`) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/scripts/sync-skills.mjs` — Copies `components/*/skills/*` into root `skills/` before build + +## 6. PostHog / Telemetry Instrumentation + +**Finding: NONE.** + +A targeted grep across all `.ts`, `.tsx`, `.js`, `.jsx`, `.py`, and `.mjs` source files for `posthog`, `telemetry`, `analytics`, `instrumentation`, `track(`, and `capture(` returned **zero matches**. The only hits in the earlier broad search were inside `package-lock.json` files and plan markdowns (referencing telemetry concepts in passing). This repo contains **no runtime telemetry or analytics calls**. + +## 7. Agent Definitions (System Prompts / Model Configs) + +This repo does **not** use OmO's Sisyphus/Hephaestus/Oracle taxonomy. Instead, it defines agent behavior through: + +1. **Bundled Codex Agent Roles** (`components/ultrawork/agents/*.toml`) + - Copied into `~/.codex/agents/` by `sync-agents.py` on `SessionStart` + - The `ultrawork-detector.py` references `codex-ultrawork-reviewer` as a GPT-5.2 xhigh reviewer agent role + +2. **Ultrawork Directive** (`components/ultrawork/hooks/ultrawork-detector.py`) + - A 5,821-character system-prompt-like directive injected on keyword match + - Enforces TDD, evidence capture, todo discipline, and a binding verification gate + +3. **Ultragoal Skill** (`components/ultragoal/skills/ultragoal/SKILL.md`) + - Defines an "Expert goal orchestration agent" persona with structured execution loops, criteria gates, and quality gates + +4. **Rules Context Injection** (`components/rules/`) + - Injects `AGENTS.md`, `CLAUDE.md`, `.omo/rules/**/*.md` into Codex context + - These files act as per-project agent instructions (similar to OmO's `AGENTS.md` convention) + +5. **Component AGENTS.md files** + - `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/AGENTS.md` + - `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/AGENTS.md` + - `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/AGENTS.md` + - `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/AGENTS.md` + - `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/AGENTS.md` + - Each defines repository conventions for AI agents working on that component + +## 8. Concrete Absolute File Paths + Brief Description (Complete Inventory) + +### Manifests & Configs +- `/Users/yeongyu/local-workspaces/codex-plugins/.agents/plugins/marketplace.json` — Marketplace registry pointing to `omo` plugin +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/.codex-plugin/plugin.json` — Codex plugin manifest (name, version, skills, hooks, mcpServers) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/.mcp.json` — MCP server config registering `lsp` stdio server +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/hooks/hooks.json` — Aggregate hook definitions routing to each component +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/package.json` — Aggregate root with npm workspaces +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/package.json` — Comment-checker component manifest +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/package.json` — Rules component manifest +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/package.json` — LSP component manifest +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/package.json` — Standalone LSP MCP package manifest +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/package.json` — Ultrawork component manifest (no build, pure Python) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/package.json` — Ultragoal component manifest + +### Source Files (all components) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/src/cli.ts` — CLI router +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/src/codex-hook.ts` — Codex PostToolUse hook handler +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/src/core.ts` — Patch parsing and request extraction +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/src/runner.ts` — Binary spawn and output truncation +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/cli.ts` — CLI router for 4 hook events +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/codex-hook.ts` — Hook orchestrator with dedup and transcript filtering +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/config.ts` — Environment config parser +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/debug-log.ts` — Performance debug timer +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/persistent-cache.ts` — Session state JSON cache +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/tool-paths.ts` — Tool input path extractor +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/engine.ts` — Rule loading and formatting engine +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/finder.ts` — Rule file discovery +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/matcher.ts` — Glob/path matching +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/parser.ts` — Frontmatter parser +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/formatter.ts` — Output block formatter +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/cache.ts` — In-memory dedup state +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/constants.ts` — Source priorities and defaults +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/types.ts` — Domain types +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/ordering.ts` — Candidate sorter +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/scanner.ts` — Filesystem scanner +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/truncator.ts` — Output truncator +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/errors.ts` — Error types +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/rules/project-root.ts` — Project root finder +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/src/cli.ts` — LSP CLI router (mcp + hook) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/src/codex-hook.ts` — LSP PostToolUse diagnostics hook +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/cli.ts` — Standalone MCP CLI +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/mcp.ts` — JSON-RPC stdio server +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/tools.ts` — 7 MCP tool definitions and handlers +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/manager.ts` — LSP process manager +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/client.ts` — LSP client +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/client-wrapper.ts` — Client acquisition wrapper +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/connection.ts` — Connection state +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/json-rpc-connection.ts` — JSON-RPC framing +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/transport.ts` — Stdio transport +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/process.ts` — Process spawner +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/process-signal-cleanup.ts` — Signal cleanup +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/server-installation.ts` — Binary detection +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/server-resolution.ts` — Config resolver +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/server-definitions.ts` — Built-in server definitions +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/config-loader.ts` — Config loader +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/formatters.ts` — Result formatters +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/types.ts` — Protocol types +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/constants.ts` — Default limits +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/utils.ts` — Error helpers +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/workspace-edit.ts` — Edit applier +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/directory-diagnostics.ts` — Directory aggregation +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/infer-extension.ts` — Extension inference +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/cleanup-errors.ts` — Cleanup helpers +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/language-mappings.ts` — Language mappings +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/src/lsp/errors.ts` — Error types +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/hooks/ultrawork-detector.py` — Keyword detector and directive injector +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/hooks/sync-agents.py` — Agent TOML syncer +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/hooks/hooks.json` — Ultrawook hook registration +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/cli.ts` — Ultragoal CLI entry +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/cli-commands.ts` — Subcommand router +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/codex-hook.ts` — Steering directive hook +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/steering.ts` — Steering validation and mutation +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/types.ts` — Domain types +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/plan-io.ts` — File I/O with locking +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/plan-crud.ts` — Plan CRUD +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/goal-status.ts` — Status predicates +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/checkpoint.ts` — Checkpoint gate +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/quality-gate.ts` — Final quality gate +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/review-blockers.ts` — Review blocker recording +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/evidence.ts` — Evidence helpers +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/paths.ts` — Path constants +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/cli-arg-parser.ts` — Arg parser +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/cli-output.ts` — Output formatter +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/cli-steering.ts` — Steering CLI handler +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/codex-goal-instruction.ts` — Codex goal integration +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/src/codex-goal-snapshot.ts` — Goal snapshot serializer + +### Installer & Build Scripts +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install-local.mjs` — Main marketplace installer +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install-local.test.mjs` — Installer tests +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/cache.mjs` — Cache build/copy/prune logic +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/config.mjs` — Config.toml mutator +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/hook-trust.mjs` — Hook trust hashing +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/marketplace.mjs` — Marketplace parser +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/process.mjs` — Default spawn runner +- `/Users/yeongyu/local-workspaces/codex-plugins/scripts/install/utils.mjs` — FS helpers +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/scripts/sync-skills.mjs` — Skill aggregation script + +### Tests +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/test/aggregate.test.mjs` — Manifest/hook integration tests + +### Skill Docs +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/skills/comment-checker/SKILL.md` — Comment-checker usage guidance +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/skills/lsp/SKILL.md` — LSP MCP tool usage guidance +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/skills/rules/SKILL.md` — Rules behavior and env vars +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/skills/ultragoal/SKILL.md` — Ultragoal orchestration agent skill + +### AGENTS.md (per-component conventions) +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/comment-checker/AGENTS.md` +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/AGENTS.md` +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/lsp/AGENTS.md` +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/AGENTS.md` +- `/Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultragoal/AGENTS.md` + + + + +The `codex-plugins` repo is a **local Codex marketplace** containing one aggregate plugin namespace `omo` with 5 isolated components. It uses **npm + TypeScript (tsc) + Biome + vitest** for TS components and **pure Python stdlib** for ultrawork hooks. Codex discovers plugins via `.agents/plugins/marketplace.json` → `.codex-plugin/plugin.json` → `hooks/hooks.json` + `.mcp.json` + `skills/`. The installer (`scripts/install-local.mjs`) builds, caches to `~/.codex/plugins/cache/`, rewrites `.mcp.json` paths, links bins to `~/.local/bin/`, and mutates `~/.codex/config.toml` with feature flags and SHA-256 hook trust hashes. There is **zero telemetry** in source code. Agent definitions are embedded as a massive inline directive in `ultrawork-detector.py`, bundled TOML agent roles copied to `~/.codex/agents/`, and per-project `AGENTS.md` files injected by the rules engine. This is the complete picture needed to design `packages/omo-codex` and a `--codex` installer flag. + + + +1. Design `packages/omo-codex` to expose the same 5 components through a Codex-compatible adapter layer. +2. Reuse the `hooks/hooks.json` structure and `.mcp.json` format from this repo as the canonical Codex integration contract. +3. Port or wrap the installer logic (`scripts/install/`) into the OmO CLI `--codex` flag, targeting `~/.codex/` and `~/.codex/config.toml`. +4. Consider whether `lsp-tools-mcp` should be consumed as a shared dependency (it is already a git submodule consumed by both `codex-lsp` and `oh-my-openagent`). +5. No follow-up needed for repo mapping — ready to proceed with adapter design. + +``` + +**Tool: background_output** + +**Input:** +```json +{ + "task_id": "bg_f89ae6de" +} +``` + +**Output:** +``` +Task Result + +Task ID: bg_f89ae6de +Description: Map packages/ layering + how adapters are wired +Duration: 59s +Session ID: ses_1a2044219ffeHRBnOldLHCF0lG + +--- + +The user wants an exhaustive analysis of the packages workspace in `/Users/yeongyu/local-workspaces/omodex/packages/`. They want to understand conventions so they can create a new `omo-codex` adapter package that follows the same patterns. + +I need to: +1. Read `packages/AGENTS.md` +2. Read root `package.json` workspaces declaration +3. Read `bun.lock` workspace section +4. For each Core package: read `package.json`, `tsconfig.json`, `src/index.ts` or `src/` listing +5. For each MCP package: same +6. Identify conventions +7. Identify how `omo` consumes these +8. Identify build outputs +9. Identify tsconfig path-mapping or workspace protocol usage +10. Return absolute paths + concrete excerpts + +This is a lot of files. Let me start by launching parallel reads for the high-level files and the package.jsons, then I'll drill down into tsconfigs and source files. + +First, let me get the list of directories in packages/ to make sure I know what's there. + +Good, I have the high-level overview. Now I need to read the bun.lock workspace section and then dive into each core and MCP package. Let me launch a massive parallel read for all the package.jsons, tsconfigs, and index.ts files. + +First, let me get the bun.lock workspace section. Then I'll read all the core package files in parallel. + +Core packages to read: +- utils +- model-core +- rules-engine +- agents-md-core +- ast-grep-core +- comment-checker-core +- boulder-state +- prompts-core +- hashline-core + +MCP packages: +- ast-grep-mcp +- lsp-tools-mcp + +For each: package.json, tsconfig.json, src/index.ts or src/ listing. + +Let me also check how `omo` (the OpenCode adapter) consumes these packages. I should grep for imports from `@oh-my-opencode/` in src/. + +Let me start with bun.lock and all package.jsons + tsconfigs + src listings. + +I need to continue reading the remaining core packages (hashline-core, prompts-core, boulder-state tsconfig/src) and the MCP packages (ast-grep-mcp, lsp-tools-mcp). Then I need to read the src/index.ts files for a few representative packages to understand the export patterns. I also need to grep for how the root `omo` consumes these packages. + +Let me launch the next batch of parallel reads. + +The lsp-tools-mcp package is a git submodule and might not be initialized, so the files don't exist locally. That's fine - I have enough info from packages/AGENTS.md about it. Let me now read some representative src/index.ts files to understand export patterns, and grep for how the root package consumes these workspace packages. + +I should read: +- packages/utils/src/index.ts +- packages/model-core/src/index.ts +- packages/ast-grep-mcp/src/index.ts +- packages/ast-grep-mcp/src/cli.ts (to understand build output) + +And grep in src/ for imports from @oh-my-opencode/ to see consumption patterns. + +I have a lot of data now. Let me also check a few more things: +1. How the root package.json `files` field includes MCP dists +2. Whether there are any `index.d.ts` files in the packages (since they reference `./index.d.ts` in exports) +3. Check if any package has a `dist/` directory or build artifacts +4. Check the `bunfig.toml` to see if workspace test exclusions exist +5. Read a few more index.ts files from core packages to see patterns + +Let me also check if there are `index.d.ts` files in packages, and look at the build outputs. + +I now have comprehensive data. Let me also check the `index.d.ts` files that exist to see if they're hand-written or generated, and check if any packages have `dist/` directories. I also want to check how the root `package.json` includes the MCP dists in its `files` field, and whether there are any build scripts in the root that build specific packages. + +I should also check if there are any `.gitignore` or build artifacts in the packages. Let me also look at the `packages/ast-grep-mcp/dist/` since it was mentioned in the root package.json files field. + +Let me also check the ROADMAP.md for the specific mention of Pi and Codex adapters to understand the intended structure. + +I now have all the data I need to provide an exhaustive, convention-compliant answer. Let me synthesize everything into the required format. + +Key findings: +1. **packages/AGENTS.md** - 23 sibling packages, 4 roles. Core packages are pure TS, private, not published as part of main dist (except MCP dists included in root files). +2. **Root package.json workspaces** - 10 workspaces listed (9 core + ast-grep-mcp). lsp-tools-mcp is NOT in workspaces because it's a git submodule with its own package management (npm). +3. **bun.lock** - workspace protocol `workspace:*` used throughout. No `packages/web/` in workspaces. +4. **Core package conventions**: + - Name: `@oh-my-opencode/` + - Version: `0.1.0` (core), `0.0.0` (ast-grep-mcp) + - `type: "module"` + - `private: true` + - `exports`: `{ ".": { "types": "./index.d.ts", "import": "./src/index.ts" } }` + - `types`: `"./index.d.ts"` + - `scripts`: `typecheck` (tsgo), `test` (bun test src/*.test.ts) + - `tsconfig.json`: strict, ESNext, bundler moduleResolution, bun-types + - `index.d.ts`: hand-written 1-line barrel re-exporting from `./src/index` + - No `dist/` directories for core packages - they are consumed directly via `./src/index.ts` + - No build step for core packages +5. **MCP package conventions (ast-grep-mcp)**: + - Has a `build` script: `bun build src/cli.ts --outdir dist --target node --format esm` + - `bin`: `{ "ast-grep-mcp": "dist/cli.js" }` + - `exports`: `{ ".": { "types": "./src/index.ts", "import": "./src/index.ts" } }` (points to src, not dist) + - Has `devDependencies` with `bun-types` + - Root `package.json` includes `packages/ast-grep-mcp/dist` in `files` + - Root build script calls `bun run --cwd packages/ast-grep-mcp build` +6. **lsp-tools-mcp**: Git submodule, NOT in root workspaces, managed with npm, has its own CI/build. Root `package.json` includes `packages/lsp-tools-mcp/dist` in `files` and has `build:lsp-tools-mcp` script using npm. +7. **Consumption patterns**: + - Root `devDependencies` lists all `@oh-my-opencode/*` packages with `workspace:*` + - Source code in `src/` imports directly from `@oh-my-opencode/` (e.g., `@oh-my-opencode/model-core`, `@oh-my-opencode/utils`) + - No tsconfig path-mapping in root or packages - workspace protocol handles resolution + - Core packages import each other via `workspace:*` in their own `dependencies`/`peerDependencies` +8. **Test exclusions**: `bunfig.toml` ignores `packages/web/**` and `packages/lsp-tools-mcp/**` +9. **Where omo-codex should live**: `packages/omo-codex/` following the same conventions as core packages (if it's pure TS logic) or potentially as an adapter package. Based on ROADMAP.md, future adapters consume the Core layer. Since it's an adapter, it might need a build step like ast-grep-mcp if it has a CLI entry, or it could be a pure TS package like core packages if it's just a library. + +Wait, the user said "adapter package". Looking at the ROADMAP, adapters are "Harness-specific glue: OpenCode plugin, Pi extensions, Codex plugins". The current `omo` plugin is the OpenCode adapter and lives in `src/` (not in `packages/`). But the user wants to create `packages/omo-codex/` that follows the SAME conventions as existing core/adapter packages. + +Actually, looking more carefully: the user says "I'll create `packages/omo-codex/` that follows the SAME conventions as existing core/adapter packages." So they want to know the conventions of packages within `packages/` to create a new one there. + +The existing packages in `packages/` are either: +- Core pure TS packages (no build, consumed via src/index.ts) +- MCP packages (have build step, dist/ output, bin entry) +- Platform binaries (compiled artifacts) +- Web (independent Next.js app) + +For a Codex adapter, if it's meant to be a library/package that other things consume, it would likely follow the **core package** conventions if it's pure TS, or **MCP package** conventions if it needs a build output. But since the user specifically says "adapter package" and mentions "future Pi and Codex adapters will consume the same Core layer", an adapter might be more like a thin wrapper. + +However, the user explicitly asked to follow conventions of existing packages. I should present both patterns (core vs MCP) and explain which one fits an adapter. + +Actually, looking at the ROADMAP again: "Layering achieved: Core (7 pure-TS packages) → Adapter (omo plugin) → Platform binaries. Future Pi and Codex adapters will consume the same Core layer." The current `omo` adapter is NOT in `packages/`, it's in `src/`. But the user wants to put `omo-codex` in `packages/`. This might be because they want it as a separate publishable unit or just as a workspace package. + +Given the user's explicit request to follow conventions, I should lay out the conventions clearly and note that a new adapter package would most likely follow the **core package** pattern (pure TS, no build, exported via src/index.ts) if it's a library, or the **MCP package** pattern if it needs a compiled dist/ for a binary. + +Let me also check if there are any other files I should look at, like `.gitignore` in packages, or if any core package has a `dist` script. But I think I have enough. + +Wait, I should also check if the root tsconfig.json has any references to packages. + +I now have all the information needed. Let me compile the exhaustive response. + +Key observations to include: +1. **packages/AGENTS.md** - The governing document for the packages workspace +2. **Root package.json workspaces** - Only 10 entries, all core + ast-grep-mcp. lsp-tools-mcp and web are excluded. +3. **bun.lock** - Uses `workspace:*` protocol. No path-mapping. +4. **Core package conventions**: + - `@oh-my-opencode/` + - `version: "0.1.0"` + - `"type": "module"` + - `"private": true` + - `exports` points `./index.d.ts` for types and `./src/index.ts` for import (no dist!) + - `scripts`: `typecheck` with `tsgo --noEmit -p tsconfig.json`, `test` with `bun test src/*.test.ts` + - `tsconfig.json`: strict, ESNext, bundler, bun-types, include src/**/* + - `index.d.ts`: 1-line hand-written barrel `export * from "./src/index";` + - No build step, no dist directory + - Dependencies on other workspace packages use `workspace:*` +5. **MCP package conventions (ast-grep-mcp)**: + - `version: "0.0.0"` + - Has `bin` entry pointing to `dist/cli.js` + - Has `build` script using `bun build src/cli.ts --outdir dist --target node --format esm` + - Root package.json includes `packages/ast-grep-mcp/dist` in `files` + - Root has `build:ast-grep-mcp` script +6. **lsp-tools-mcp**: Git submodule, NOT in workspaces, managed independently with npm. Root includes its dist in files and has `build:lsp-tools-mcp` using npm. +7. **How omo consumes packages**: + - Root `devDependencies` lists all `@oh-my-opencode/*` with `workspace:*` + - `src/` imports directly from package names (e.g., `import { x } from "@oh-my-opencode/model-core"`) + - No tsconfig path aliases in src/ (explicitly banned per AGENTS.md) + - Root `tsconfig.json` has `rootDir: "src"`, `outDir: "dist"`, `declarationDir: "dist"` - this is for the root plugin build only +8. **Build outputs**: + - Core packages: NO build output. Consumed directly via `./src/index.ts` in exports + - ast-grep-mcp: `dist/` produced by `bun build`, shipped in root npm package via `files` field + - lsp-tools-mcp: `dist/` produced by its own build, shipped in root npm package + - Root plugin: `dist/` (ESM bundle + .d.ts + CLI bundle + schema) +9. **Test setup**: + - `bunfig.toml` excludes `packages/web/**` and `packages/lsp-tools-mcp/**` + - Core packages test with `bun test src/*.test.ts` + - Root `typecheck:packages` runs `tsgo --noEmit -p /tsconfig.json` for each workspace package +10. **Where omo-codex should live**: `packages/omo-codex/` + - If it's a pure TS adapter library: follow core package conventions (no build, src/index.ts, index.d.ts barrel) + - If it needs a CLI/binary: follow ast-grep-mcp conventions (build script, dist/, bin entry) + - Must add to root `package.json` `workspaces` array + - Must add to root `devDependencies` with `workspace:*` + - Must add to root `typecheck:packages` script + - Consider `bunfig.toml` test exclusions if needed + +I should present this in a very structured way with absolute paths and concrete excerpts. + + +**Literal Request**: Read specific files across the `packages/` workspace to understand organization, dependencies, and conventions for adding a new `omo-codex` adapter package. + +**Actual Need**: The user is about to create `packages/omo-codex/` and needs to mirror existing conventions exactly. They need to know: (1) which pattern to follow (core vs MCP), (2) every field and file required, (3) how the root package integrates workspace packages, (4) build/test/typecheck wiring, and (5) absolute paths to reference. + +**Success Looks Like**: A comprehensive convention guide with absolute paths, verbatim excerpts from real files, and a clear checklist for creating `packages/omo-codex/` without trial-and-error. + + + + + +- /Users/yeongyu/local-workspaces/omodex/packages/AGENTS.md - Governing document for the packages workspace; defines 4 roles (Core, MCP, Platform, Web) +- /Users/yeongyu/local-workspaces/omodex/package.json - Root manifest; defines workspaces array, devDependencies with workspace:*, files field including MCP dists, and typecheck:packages script +- /Users/yeongyu/local-workspaces/omodex/bun.lock - Workspace resolution via workspace:* protocol; no path-mapping +- /Users/yeongyu/local-workspaces/omodex/bunfig.toml - Excludes packages/web/** and packages/lsp-tools-mcp/** from root bun test +- /Users/yeongyu/local-workspaces/omodex/tsconfig.json - Root tsconfig for the plugin itself (rootDir: src, outDir: dist); packages have their own tsconfig.json +- /Users/yeongyu/local-workspaces/omodex/packages/utils/package.json - Canonical Core package manifest template +- /Users/yeongyu/local-workspaces/omodex/packages/utils/tsconfig.json - Canonical Core tsconfig template +- /Users/yeongyu/local-workspaces/omodex/packages/utils/src/index.ts - Canonical barrel export pattern +- /Users/yeongyu/local-workspaces/omodex/packages/utils/index.d.ts - Hand-written 1-line type barrel (not present in all core packages, but referenced by exports) +- /Users/yeongyu/local-workspaces/omodex/packages/ast-grep-mcp/package.json - Canonical MCP package manifest (has build script, bin, dist output) +- /Users/yeongyu/local-workspaces/omodex/packages/ast-grep-mcp/src/cli.ts - MCP entry point pattern +- /Users/yeongyu/local-workspaces/omodex/ROADMAP.md - Defines the layering: Core → Adapter → Platform; future Pi/Codex adapters consume the same Core layer + + + + +## 1. Workspace Scope & Role Map + +The `packages/` directory contains 23 sibling packages across 4 roles (per `/Users/yeongyu/local-workspaces/omodex/packages/AGENTS.md`): + +| Role | Packages | Build Output? | In root workspaces? | +|------|----------|---------------|-------------------| +| **Core** (9) | utils, model-core, prompts-core, rules-engine, agents-md-core, ast-grep-core, comment-checker-core, hashline-core, boulder-state | No | Yes | +| **MCP** (2) | ast-grep-mcp, lsp-tools-mcp | Yes (dist/) | ast-grep-mcp only | +| **Platform** (11) | oh-my-opencode-* | Compiled binaries | No | +| **Web** (1) | web | Next.js build | No (independent bun.lock) | + +**Critical**: `lsp-tools-mcp` is a **git submodule** with its own `.git`, `package.json`, and `npm` workflow. It is **NOT** in the root `workspaces` array. + +--- + +## 2. Root package.json Workspaces Declaration + +**File**: `/Users/yeongyu/local-workspaces/omodex/package.json` + +```json +"workspaces": [ + "packages/rules-engine", + "packages/ast-grep-core", + "packages/ast-grep-mcp", + "packages/utils", + "packages/model-core", + "packages/prompts-core", + "packages/comment-checker-core", + "packages/hashline-core", + "packages/boulder-state", + "packages/agents-md-core" +] +``` + +Note: `lsp-tools-mcp` and `web` are **absent**. `prompts-core` is present despite having `test/` at top level. + +--- + +## 3. bun.lock Workspace Protocol + +**File**: `/Users/yeongyu/local-workspaces/omodex/bun.lock` + +Excerpt: +```json +"workspaces": { + ... + "@oh-my-opencode/agents-md-core": "workspace:*", + "@oh-my-opencode/ast-grep-core": "workspace:*", + "@oh-my-opencode/ast-grep-mcp": "workspace:*", + ... +} +``` + +And per-package resolution: +```json +"packages/agents-md-core": { + "name": "@oh-my-opencode/agents-md-core", + "dependencies": { + "@oh-my-opencode/rules-engine": "workspace:*", + "@oh-my-opencode/utils": "workspace:*" + } +} +``` + +**Convention**: All intra-workspace dependencies use **`workspace:*`**. No `^` or `~` between workspace siblings. + +--- + +## 4. Core Package Conventions (The Pattern for `omo-codex` if it is pure TS) + +### 4a. package.json + +**File**: `/Users/yeongyu/local-workspaces/omodex/packages/utils/package.json` (canonical template) + +```json +{ + "name": "@oh-my-opencode/utils", + "version": "0.1.0", + "type": "module", + "private": true, + "description": "Pure TypeScript shared utilities for oh-my-opencode.", + "exports": { + ".": { + "types": "./index.d.ts", + "import": "./src/index.ts" + } + }, + "types": "./index.d.ts", + "scripts": { + "typecheck": "tsgo --noEmit -p tsconfig.json", + "test": "bun test src/*.test.ts" + }, + "dependencies": { + "js-yaml": "^4.1.1", + "jsonc-parser": "^3.3.1" + } +} +``` + +**Observed across all 9 Core packages**: +- `name`: `@oh-my-opencode/` +- `version`: `"0.1.0"` (uniform across core) +- `type`: `"module"` (always) +- `private`: `true` (always; core packages are not independently published today) +- `exports["."]`: `types` → `./index.d.ts`, `import` → `./src/index.ts` (always points to source, **never** `dist/`) +- `types`: `"./index.d.ts"` +- `scripts`: exactly `typecheck` and `test` (no `build` script for core) +- `dependencies`: external deps use `^`, workspace deps use `workspace:*` + +### 4b. tsconfig.json + +**File**: `/Users/yeongyu/local-workspaces/omodex/packages/utils/tsconfig.json` + +```json +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "lib": ["ESNext"], + "types": ["bun-types"] + }, + "include": ["src/**/*"] +} +``` + +**Observed variants**: +- `ast-grep-core` and `ast-grep-mcp` add `"DOM"` to `lib`: `["ESNext", "DOM"]` +- `prompts-core` adds `"allowArbitraryExtensions": true` and `"include": ["src/**/*", "test/**/*"]` because it has top-level `test/` + +**Never present in package tsconfigs**: +- `outDir` +- `rootDir` +- `declaration` / `declarationDir` +- `paths` / `baseUrl` + +### 4c. index.d.ts (hand-written barrel) + +**File**: `/Users/yeongyu/local-workspaces/omodex/packages/rules-engine/index.d.ts` + +```ts +export * from "./src/index"; +``` + +Only 3 core packages currently have this file on disk (`rules-engine`, `comment-checker-core`, `agents-md-core`), but **all** core packages reference it in `exports["."]`. You must create it. + +### 4d. src/index.ts (barrel exports only) + +**File**: `/Users/yeongyu/local-workspaces/omodex/packages/utils/src/index.ts` + +```ts +export * from "./deep-merge" +export * from "./snake-case" +export * from "./record-type-guard" +... +``` + +**Rule**: `index.ts` is a barrel. No logic dumped into it. Every substantive module is a sibling file in `src/`. + +--- + +## 5. MCP Package Conventions (If `omo-codex` needs a CLI/binary) + +### 5a. package.json + +**File**: `/Users/yeongyu/local-workspaces/omodex/packages/ast-grep-mcp/package.json` + +```json +{ + "name": "@oh-my-opencode/ast-grep-mcp", + "version": "0.0.0", + "type": "module", + "private": true, + "bin": { + "ast-grep-mcp": "dist/cli.js" + }, + "exports": { + ".": { + "types": "./src/index.ts", + "import": "./src/index.ts" + } + }, + "scripts": { + "build": "bun build src/cli.ts --outdir dist --target node --format esm", + "typecheck": "tsgo --noEmit -p tsconfig.json", + "test": "bun test src/*.test.ts" + }, + "dependencies": { + "@oh-my-opencode/ast-grep-core": "workspace:*", + "@ast-grep/cli": "^0.41.1" + }, + "devDependencies": { + "bun-types": "1.3.12" + } +} +``` + +**Key differences from Core**: +- `version`: `"0.0.0"` (not `0.1.0`) +- Has `bin` entry pointing to `dist/cli.js` +- Has `build` script using `bun build src/cli.ts --outdir dist --target node --format esm` +- `exports["."]` points to `./src/index.ts` for both types and import (no `index.d.ts`) +- Has `devDependencies` (core packages generally do not) + +### 5b. Root integration for MCP-style packages + +Root `package.json` includes the dist in its own npm publish: + +```json +"files": [ + "dist", + "bin", + "postinstall.mjs", + "packages/lsp-tools-mcp/dist", + "packages/ast-grep-mcp/dist" +] +``` + +Root build script: +```json +"build:ast-grep-mcp": "bun run --cwd packages/ast-grep-mcp build" +``` + +And root `build` script calls it: +```json +"build": "bun run build:ast-grep-mcp && ..." +``` + +--- + +## 6. How the Root `omo` Adapter Consumes These Packages + +### 6a. Root devDependencies + +**File**: `/Users/yeongyu/local-workspaces/omodex/package.json` + +```json +"devDependencies": { + "@oh-my-opencode/ast-grep-core": "workspace:*", + "@oh-my-opencode/ast-grep-mcp": "workspace:*", + "@oh-my-opencode/agents-md-core": "workspace:*", + "@oh-my-opencode/boulder-state": "workspace:*", + "@oh-my-opencode/comment-checker-core": "workspace:*", + "@oh-my-opencode/hashline-core": "workspace:*", + "@oh-my-opencode/model-core": "workspace:*", + "@oh-my-opencode/prompts-core": "workspace:*", + "@oh-my-opencode/rules-engine": "workspace:*", + "@oh-my-opencode/utils": "workspace:*", + ... +} +``` + +**Every** workspace package is listed here with `workspace:*`. + +### 6b. Source imports + +**Pattern observed across `src/`** (40+ matches in 32 files): + +```ts +// src/shared/model-requirements.ts +export type { FallbackEntry, ModelRequirement } from "@oh-my-opencode/model-core" + +// src/hooks/comment-checker/hook.ts +import { extractApplyPatchEdits } from "@oh-my-opencode/comment-checker-core" + +// src/hooks/keyword-detector/search/default.ts +import { SEARCH_MODE_PROMPT } from "@oh-my-opencode/prompts-core" +``` + +**No path aliases** (`@/`, `~/`, etc.) are used in `src/`. The AGENTS.md explicitly bans them in `src/`. + +### 6c. Typecheck wiring + +Root `package.json` `scripts`: +```json +"typecheck:packages": "tsgo --noEmit -p packages/rules-engine/tsconfig.json && tsgo --noEmit -p packages/ast-grep-core/tsconfig.json && tsgo --noEmit -p packages/ast-grep-mcp/tsconfig.json && tsgo --noEmit -p packages/utils/tsconfig.json && tsgo --noEmit -p packages/model-core/tsconfig.json && tsgo --noEmit -p packages/prompts-core/tsconfig.json && tsgo --noEmit -p packages/comment-checker-core/tsconfig.json && tsgo --noEmit -p packages/hashline-core/tsconfig.json && tsgo --noEmit -p packages/boulder-state/tsconfig.json && tsgo --noEmit -p packages/agents-md-core/tsconfig.json" +``` + +**Every** workspace package tsconfig is enumerated here. Adding a new package requires appending to this chain. + +--- + +## 7. Build Outputs & What Gets Shipped + +| Package Type | Build Output | Shipped via | +|--------------|--------------|-------------| +| **Core** | None. Consumed directly via `./src/index.ts` | Not in root `files`. Bundled into root `dist/` by root `bun build` + `tsc` | +| **ast-grep-mcp** | `packages/ast-grep-mcp/dist/` (ESM, node target) | Root `files` includes `packages/ast-grep-mcp/dist` | +| **lsp-tools-mcp** | `packages/lsp-tools-mcp/dist/` (built via npm inside submodule) | Root `files` includes `packages/lsp-tools-mcp/dist` | +| **Root plugin** | `dist/` (ESM bundle, .d.ts, CLI bundle, schema JSON) | Root `files` ships `dist/`, `bin/`, `postinstall.mjs` | + +**Core packages have no `dist/` directory on disk today** (verified via `glob packages/*/dist/*` — no matches). They are compiled into the root `dist/` during the root build. + +--- + +## 8. Path Mapping & Resolution + +- **No tsconfig `paths` or `baseUrl`** in any package tsconfig. +- **No root tsconfig references** to packages. +- Resolution is purely via Bun workspaces + `workspace:*` protocol. +- The root `tsconfig.json` is isolated to the plugin (`rootDir: "src"`, `outDir: "dist"`). + +--- + +## 9. Checklist for Creating `packages/omo-codex/` + +Based on the exhaustive audit, here is the exact convention to follow: + +### If `omo-codex` is a **pure TypeScript adapter library** (follow Core pattern): + +1. **Create directory**: `packages/omo-codex/` +2. **Create `packages/omo-codex/package.json`**: + ```json + { + "name": "@oh-my-opencode/omo-codex", + "version": "0.1.0", + "type": "module", + "private": true, + "description": "Pure TypeScript Codex harness adapter for oh-my-opencode.", + "exports": { + ".": { + "types": "./index.d.ts", + "import": "./src/index.ts" + } + }, + "types": "./index.d.ts", + "scripts": { + "typecheck": "tsgo --noEmit -p tsconfig.json", + "test": "bun test src/*.test.ts" + }, + "dependencies": { + "@oh-my-opencode/utils": "workspace:*", + "@oh-my-opencode/model-core": "workspace:*" + } + } + ``` +3. **Create `packages/omo-codex/tsconfig.json`**: + ```json + { + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "lib": ["ESNext"], + "types": ["bun-types"] + }, + "include": ["src/**/*"] + } + ``` +4. **Create `packages/omo-codex/index.d.ts`**: + ```ts + export * from "./src/index"; + ``` +5. **Create `packages/omo-codex/src/index.ts`** as a barrel. +6. **Update root `package.json`**: + - Add `"packages/omo-codex"` to `workspaces` array + - Add `"@oh-my-opencode/omo-codex": "workspace:*"` to `devDependencies` + - Append `tsgo --noEmit -p packages/omo-codex/tsconfig.json` to `typecheck:packages` script + +### If `omo-codex` needs a **CLI entry point** (follow MCP pattern): + +- Add `bin: { "omo-codex": "dist/cli.js" }` +- Add `build: "bun build src/cli.ts --outdir dist --target node --format esm"` to `scripts` +- Add `packages/omo-codex/dist` to root `files` array +- Add `build:omo-codex: "bun run --cwd packages/omo-codex build"` to root scripts and wire into root `build` + + + + +Ready to proceed. Use the checklist above to scaffold `packages/omo-codex/`. If you need me to generate the actual files (package.json, tsconfig.json, index.d.ts, src/index.ts) verbatim, say the word. + + + +``` + +**Tool: background_output** + +**Input:** +```json +{ + "task_id": "bg_424806df" +} +``` + +**Output:** +``` +Task Result + +Task ID: bg_424806df +Description: Look at sibling oh-my-codex repo for prior art +Duration: 39s +Session ID: ses_1a203dbfcffeOImnYDp4COf7Ky + +--- + +The user wants me to catalog the contents of `/Users/yeongyu/local-workspaces/oh-my-codex/` to understand if it has useful prior art for the new `omo-codex` package. They also mention `/Users/yeongyu/local-workspaces/codex-plugins/` as something being consolidated into omodex. + +Let me break down what I need to do: +1. Get a full directory tree of oh-my-codex (3-4 levels, skip node_modules/dist/.git) +2. Read README.md, package.json, entry points +3. Identify what it does +4. Identify overlap with OpenCode plugin capabilities +5. Identify telemetry/PostHog usage +6. Compare with codex-plugins approach +7. Give a verdict + +I should also check codex-plugins to compare. Let me start with parallel calls to explore both directories. + +The output was truncated for oh-my-codex. I need to read the key files: README.md, package.json, and the main entry point. Let me also get a cleaner tree view. Let me read the critical files in parallel. + +Now I have a good picture. Let me also check for telemetry/PostHog in oh-my-codex, and look at the codex-plugins components in more detail to compare. Let me also check the oh-my-codex plugin structure and any AGENTS.md generator. + +Now I have a very clear picture. Let me also check the telemetry file specifically and the AGENTS.md generator in oh-my-codex, and look at the plugin manifest for codex-plugins to understand the hook structure. + +Now I have a comprehensive picture. Let me also quickly check if oh-my-codex has any PostHog specifically, and look at the codex-plugins components' source structure to compare. + +Now I have all the information I need to provide a comprehensive answer. Let me synthesize everything. + +**oh-my-codex (OMX)**: +- A workflow layer for OpenAI Codex CLI (not a plugin architecture like OpenCode) +- npm package `oh-my-codex`, CLI `omx` +- Written in TypeScript, compiled with tsc +- Has its own CLI, setup, doctor, HUD, team mode, tmux integration +- 30+ agent prompts, 35+ workflow skills +- AGENTS.md orchestration with generated markers +- MCP servers for state, memory, trace, wiki +- Rust sidecars (explore harness, sparkshell, runtime) +- No PostHog - telemetry is local lifecycle logging only +- Codex plugin layout at `plugins/oh-my-codex` for marketplace install + +**codex-plugins**: +- Local marketplace for Codex plugin components +- 5 isolated components: comment-checker, rules, lsp, ultrawork, ultragoal +- Each is a standalone package with hooks, skills, CLI +- Uses Codex's native plugin hook system (SessionStart, UserPromptSubmit, PostToolUse, PostCompact) +- Hooks are command-based (spawn node/python processes) +- Python hooks for ultrawork detection +- This is what we're consolidating into omodex + +**Comparison**: +- oh-my-codex is a full CLI wrapper around Codex with its own runtime +- codex-plugins is a lightweight plugin using Codex's native plugin system +- omodex (oh-my-opencode) is an OpenCode plugin with a completely different architecture + +**Verdict**: +- For `omo-codex` package, codex-plugins is the direct predecessor and should be the primary source +- oh-my-codex has some ideas (AGENTS.md generation markers, skill structure, ultragoal/ultrawork concepts) but the architecture is too different (CLI wrapper vs plugin) +- The telemetry in oh-my-codex is just local MCP lifecycle logs, not PostHog + +Let me format this properly. + + +**Literal Request**: Catalog oh-my-codex contents and compare with codex-plugins to decide what to borrow for omo-codex. +**Actual Need**: Understand prior art in the sibling directory so the new Codex adapter package can reuse proven patterns instead of reinventing them. +**Success Looks Like**: A clear verdict with absolute paths, feature mapping, and a concrete recommendation on what to port vs ignore. + + + + +- /Users/yeongyu/local-workspaces/oh-my-codex/README.md - Full project overview; OMX is a Codex CLI workflow layer +- /Users/yeongyu/local-workspaces/oh-my-codex/package.json - npm manifest: `oh-my-codex` v0.18.1, Node 20+, tsc build, bin `omx` +- /Users/yeongyu/local-workspaces/oh-my-codex/src/index.ts - Library entry: exports setup, doctor, version, mergeConfig, agent definitions, native config installer, HUD +- /Users/yeongyu/local-workspaces/oh-my-codex/src/cli/omx.ts - CLI entry point (compiled `dist/cli/index.js`) +- /Users/yeongyu/local-workspaces/oh-my-codex/src/agents/definitions.ts - 30+ agent role definitions with reasoning effort / posture / model class / routing role +- /Users/yeongyu/local-workspaces/oh-my-codex/src/utils/agents-md.ts - AGENTS.md generator with `` / `` managed block upsert logic +- /Users/yeongyu/local-workspaces/oh-my-codex/src/mcp/lifecycle-telemetry.ts - Local-only MCP lifecycle log telemetry (no PostHog); writes to `~/Library/Logs/oh-my-codex/mcp` on macOS +- /Users/yeongyu/local-workspaces/codex-plugins/README.md - Local marketplace description; 5 isolated components +- /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/README.md - Aggregate plugin root exposing one Codex plugin namespace `omo` +- /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/package.json - Workspace root with 6 component workspaces +- /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/.codex-plugin/plugin.json - Codex plugin manifest: skills, hooks, MCP servers +- /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/hooks/hooks.json - Native Codex hook registrations: SessionStart, UserPromptSubmit, PostToolUse, PostCompact +- /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/rules/src/codex-hook.ts - Rules injection hook implementation for Codex lifecycle +- /Users/yeongyu/local-workspaces/codex-plugins/plugins/omo/components/ultrawork/hooks/ultrawork-detector.py - Python hook that injects ultrawork directive on `ulw`/`ultrawork` keyword match + + + + +## What oh-my-codex is + +`oh-my-codex` (OMX) is a **standalone CLI wrapper and workflow layer** around OpenAI Codex CLI — not a plugin inside Codex. It installs globally as `npm i -g oh-my-codex` and provides: + +- Its own CLI (`omx setup`, `omx doctor`, `omx --madmax --high`) +- Tmux-based HUD/runtime panes for team mode +- 30+ agent role definitions and 35+ workflow skills +- AGENTS.md generation with managed block markers (``) +- MCP servers (state, memory, trace, wiki, code-intel) +- Rust sidecars (explore harness, sparkshell, runtime core) +- Native Codex hooks (legacy `.codex/hooks.json` + plugin-scoped `plugins/oh-my-codex/hooks/hooks.json`) + +It keeps Codex as the execution engine but wraps it with a full external runtime. + +## What codex-plugins is + +`codex-plugins` is a **native Codex plugin** using Codex's official plugin system. It exposes one namespace `omo` with 5 isolated components: + +| Component | What it does | +|-----------|--------------| +| `comment-checker` | Post-tool-use hook runs comment-checker after edits | +| `rules` | Injects project rule files into context via SessionStart / UserPromptSubmit / PostToolUse / PostCompact hooks | +| `lsp` | Exposes LSP diagnostics/navigation/symbols/rename via MCP + post-edit hooks | +| `ultrawork` | Keyword detector (`ulw`/`ultrawork`) injects ultrawork directive into prompt context | +| `ultragoal` | Durable multi-goal orchestration with `.omo/ultragoal/` evidence audit | + +Each component is a standalone package with its own `src/`, `dist/`, `hooks/hooks.json`, `skills/`, and tests. + +## Overlap with OpenCode plugin (omodex) + +| Capability | oh-my-codex | codex-plugins | omodex (OpenCode plugin) | +|------------|-------------|---------------|--------------------------| +| Architecture | External CLI wrapper | Native Codex plugin | OpenCode plugin | +| Rules injection | Yes (native hooks) | Yes (Codex hooks) | Yes (`rules-injector` hook) | +| Comment checker | Yes | Yes | Yes (`comment-checker` hook) | +| LSP tools | Yes (MCP) | Yes (MCP) | Yes (built-in MCP) | +| Ultrawork keyword | Yes | Yes (Python hook) | Yes (`keyword-detector` hook) | +| Ultragoal | Yes (`.omx/ultragoal`) | Yes (`.omo/ultragoal`) | Yes (`boulder-state` + tasks) | +| Team mode | Yes (tmux-based) | No | Yes (`team-mode`) | +| AGENTS.md generator | Yes (with markers) | No | Yes (`agents-md-core`) | +| Telemetry / PostHog | **No PostHog** — only local MCP lifecycle logs | None | None | + +## Telemetry verdict + +**No PostHog or external analytics found in oh-my-codex.** The `lifecycle-telemetry.ts` file is purely local disk logging for MCP server lifecycle events (spawn/crash/exit), written to `~/Library/Logs/oh-my-codex/mcp` on macOS. It is disabled by default unless `OMX_MCP_LIFECYCLE_LOG` is set. + +## Approach comparison (one paragraph) + +oh-my-codex takes a **heavyweight external-orchestrator** approach: it owns the terminal, spawns Codex as a subprocess, manages tmux panes, and intercepts lifecycle via both native Codex hooks and its own runtime watchers. codex-plugins takes a **lightweight in-process plugin** approach: it registers command-based hooks inside Codex's native plugin system, letting Codex own the terminal while injecting context and running post-tool checks as spawned CLI processes. codex-plugins is closer to what a modern Codex adapter should look like because it respects Codex's own plugin contract; oh-my-codex's value is in its workflow concepts (agent definitions, AGENTS.md markers, ultragoal state machine) rather than its CLI-wrapper architecture. + +## Concrete verdict + +| Source | Verdict | Rationale | +|--------|---------|-----------| +| **codex-plugins** | **USE THIS CODE** | This is the direct architectural predecessor. The hook JSON schema, component isolation pattern, skill packaging, and MCP wiring should be ported almost directly into `omo-codex`. The `hooks/hooks.json` structure and `plugin.json` manifest are the canonical Codex plugin interface. | +| **oh-my-codex** | **USE THESE IDEAS** | Borrow the AGENTS.md managed-block marker pattern (``), the agent definition taxonomy (reasoning effort / posture / model class / routing role), and the ultragoal state machine concepts. Do **not** borrow the CLI wrapper architecture, tmux HUD, or Rust sidecars — they are overkill for a Codex plugin adapter. | +| **oh-my-codex telemetry** | **IGNORE** | There is no PostHog or useful telemetry to reuse; local MCP lifecycle logging is not relevant to omo-codex. | + + + + +1. Start `omo-codex` by copying the `codex-plugins/plugins/omo/hooks/hooks.json` structure and `.codex-plugin/plugin.json` manifest as the baseline. +2. Port the 5 component patterns from `codex-plugins/plugins/omo/components/` into the new package, collapsing them into a unified TypeScript build if desired (they currently use separate builds per component). +3. If omo-codex needs AGENTS.md generation, adapt the marker-based upsert logic from `oh-my-codex/src/utils/agents-md.ts` — the `` pattern is proven and non-destructive. +4. No telemetry integration is needed; both predecessors are telemetry-free. + + +``` + +**Tool: background_output** + +**Input:** +```json +{ + "task_id": "bg_f8d4250d" +} +``` + +**Output:** +``` +Task Result + +Task ID: bg_f8d4250d +Description: Find install docs + uninstall + privacy policy +Duration: 56s +Session ID: ses_1a203c10fffemAkXIlkn5WGLL1 + +--- + +The user wants to understand all user-facing documentation around installation, telemetry, and privacy so they can add a new `--codex` flag. They want: + +1. List every file under `docs/` (3 levels deep) +2. Read specific files in full +3. Read CHANGELOG.md (most recent 100 lines) +4. Grep across docs/ + README*.md for specific terms +5. Identify section structure of installation.md +6. Return absolute paths + concrete excerpts + +Let me start by launching multiple parallel calls to gather all this information. + +The user wants an exhaustive compilation of every doc file that mentions installation, configuration, privacy, telemetry, posthog, or uninstall, so they can update them for a new `--codex` flag and `omo-codex` telemetry stream. + +I have already gathered: +1. All files under `docs/` (26 files) +2. Full contents of `installation.md`, `privacy-policy.md`, `terms-of-service.md`, `overview.md` +3. First 100 lines of CHANGELOG.md +4. Grep results across docs/ and README*.md for the keywords + +Now I need to synthesize this into a structured response with: +- Intent analysis +- Absolute paths + concrete excerpts +- Section structure of installation.md +- Next steps + +Let me also check if there are any other files I might have missed. The user asked for docs/ + README*.md. I found 5 README files (README.md, README.ko.md, README.ja.md, README.zh-cn.md, README.ru.md). I should also check if there are any other files outside docs/ that mention these terms, like maybe ROADMAP.md or package.json, but the user specifically asked for docs/ + README*.md. However, to be truly exhaustive, I should note any other user-facing docs. + +Actually, looking at the user's request: "Grep across docs/ + README*.md for: codex, posthog, telemetry, privacy, install, --codex". I did that. But they also said "Compile every doc file that mentions installation, configuration, privacy, telemetry, posthog, or uninstall." So I should list all files from the grep results. + +Let me structure the response: + +1. **Intent Analysis** +2. **Files under docs/ (3 levels deep)** - list all 26 +3. **Section structure of installation.md** - detailed breakdown +4. **Concrete excerpts from each relevant file** - grouped by file +5. **Results block** + +Let me also read a bit more of the CHANGELOG to see if there's anything about codex or telemetry, but the first 100 lines already show the multi-harness refactor. The user only asked for the most recent 100 lines, which I have. + +Wait, I should also check if there are any mentions of "codex" in the docs that are NOT about the model "gpt-5.3-codex" but about the Codex harness. Looking at the grep results: +- `docs/reference/rules-injection-cross-module-comparison.md` mentions `codex-rules` (Codex hook plugin) +- `docs/guide/overview.md` mentions "Pure Codex is single-model" and "Codex CLI" +- `docs/guide/installation.md` mentions "Codex Plan Mode analysis" and "Built for Codex" +- `README.md` mentions "Codex" in the ROADMAP and Hephaestus section + +These are relevant because the user is adding a `--codex` flag for the Codex harness. + +Let me also check `docs/reference/cli.md` and `docs/reference/configuration.md` more closely since they were in the grep results but I didn't read them fully. The user asked to read specific files in full, and I did. For the others, I have grep excerpts which should be sufficient. + +Actually, I should read `docs/reference/cli.md` and `docs/reference/configuration.md` to get the full context around telemetry and installation, since they are reference docs that would need updating. But the user didn't explicitly ask me to read them in full. However, to be "exhaustive", I should probably read the relevant sections or at least note them. + +Wait, the user's explicit read requests were: +- Read `docs/guide/installation.md` in full +- Read `docs/legal/privacy-policy.md` in full +- Read `docs/legal/terms-of-service.md` in full +- Read `docs/guide/overview.md` +- Read CHANGELOG.md (just the most recent 100 lines) + +I did all of these. The grep results give me the other mentions. + +Let me also check if there are any other README files I missed. I found 5. Let me verify with a glob. + +Good, I confirmed there are exactly 5 README files. Now I have all the information needed. Let me compile the exhaustive response. + +Key findings to highlight: + +**Files that need updating for `--codex` flag / `omo-codex` telemetry:** + +1. `/Users/yeongyu/local-workspaces/omodex/docs/guide/installation.md` - The main installation guide. Needs `--codex` flag added to Step 0 (subscription questions), Step 2 (installer flags), examples, and model setup sections. Also telemetry mention. +2. `/Users/yeongyu/local-workspaces/omodex/docs/reference/cli.md` - Mentions `install` subcommand and telemetry. Needs `--codex` flag documentation. +3. `/Users/yeongyu/local-workspaces/omodex/docs/reference/configuration.md` - Mentions telemetry env vars (`OMO_SEND_ANONYMOUS_TELEMETRY`, `OMO_DISABLE_POSTHOG`, `POSTHOG_HOST`). Needs `omo-codex` telemetry stream documentation. +4. `/Users/yeongyu/local-workspaces/omodex/docs/legal/privacy-policy.md` - Mentions `omo_daily_active` telemetry. Needs to mention `omo-codex` telemetry stream if it's separate. +5. `/Users/yeongyu/local-workspaces/omodex/docs/legal/terms-of-service.md` - Mentions anonymous telemetry. May need update. +6. `/Users/yeongyu/local-workspaces/omodex/docs/guide/overview.md` - Mentions installation and "Pure Codex is single-model". Needs `--codex` flag mention in Quick Start. +7. `/Users/yeongyu/local-workspaces/omodex/README.md` - Mentions installation, telemetry, uninstall, and Codex. Needs `--codex` flag and `omo-codex` telemetry. +8. `/Users/yeongyu/local-workspaces/omodex/README.ko.md` - Korean translation. Needs sync. +9. `/Users/yeongyu/local-workspaces/omodex/README.ja.md` - Japanese translation. Needs sync. +10. `/Users/yeongyu/local-workspaces/omodex/README.zh-cn.md` - Chinese translation. Needs sync. +11. `/Users/yeongyu/local-workspaces/omodex/README.ru.md` - Russian translation. Needs sync. +12. `/Users/yeongyu/local-workspaces/omodex/CHANGELOG.md` - Needs entry for `--codex` flag and `omo-codex` telemetry. +13. `/Users/yeongyu/local-workspaces/omodex/docs/reference/features.md` - Mentions installation. May need update. +14. `/Users/yeongyu/local-workspaces/omodex/docs/AGENTS.md` - Internal docs file, but mentions installation. Probably not user-facing but good to know. +15. `/Users/yeongyu/local-workspaces/omodex/docs/guide/agent-model-matching.md` - Mentions installation guide and `gpt-5.3-codex` model. May need `--codex` harness mention. +16. `/Users/yeongyu/local-workspaces/omodex/docs/guide/team-mode.md` - Mentions fresh-install. Probably minimal impact. +17. `/Users/yeongyu/local-workspaces/omodex/docs/reference/rules-injection-cross-module-comparison.md` - Mentions `codex-rules`. Not directly about installation/telemetry but relevant to Codex harness. + +Wait, the user said "Compile every doc file that mentions installation, configuration, privacy, telemetry, posthog, or uninstall." So I should list all of these. + +Let me structure the response carefully. + +**Section structure of installation.md:** +I can derive this from the full read: +- `# Installation` +- `## For Humans` + - Paste prompt + - Alternative: `bunx oh-my-openagent install` + - Platform notes + - Telemetry paragraph (line 28) + - Postinstall / Core CLI subcommands + - Config schema URL + - Operational notes +- `## For LLM Agents` + - IMPORTANT curl note + - Greeting + - `### Step 0: Ask user about subscriptions` (lines 62-105) + - Questions 1-9 (Claude, OpenAI, Gemini, Copilot, OpenCode Zen, Z.ai, OpenCode Go, Kimi for Coding, Vercel AI Gateway) + - Provider selection note + - Warning about Claude subscription + - `### Step 1: Install OpenCode (if not installed)` (lines 109-118) + - `### Step 2: Run the installer` (lines 123-147) + - Installer command with flags + - Examples (lines 131-141) + - CLI actions + - `### Step 3: Verify Setup` (lines 148-163) + - Version check + - `#### Run Doctor Verification` (lines 154-163) + - `### Step 4: Configure Authentication` (lines 164-295) + - Anthropic (Claude) + - Google Gemini (Antigravity OAuth) + - GitHub Copilot (Fallback Provider) + - Z.ai Coding Plan + - OpenCode Zen + - `### Step 5: Understand Your Model Setup` (lines 296-499) + - `#### Model Families: What You're Working With` + - Claude-like Models table + - GPT Models table + - Different-Behavior Models table + - Speed-Focused Models table + - `#### What Each Agent Does and Which Model It Got` + - Claude-Optimized Agents table + - Dual-Prompt Agents table + - GPT-Native Agents table + - Utility Agents table + - `#### Why Different Models Need Different Prompts` + - `#### Custom Model Configuration` + - `#### Provider Resolution` + - `### ⚠️ Warning` (lines 447-452) + - `### Step 6: Verification and Next Steps` (lines 453-499) + - `#### Say 'Congratulations! 🎉' to the user` + - `#### Free advertising` + - `#### Ask for a Star ⭐` + - `#### Tell user the tutorial` + - `#### Advanced Configuration` + +The best place to add Codex installation steps would be: +1. In **Step 0** (subscription questions): Add a 10th question about Codex subscription +2. In **Step 2** (installer flags): Add `--codex=` to the command and examples +3. In **Step 4** (Configure Authentication): Add a new subsection for Codex authentication +4. In **Step 5** (Model Setup): Add Codex models to the tables if applicable +5. In the **For Humans** section: Mention `--codex` flag in the telemetry paragraph or CLI subcommands + +Now let me write the response. + + +**Literal Request**: List doc files, read specific docs, grep for keywords, identify installation.md structure. +**Actual Need**: The user is adding a `--codex` CLI flag and an `omo-codex` telemetry stream. They need to know every single user-facing document that must be updated so the new flag and telemetry stream are documented consistently across all languages and references. +**Success Looks Like**: An exhaustive inventory of every file mentioning install/telemetry/privacy/uninstall, with absolute paths, concrete excerpts showing exactly what text exists today, and a clear map of where in `installation.md` the Codex content should be inserted. + + +Here is the exhaustive inventory. + +--- + +## 1. All files under `docs/` (3 levels deep) + +| # | Absolute Path | Audience | +|---|---------------|----------| +| 1 | `/Users/yeongyu/local-workspaces/omodex/docs/guide/installation.md` | User-facing install guide | +| 2 | `/Users/yeongyu/local-workspaces/omodex/docs/guide/overview.md` | User-facing quick start | +| 3 | `/Users/yeongyu/local-workspaces/omodex/docs/guide/orchestration.md` | User-facing orchestration | +| 4 | `/Users/yeongyu/local-workspaces/omodex/docs/guide/agent-model-matching.md` | User-facing model matching | +| 5 | `/Users/yeongyu/local-workspaces/omodex/docs/guide/team-mode.md` | User-facing team mode | +| 6 | `/Users/yeongyu/local-workspaces/omodex/docs/reference/features.md` | Reference | +| 7 | `/Users/yeongyu/local-workspaces/omodex/docs/reference/configuration.md` | Reference | +| 8 | `/Users/yeongyu/local-workspaces/omodex/docs/reference/cli.md` | Reference | +| 9 | `/Users/yeongyu/local-workspaces/omodex/docs/reference/known-issues.md` | Reference | +| 10 | `/Users/yeongyu/local-workspaces/omodex/docs/reference/prompt-async-gate-rfc.md` | Reference | +| 11 | `/Users/yeongyu/local-workspaces/omodex/docs/reference/rules-injection-cross-module-comparison.md` | Internal comparison | +| 12 | `/Users/yeongyu/local-workspaces/omodex/docs/reference/release-process.md` | Internal process | +| 13 | `/Users/yeongyu/local-workspaces/omodex/docs/superpowers/specs/2026-03-17-model-settings-compatibility-design.md` | Internal spec | +| 14 | `/Users/yeongyu/local-workspaces/omodex/docs/superpowers/specs/2026-04-27-background-task-retry-timeline-design.md` | Internal spec | +| 15 | `/Users/yeongyu/local-workspaces/omodex/docs/superpowers/plans/2026-04-27-background-task-retry-timeline.md` | Internal plan | +| 16 | `/Users/yeongyu/local-workspaces/omodex/docs/superpowers/plans/2026-05-08-log-rotation-design.md` | Internal plan | +| 17 | `/Users/yeongyu/local-workspaces/omodex/docs/superpowers/plans/2026-03-17-model-settings-compatibility-resolver.md` | Internal plan | +| 18 | `/Users/yeongyu/local-workspaces/omodex/docs/troubleshooting/ollama.md` | Troubleshooting | +| 19 | `/Users/yeongyu/local-workspaces/omodex/docs/model-capabilities-maintenance.md` | Maintenance | +| 20 | `/Users/yeongyu/local-workspaces/omodex/docs/legal/terms-of-service.md` | Legal | +| 21 | `/Users/yeongyu/local-workspaces/omodex/docs/legal/privacy-policy.md` | Legal | +| 22 | `/Users/yeongyu/local-workspaces/omodex/docs/manifesto.md` | Philosophy | +| 23 | `/Users/yeongyu/local-workspaces/omodex/docs/AGENTS.md` | Internal docs index | +| 24 | `/Users/yeongyu/local-workspaces/omodex/docs/examples/default.jsonc` | Config example | +| 25 | `/Users/yeongyu/local-workspaces/omodex/docs/examples/planning-focused.jsonc` | Config example | +| 26 | `/Users/yeongyu/local-workspaces/omodex/docs/examples/coding-focused.jsonc` | Config example | + +--- + +## 2. Section structure of `installation.md` (insertion map) + +``` +# Installation +├── ## For Humans +│ ├── Paste-this prompt block +│ ├── Alternative installer command (bunx oh-my-openagent install) +│ ├── Platform binary note +│ ├── [TELEMETRY PARAGRAPH] ← line 28 +│ ├── Postinstall / Core CLI subcommands note ← line 34 +│ ├── Config schema URL +│ └── Operational notes (Claude Code compat, logger path) +│ +├── ## For LLM Agents +│ ├── IMPORTANT curl note +│ ├── Greeting / "oMoMoMoMo..." +│ │ +│ ├── ### Step 0: Ask user about subscriptions +│ │ ├── Q1 Claude Pro/Max (lines 66-70) +│ │ ├── Q2 OpenAI/ChatGPT (lines 72-74) +│ │ ├── Q3 Gemini (lines 76-78) +│ │ ├── Q4 GitHub Copilot (lines 80-82) +│ │ ├── Q5 OpenCode Zen (lines 84-86) +│ │ ├── Q6 Z.ai Coding Plan (lines 88-90) +│ │ ├── Q7 OpenCode Go (lines 92-95) +│ │ ├── Q8 Kimi for Coding (lines 97-99) +│ │ ├── Q9 Vercel AI Gateway (lines 101-103) +│ │ └── Provider-selection warning (lines 105-108) +│ │ [INSERT CODEX SUBSCRIPTION QUESTION HERE — after Q9, before the warning] +│ │ +│ ├── ### Step 1: Install OpenCode (if not installed) +│ │ +│ ├── ### Step 2: Run the installer +│ │ ├── Command template with all flags (line 128) +│ │ ├── [INSERT --codex FLAG INTO TEMPLATE] +│ │ └── 8 examples (lines 133-141) +│ │ [INSERT CODEX EXAMPLE HERE] +│ │ +│ ├── ### Step 3: Verify Setup +│ │ └── Doctor verification +│ │ +│ ├── ### Step 4: Configure Authentication +│ │ ├── Anthropic (Claude) +│ │ ├── Google Gemini (Antigravity OAuth) +│ │ ├── GitHub Copilot (Fallback Provider) +│ │ ├── Z.ai Coding Plan +│ │ └── OpenCode Zen +│ │ [INSERT CODEX AUTH SUBSECTION HERE] +│ │ +│ ├── ### Step 5: Understand Your Model Setup +│ │ ├── Model Families tables +│ │ ├── What Each Agent Does tables +│ │ ├── Why Different Models Need Different Prompts +│ │ ├── Custom Model Configuration +│ │ └── Provider Resolution +│ │ [INSERT CODEX MODEL FAMILY / PROVIDER NOTES IF APPLICABLE] +│ │ +│ ├── ### ⚠️ Warning +│ │ +│ └── ### Step 6: Verification and Next Steps +│ ├── Congratulations +│ ├── Free advertising +│ ├── Ask for a Star +│ ├── Tutorial bullets +│ └── Advanced Configuration +``` + +--- + +## 3. Concrete excerpts from every relevant file + +### A. `docs/guide/installation.md` — primary target + +**Telemetry paragraph (line 28):** +> Anonymous telemetry is enabled by default to track active installations (DAU/WAU/MAU). A single event is sent at most once per UTC day per machine using a hashed installation identifier, and PostHog person profiles are not created. Disable with `OMO_SEND_ANONYMOUS_TELEMETRY=0` or `OMO_DISABLE_POSTHOG=1`. See [Privacy Policy](../legal/privacy-policy.md) and [Terms of Service](../legal/terms-of-service.md). + +**CLI subcommands (line 36):** +> Core CLI subcommands are: `install`, `run`, `doctor`, `mcp-oauth`, `refresh-model-capabilities`, and `get-local-version`. + +**Installer command template (line 128):** +```bash +bunx oh-my-openagent install --no-tui --claude= --gemini= --copilot= [--openai=] [--opencode-go=] [--opencode-zen=] [--zai-coding-plan=] [--kimi-for-coding=] [--vercel-ai-gateway=] [--skip-auth] +``` + +**Existing examples (lines 133-141):** +- `bunx oh-my-openagent install --no-tui --claude=max20 --openai=yes --gemini=yes --copilot=no` +- `bunx oh-my-openagent install --no-tui --claude=yes --gemini=no --copilot=no` +- `bunx oh-my-openagent install --no-tui --claude=yes --openai=yes --gemini=no --copilot=no` +- `bunx oh-my-openagent install --no-tui --claude=no --gemini=no --copilot=yes` +- `bunx oh-my-openagent install --no-tui --claude=yes --gemini=no --copilot=no --zai-coding-plan=yes` +- `bunx oh-my-openagent install --no-tui --claude=no --gemini=no --copilot=no --opencode-zen=yes` +- `bunx oh-my-openagent install --no-tui --claude=no --openai=no --gemini=no --copilot=no --opencode-go=yes` +- `bunx oh-my-openagent install --no-tui --claude=no --gemini=no --copilot=no` + +**Codex references already in doc (not the harness flag):** +- Line 322: `**GPT-5.3-codex** | openai, github-copilot, opencode | Deep coding powerhouse...` +- Line 344: `**GPT-5.3-codex-spark** | openai | Extremely fast...` +- Line 393: `Key insight from Codex Plan Mode analysis...` +- Line 439: `Hephaestus → Claude: **Built for Codex. Claude can't replicate this.**` + +--- + +### B. `docs/legal/privacy-policy.md` — telemetry definition + +**Application scope (line 7):** +> "Application" means the published `oh-my-opencode` CLI package and the OpenCode plugin runtime it installs. + +**Telemetry event (lines 17-23):** +> - `omo_daily_active`, sent at most once per UTC day per machine when the plugin loads or when the `run` CLI is invoked... +> - The Application does not create or update PostHog person profiles... + +**Opt-out (lines 31-41):** +> The Application uses PostHog for anonymous product analytics... Disable with: +> ```bash +> export OMO_SEND_ANONYMOUS_TELEMETRY=0 +> export OMO_DISABLE_POSTHOG=1 +> ``` + +**Third-party services (lines 43-51):** +> - **PostHog** for anonymous product analytics +> - **npm** and **GitHub** for package distribution... + +--- + +### C. `docs/legal/terms-of-service.md` — telemetry reference + +**Line 27-28:** +> Except for the limited anonymous telemetry described in the Privacy Policy, the Application is intended to run locally and does not transmit your repository contents to us as part of ordinary use. + +--- + +### D. `docs/guide/overview.md` — install references + +**Quick Start / Installation (lines 13-22):** +> Paste this into your LLM agent session: +> `Install and configure oh-my-openagent by following the instructions here: https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md` + +**Codex references already present (lines 99-104):** +> **Why this beats vanilla Codex CLI:** +> - **Multi-model orchestration.** Pure Codex is single-model. OmO routes different tasks to different models automatically. + +--- + +### E. `docs/reference/cli.md` — install & telemetry + +**Install subcommand (lines 35-42):** +> ## install +> Interactive installation tool for initial setup. +> ```bash +> bunx oh-my-openagent install +> ``` + +**Telemetry in CLI (line 61):** +> Anonymous telemetry uses PostHog with a hashed installation identifier. Disable with `OMO_SEND_ANONYMOUS_TELEMETRY=0` or `OMO_DISABLE_POSTHOG=1`. + +--- + +### F. `docs/reference/configuration.md` — telemetry env vars + +**Lines 1008-1011:** +> | `OMO_SEND_ANONYMOUS_TELEMETRY` | Set to `0`, `false`, or `no` to disable anonymous telemetry | +> | `OMO_DISABLE_POSTHOG` | Legacy telemetry opt-out flag. Set to `1` or `true` to disable PostHog | +> | `POSTHOG_HOST` | Override the PostHog ingestion host. Defaults to `https://us.i.posthog.com` | + +**Codex model references (lines 741, 813, 823, 859, 889):** +> `"model": "openai/gpt-5.3-codex",` +> `"model": "gpt-5.3-codex",` +> `gpt-5.4-mini` and `gpt-5.3-codex` as OpenAI fallback entries... + +--- + +### G. `docs/reference/features.md` — install mention + +**Line 366:** +> **Requires installation**: + +--- + +### H. `docs/guide/agent-model-matching.md` — install & codex model + +**Line 123:** +> | **OpenAI Plus/Pro** | $20+/mo | `gpt-5.4`, `gpt-5.4-pro`, `gpt-5.5`, `gpt-5.3-codex` | GPT-native agents... + +**Line 133:** +> Add `--claude=max20` (or `yes`) on install. + +**Line 171:** +> | 2 | `gpt-5.3-codex` | same | Still the deep-coding powerhouse... + +**Line 323:** +> | `unspecified-low` | ... | `gpt-5.3-codex` (medium) → ... + +**Line 532:** +> - [Installation Guide](./installation.md) — Setup and authentication + +--- + +### I. `docs/guide/team-mode.md` — install mention + +**Line 32:** +> v4.2.1 adds a fresh-install regression test... + +--- + +### J. `docs/reference/rules-injection-cross-module-comparison.md` — codex harness + +**Lines 6, 14, 20-22, 26-27, 43, 56, 67, 69, 71, 94-96, 102, 115:** +Multiple references to `codex-rules` (the Codex hook plugin), `codex-rules` benchmark harness, and cross-module comparisons with `pi-rules` and `omo`. This is internal reference docs but mentions Codex explicitly. + +--- + +### K. `README.md` — install, telemetry, uninstall, codex + +**Installation section (lines 110-125):** +> Copy and paste this prompt to your LLM agent... +> `https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md` +> Anonymous telemetry is enabled by default... Disable with `OMO_SEND_ANONYMOUS_TELEMETRY=0` or `OMO_DISABLE_POSTHOG=1`. + +**Uninstallation section (lines 315-335):** +> To remove oh-my-openagent: +> 1. Remove the plugin from your OpenCode config... +> 2. Remove configuration files... +> 3. Verify removal... + +**Codex references (lines 99-104, ROADMAP):** +> **Why this beats vanilla Codex CLI:** +> - Pure Codex is single-model. OmO routes different tasks... +> We are restructuring the codebase to support multiple agent harnesses (OpenCode, Codex, Pi, Claude Code, and others). + +--- + +### L. `README.ko.md` — Korean translation + +**Lines 110-125:** Identical structure to README.md — installation prompt, telemetry paragraph with `OMO_SEND_ANONYMOUS_TELEMETRY=0` / `OMO_DISABLE_POSTHOG=1`. + +**Line 363:** +> **Model Setup**: 에이전트-모델 매칭은 [설치 가이드](docs/guide/installation.md#step-5-understand-your-model-setup)에 기본 포함 + +--- + +### M. `README.ja.md` — Japanese translation + +**Lines 109-124:** Identical structure — installation prompt, telemetry paragraph. + +**Line 362:** +> **モデルセットアップ**: エージェントとモデルのマッチングは [インストールガイド](docs/guide/installation.md#step-5-understand-your-model-setup) に組み込み済み + +--- + +### N. `README.zh-cn.md` — Chinese translation + +**Lines 109-124:** Identical structure — installation prompt, telemetry paragraph. + +**Line 362:** +> **模型设置**: Agent 与模型的匹配已内置在 [安装指南](docs/guide/installation.md#step-5-understand-your-model-setup) 中 + +--- + +### O. `README.ru.md` — Russian translation + +**Lines 107-122:** Identical structure — installation prompt, telemetry paragraph. + +**Line 362:** +> **Настройка моделей**: Сопоставление агент–модель встроено в [руководство по установке](docs/guide/installation.md#step-5-understand-your-model-setup) + +--- + +### P. `CHANGELOG.md` — most recent 100 lines (lines 1-100) + +**Key telemetry-related entries:** +- Line 12: `default_mode` config auto-activates ultrawork... +- Line 28: Massive package layering refactor... foundation for the multi-harness roadmap. +- Line 30: `prompt-async-gate` split... +- Lines 83-88: v4.2.3 `packages/rules-core`, `packages/ast-grep-mcp`, `ROADMAP.md` multi-harness docs. + +**No existing mention of `omo-codex` telemetry stream or `--codex` flag in the first 100 lines.** + +--- + +## 4. Summary: Every file that needs updating + +| Priority | File | Why it needs updating | +|----------|------|----------------------| +| **P0** | `/Users/yeongyu/local-workspaces/omodex/docs/guide/installation.md` | Primary install guide. Must add `--codex` question in Step 0, flag in Step 2 command + examples, Codex auth in Step 4, and mention `omo-codex` telemetry if distinct. | +| **P0** | `/Users/yeongyu/local-workspaces/omodex/docs/reference/cli.md` | Reference for `install` subcommand. Must document `--codex` flag and any new telemetry env var. | +| **P0** | `/Users/yeongyu/local-workspaces/omodex/docs/reference/configuration.md` | Reference for env vars. Must add `omo-codex` telemetry stream env var alongside `OMO_SEND_ANONYMOUS_TELEMETRY` / `OMO_DISABLE_POSTHOG`. | +| **P0** | `/Users/yeongyu/local-workspaces/omodex/docs/legal/privacy-policy.md` | Legal doc defining telemetry. Must mention `omo-codex` stream if it is a separate event or separate PostHog project. | +| **P0** | `/Users/yeongyu/local-workspaces/omodex/README.md` | Main landing page. Must add `--codex` to install section, update telemetry paragraph, and possibly mention Codex harness in uninstall steps. | +| **P1** | `/Users/yeongyu/local-workspaces/omodex/docs/legal/terms-of-service.md` | References "limited anonymous telemetry." May need a one-line update if the telemetry scope expands. | +| **P1** | `/Users/yeongyu/local-workspaces/omodex/docs/guide/overview.md` | Quick Start references installation. Should mention `--codex` as an available install flag. | +| **P1** | `/Users/yeongyu/local-workspaces/omodex/CHANGELOG.md` | Needs a new `[Unreleased]` bullet for `--codex` flag and `omo-codex` telemetry. | +| **P1** | `/Users/yeongyu/local-workspaces/omodex/README.ko.md` | Korean translation — must stay in sync with README.md changes. | +| **P1** | `/Users/yeongyu/local-workspaces/omodex/README.ja.md` | Japanese translation — must stay in sync. | +| **P1** | `/Users/yeongyu/local-workspaces/omodex/README.zh-cn.md` | Chinese translation — must stay in sync. | +| **P1** | `/Users/yeongyu/local-workspaces/omodex/README.ru.md` | Russian translation — must stay in sync. | +| **P2** | `/Users/yeongyu/local-workspaces/omodex/docs/guide/agent-model-matching.md` | References install guide and `gpt-5.3-codex` model. May need a note distinguishing the Codex harness from the GPT-5.3-codex model. | +| **P2** | `/Users/yeongyu/local-workspaces/omodex/docs/reference/features.md` | Mentions "Requires installation" — verify if any feature description needs Codex harness qualification. | +| **P2** | `/Users/yeongyu/local-workspaces/omodex/docs/AGENTS.md` | Internal index. Update the "WHERE TO LOOK" table if a new Codex-specific guide is added. | + + + +- /Users/yeongyu/local-workspaces/omodex/docs/guide/installation.md - Primary install guide; needs --codex flag in Step 0, Step 2, Step 4, and telemetry update +- /Users/yeongyu/local-workspaces/omodex/docs/reference/cli.md - CLI reference; documents install subcommand and telemetry opt-out +- /Users/yeongyu/local-workspaces/omodex/docs/reference/configuration.md - Config reference; documents OMO_SEND_ANONYMOUS_TELEMETRY, OMO_DISABLE_POSTHOG, POSTHOG_HOST +- /Users/yeongyu/local-workspaces/omodex/docs/legal/privacy-policy.md - Defines omo_daily_active telemetry and PostHog usage +- /Users/yeongyu/local-workspaces/omodex/docs/legal/terms-of-service.md - References anonymous telemetry scope +- /Users/yeongyu/local-workspaces/omodex/docs/guide/overview.md - Quick Start links to installation; mentions "vanilla Codex CLI" +- /Users/yeongyu/local-workspaces/omodex/README.md - Main README with install, telemetry, uninstall, and Codex references +- /Users/yeongyu/local-workspaces/omodex/README.ko.md - Korean translation of README +- /Users/yeongyu/local-workspaces/omodex/README.ja.md - Japanese translation of README +- /Users/yeongyu/local-workspaces/omodex/README.zh-cn.md - Chinese translation of README +- /Users/yeongyu/local-workspaces/omodex/README.ru.md - Russian translation of README +- /Users/yeongyu/local-workspaces/omodex/CHANGELOG.md - Needs new entry for --codex and omo-codex telemetry +- /Users/yeongyu/local-workspaces/omodex/docs/guide/agent-model-matching.md - References install guide and gpt-5.3-codex model +- /Users/yeongyu/local-workspaces/omodex/docs/reference/features.md - Contains "Requires installation" callout +- /Users/yeongyu/local-workspaces/omodex/docs/AGENTS.md - Internal docs index; may need cross-reference update + + + +The exhaustive scan found **15 files** that must be updated to introduce the `--codex` flag and `omo-codex` telemetry stream. + +**Installation.md structure** (the most critical file) has 6 major sections under `## For LLM Agents`: +1. **Step 0** (subscription questions) — insert a 10th question about Codex subscription before the provider-selection warning +2. **Step 2** (run the installer) — append `[--codex=]` to the command template and add a Codex-specific example +3. **Step 4** (configure authentication) — add a new `#### Codex` subsection after OpenCode Zen +4. **Step 5** (model setup) — add Codex provider/model notes if the harness introduces new model mappings +5. **For Humans** section (line 28) — update the telemetry paragraph if `omo-codex` is a distinct stream + +**Telemetry surface area** is currently defined in 4 places: +- `docs/legal/privacy-policy.md` (lines 17-23, 31-41) — defines `omo_daily_active` and PostHog opt-out +- `docs/reference/configuration.md` (lines 1008-1011) — documents `OMO_SEND_ANONYMOUS_TELEMETRY`, `OMO_DISABLE_POSTHOG`, `POSTHOG_HOST` +- `docs/reference/cli.md` (line 61) — repeats the opt-out env vars +- `README.md` and all 4 translations (lines 125-ish) — repeat the telemetry paragraph + +If `omo-codex` is a separate PostHog project or event name, all 4 of those locations need the new event name and any new opt-out flag documented. + +**Uninstallation** is only documented in `README.md` (lines 315-335). If the `--codex` flag creates new config files or a separate Codex plugin entry, the uninstall steps must list those artifacts. + +**Translations** (`README.ko.md`, `README.ja.md`, `README.zh-cn.md`, `README.ru.md`) mirror the README structure exactly. Any change to the English README's install/telemetry/uninstall blocks must be replicated in all four. + + + +1. Decide whether `omo-codex` telemetry is a separate PostHog project/key or the same project with a distinct event name — this determines how many env vars you need to document. +2. Update `docs/guide/installation.md` first (the source of truth), then `docs/reference/cli.md` and `docs/reference/configuration.md`. +3. Update `docs/legal/privacy-policy.md` before any code ships that sends the new telemetry. +4. Update `README.md`, then batch-translate the install/telemetry/uninstall paragraphs into the 4 localized READMEs. +5. Add a `[Unreleased]` bullet to `CHANGELOG.md`. +6. Run `bun run build:schema` if the new `--codex` flag changes the JSONC config schema. + + +``` + +**Tool: background_output** + +**Input:** +```json +{ + "task_id": "bg_58841818" +} +``` + +**Output:** +``` +Task Result + +Task ID: bg_58841818 +Description: Find build script / publish workflow / platform binary system +Duration: 47s +Session ID: ses_1a2039dedffeJavOZIP82SzIKQ + +--- + +The user wants to understand the build and publish pipeline for the oh-my-opencode project to determine how to ship a new `omo` entry point with a `--codex` flag. They need exhaustive information about: + +1. Files under `script/` +2. Build script (`script/build.ts` or equivalent) +3. Publish script +4. GitHub workflows (publish.yml, ci.yml, publish-platform.yml) +5. Files under `bin/` +6. `postinstall.mjs` +7. `package.json` scripts section +8. Dual-publish mechanism +9. Platform-binary selection logic +10. How bin shims dispatch to native binaries + +Let me start by listing files and reading the key files in parallel. + +Now I need to read the build scripts, publish scripts, GitHub workflows, and bin files. Let me do that in parallel. + +Now I have a lot of the key files. Let me also read the remaining script files and the platform package.json files to understand the full structure. I should also read the `bin/platform.test.ts` and `bin/platform.d.ts` files, and look at one of the platform package directories to understand how they're structured. + +Let me also read `script/build.ts` if it exists - wait, the user asked for `script/build.ts` but the actual build is driven by `package.json` scripts. Let me check if there's a `script/build.ts` or if the build is just in package.json. I already read package.json scripts. Let me also read the remaining script files to be exhaustive. + +Actually, looking at the user's request, they asked for `script/build.ts` (or whichever drives `bun run build`). The build is driven by the `build` script in package.json, not a separate `script/build.ts`. I should note this. + +Let me read the remaining files under `script/` and `bin/` to be exhaustive, and also look at one platform package to understand the structure. + +Now let me read one of the platform package.json files to understand their structure, and also check if there are any other relevant files. Let me read a couple of platform package.jsons and also check the CLI entry point to understand how flags are handled. + +Now I have a comprehensive understanding of the build and publish pipeline. Let me compile all the findings into a structured response. + +Key findings: + +1. **Build system**: No `script/build.ts` exists. The build is driven by `package.json` scripts. The `build` script compiles ESM bundles + CLI bundle + schema. `build:binaries` compiles 11 platform binaries via `script/build-binaries.ts`. + +2. **Dual-publish mechanism**: + - Main package: `oh-my-opencode` is published first, then `oh-my-openagent` is published by temporarily rewriting `package.json` name and optionalDependencies keys. + - Platform packages: Each platform binary is published twice - once as `oh-my-opencode-{platform}` and once as `oh-my-openagent-{platform}` (renamed via jq in publish-platform.yml). + - Trusted publisher OIDC verification covers all 24 packages (2 main + 11*2 platform). + +3. **Platform binary selection**: + - `bin/oh-my-opencode.js` is the JS shim that detects platform/arch/libc/AVX2 and tries to `require.resolve()` the correct platform package. + - `postinstall.mjs` verifies the platform binary is available after install. + - `bin/platform.js` contains the core logic: `getPlatformPackageCandidates()` returns ordered candidates (primary first, baseline fallback for x64). + - Platform packages are `optionalDependencies` in main package.json. + +4. **CLI entry point**: `src/cli/index.ts` → `runCli()` in `cli-program.ts`. Commander.js program. The binary name is hardcoded as "oh-my-opencode" in the program setup. + +5. **For `--codex` / `omo-codex` strategy**: + - The platform binaries are compiled from `src/cli/index.ts` using `bun build --compile`. This is a single entry point. + - If `--codex` is just a flag inside the existing CLI, no new binaries needed - just add the flag to `cli-program.ts`. + - If `omo-codex` needs to be a separate binary name, options are: + a) Add a new bin entry in platform package.jsons pointing to the same binary (but the binary name is `oh-my-opencode` / `oh-my-opencode.exe`) + b) Create a separate binary build with different entry point + c) Create a wrapper/shim + +Let me structure the response with all the requested information. + + +**Literal Request**: List files, read build/publish/CI/bin scripts, identify dual-publish mechanism, platform binary selection, and dispatch logic. + +**Actual Need**: Determine whether shipping `omo` + `--codex` requires new binaries, a new npm package, a new bin shim, or all three. The user needs the build-system constraints to make this packaging decision. + +**Success Looks Like**: A complete inventory of the build/publish pipeline with concrete excerpts showing exactly how binaries are built, how the JS shim dispatches, how dual-publish works, and what levers exist for adding a new entry point. + + + + + +- /Users/yeongyu/local-workspaces/omodex/package.json - Root manifest: scripts, bin entries, optionalDependencies (11 platform packages), dual-publish names +- /Users/yeongyu/local-workspaces/omodex/postinstall.mjs - Post-install verification: reads package.json name, detects libc/AVX2, resolves platform binary via bin/platform.js +- /Users/yeongyu/local-workspaces/omodex/bin/oh-my-opencode.js - Runtime JS shim: detects platform, resolves correct native binary, spawns it with inherited stdio +- /Users/yeongyu/local-workspaces/omodex/bin/platform.js - Shared platform detection: getPlatformPackageCandidates, getBinaryPath, baseline fallback logic +- /Users/yeongyu/local-workspaces/omodex/bin/platform.d.ts - Type declarations for platform detection +- /Users/yeongyu/local-workspaces/omodex/bin/platform.test.ts - Tests for platform detection including packageBaseName override +- /Users/yeongyu/local-workspaces/omodex/script/build-binaries.ts - 11-platform binary builder via `bun build --compile --target={platform}` +- /Users/yeongyu/local-workspaces/omodex/script/publish.ts - Local multi-package publish script (platform packages + main, version sync, changelog) +- /Users/yeongyu/local-workspaces/omodex/script/patch-node-require-shim.ts - Patches dist/index.js for Node/Electron require compatibility +- /Users/yeongyu/local-workspaces/omodex/script/build-schema.ts - Generates JSON Schema from Zod +- /Users/yeongyu/local-workspaces/omodex/script/generate-changelog.ts - Release notes generator +- /Users/yeongyu/local-workspaces/omodex/.github/workflows/publish.yml - GitHub Actions: test/typecheck/preflight-trust → publish-main (oh-my-opencode + oh-my-openagent) → publish-platform → release +- /Users/yeongyu/local-workspaces/omodex/.github/workflows/publish-platform.yml - Matrix build (11 platforms) + dual-publish each platform package as oh-my-opencode-{plat} and oh-my-openagent-{plat} +- /Users/yeongyu/local-workspaces/omodex/.github/workflows/ci.yml - CI: test, typecheck, build, auto-commit schema on master, draft release on dev +- /Users/yeongyu/local-workspaces/omodex/packages/oh-my-opencode-darwin-arm64/package.json - Example platform package: only `bin/` + `package.json`, `os`/`cpu` constraints, single bin entry `oh-my-opencode` +- /Users/yeongyu/local-workspaces/omodex/packages/oh-my-opencode-linux-x64/package.json - Example with `libc: ["glibc"]` constraint +- /Users/yeongyu/local-workspaces/omodex/src/cli/index.ts - CLI entry point: `runCli()` +- /Users/yeongyu/local-workspaces/omodex/src/cli/cli-program.ts - Commander.js program definition with 8 commands + + + + +## 1. Build Entry Point — No `script/build.ts` + +There is **no `script/build.ts`**. The build is driven entirely by `package.json` scripts: + +```json +// /Users/yeongyu/local-workspaces/omodex/package.json (lines 39-56) +"scripts": { + "build": "bun run build:ast-grep-mcp && bun build src/index.ts --outdir dist --target bun --format esm --external @ast-grep/napi --external zod && bun run build:node-require-shim && tsc --emitDeclarationOnly && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm --external @ast-grep/napi && bun run build:schema", + "build:all": "bun run build && bun run build:binaries", + "build:binaries": "bun run script/build-binaries.ts", + ... +} +``` + +The `build` script produces: +- `dist/index.js` — ESM plugin bundle (Bun target) +- `dist/index.d.ts` — TypeScript declarations +- `dist/cli/index.js` — ESM CLI bundle (Bun target) +- `assets/oh-my-opencode.schema.json` + `dist/oh-my-opencode.schema.json` + +## 2. Platform Binary Build (`script/build-binaries.ts`) + +11 platform binaries are built via `bun build --compile` from a **single CLI entry point** `src/cli/index.ts`: + +```typescript +// /Users/yeongyu/local-workspaces/omodex/script/build-binaries.ts (lines 18-30) +export const PLATFORMS: PlatformTarget[] = [ + { platform: "darwin-arm64", packageName: "oh-my-opencode-darwin-arm64", target: "bun-darwin-arm64", binary: "oh-my-opencode", ... }, + { platform: "darwin-x64", packageName: "oh-my-opencode-darwin-x64", target: "bun-darwin-x64", binary: "oh-my-opencode", ... }, + { platform: "darwin-x64-baseline", packageName: "oh-my-opencode-darwin-x64-baseline", target: "bun-darwin-x64-baseline", binary: "oh-my-opencode", ... }, + { platform: "linux-x64", packageName: "oh-my-opencode-linux-x64", target: "bun-linux-x64", binary: "oh-my-opencode", ... }, + ... + { platform: "windows-x64", packageName: "oh-my-opencode-windows-x64", target: "bun-windows-x64", binary: "oh-my-opencode.exe", ... }, + { platform: "windows-x64-baseline", packageName: "oh-my-opencode-windows-x64-baseline", target: "bun-windows-x64-baseline", binary: "oh-my-opencode.exe", ... }, +]; +``` + +Each binary is output to `packages/{packageName}/bin/{binary}`. The binary name is **always** `oh-my-opencode` (or `.exe` on Windows). There is **no separate binary name** per package. + +## 3. Dual-Publish Mechanism (`oh-my-opencode` + `oh-my-openagent`) + +### Main package dual-publish (`.github/workflows/publish.yml`) + +1. Publish `oh-my-opencode` first (with provenance). +2. Then **mutate `package.json` in-place** and publish `oh-my-openagent`: + +```bash +# publish.yml lines 280-295 +jq --arg v "$VERSION" ' + .name = "oh-my-openagent" | + .version = $v | + .optionalDependencies = ( + .optionalDependencies | to_entries | + map(.key = (.key | sub("^oh-my-opencode-"; "oh-my-openagent-")) | .value = $v) | + from_entries + ) +' package.json > tmp.json && mv tmp.json package.json + +npm publish --access public --provenance ... +git checkout -- package.json # restore after publish +``` + +### Platform package dual-publish (`.github/workflows/publish-platform.yml`) + +Each platform artifact is published **twice** from the same extracted directory: + +```bash +# First: oh-my-opencode-{platform} +cd "packages/oh-my-opencode-${{ matrix.platform }}" +npm publish --access public --provenance ... + +# Second: oh-my-openagent-{platform} — rename package.json in-place +jq --arg name "oh-my-openagent-${{ matrix.platform }}" \ + --arg desc "Platform-specific binary for oh-my-openagent (${{ matrix.platform }})" \ + '.name = $name | .description = $desc | .bin = {"oh-my-openagent": (.bin | to_entries | .[0].value)}' \ + package.json > tmp.json && mv tmp.json package.json +npm publish --access public --provenance ... +``` + +The `preflight-trust` job verifies OIDC trusted-publisher setup for **all 24 packages**: +- 2 main: `oh-my-opencode`, `oh-my-openagent` +- 22 platform: `oh-my-opencode-{plat}` + `oh-my-openagent-{plat}` for 11 platforms + +## 4. Platform-Binary Selection at Runtime + +### `bin/platform.js` — core logic + +```javascript +// /Users/yeongyu/local-workspaces/omodex/bin/platform.js (lines 10-39) +export function getPlatformPackage({ platform, arch, libcFamily, packageBaseName = "oh-my-opencode" }) { + let suffix = ""; + if (platform === "linux") { + if (libcFamily === "musl") suffix = "-musl"; + } + const os = platform === "win32" ? "windows" : platform; + return `${packageBaseName}-${os}-${arch}${suffix}`; +} + +export function getPlatformPackageCandidates({ platform, arch, libcFamily, preferBaseline = false, packageBaseName = "oh-my-opencode" }) { + const primaryPackage = getPlatformPackage({ platform, arch, libcFamily, packageBaseName }); + const baselinePackage = getBaselinePlatformPackage({ platform, arch, libcFamily, packageBaseName }); + if (!baselinePackage) return [primaryPackage]; + return preferBaseline ? [baselinePackage, primaryPackage] : [primaryPackage, baselinePackage]; +} +``` + +Key behaviors: +- `packageBaseName` defaults to `"oh-my-opencode"` but can be overridden (tested in `platform.test.ts`). +- For x64 platforms, returns **two candidates**: primary (AVX2) + baseline fallback. +- For ARM64, returns only one candidate (no baseline). +- Linux requires `libcFamily` (`glibc` or `musl`). + +### `bin/oh-my-opencode.js` — JS shim dispatch + +```javascript +// /Users/yeongyu/local-workspaces/omodex/bin/oh-my-opencode.js (lines 83-151) +function main() { + const { platform, arch } = process; + const libcFamily = getLibcFamily(); + const packageBaseName = getPackageBaseName(); // reads from ../package.json name field + const avx2Supported = supportsAvx2(); + + const packageCandidates = getPlatformPackageCandidates({ + platform, arch, libcFamily, + preferBaseline: avx2Supported === false, + packageBaseName, + }); + + const resolvedBinaries = packageCandidates + .map((pkg) => { + try { + return { pkg, binPath: require.resolve(getBinaryPath(pkg, platform)) }; + } catch { + return null; + } + }) + .filter((entry) => entry !== null); + + // Try each candidate in order; on SIGILL, fall back to baseline + for (let index = 0; index < resolvedBinaries.length; index += 1) { + const currentBinary = resolvedBinaries[index]; + const hasFallback = index < resolvedBinaries.length - 1; + const result = spawnSync(currentBinary.binPath, process.argv.slice(2), { + stdio: "inherit", + }); + + if (result.error) { + if (hasFallback) continue; + ... + } + if (result.signal === "SIGILL" && hasFallback) { + continue; // AVX2 not supported → try baseline + } + ... + } +} +``` + +The shim: +1. Reads the **owning package's name** from `../package.json` to determine `packageBaseName`. +2. Resolves platform packages via `require.resolve()` (Node module resolution). +3. Spawns the native binary with `process.argv.slice(2)` (passes all args through). +4. Handles `SIGILL` fallback to baseline binary automatically. + +### `postinstall.mjs` — install-time verification + +Same logic as the shim: detects platform, reads `package.json` name, resolves binary, prints confirmation. Does **not** fail installation if binary missing. + +## 5. Platform Package Structure + +Each platform package contains **only** `bin/` + `package.json`: + +```json +// /Users/yeongyu/local-workspaces/omodex/packages/oh-my-opencode-darwin-arm64/package.json +{ + "name": "oh-my-opencode-darwin-arm64", + "version": "4.4.0", + "os": ["darwin"], + "cpu": ["arm64"], + "files": ["bin"], + "bin": { "oh-my-opencode": "./bin/oh-my-opencode" } +} +``` + +```json +// /Users/yeongyu/local-workspaces/omodex/packages/oh-my-opencode-linux-x64/package.json +{ + "name": "oh-my-opencode-linux-x64", + "version": "4.4.0", + "os": ["linux"], + "cpu": ["x64"], + "libc": ["glibc"], + "files": ["bin"], + "bin": { "oh-my-opencode": "./bin/oh-my-opencode" } +} +``` + +The `bin` field names the CLI command. Currently it is always `oh-my-opencode`. + +## 6. Root `package.json` bin entries + +```json +// /Users/yeongyu/local-workspaces/omodex/package.json (lines 20-23) +"bin": { + "oh-my-opencode": "bin/oh-my-opencode.js", + "oh-my-openagent": "bin/oh-my-opencode.js" +} +``` + +Both npm package names (`oh-my-opencode` and `oh-my-openagent`) install the **same JS shim** under different command names. + + + + + +## Packaging Strategy Decision Matrix for `omo` + `--codex` + +Based on the build system constraints, here are your options: + +### Option A: `--codex` as a flag inside the existing CLI (RECOMMENDED) +- **What to change**: Add `--codex` flag to `src/cli/cli-program.ts` (Commander.js `.option()`). +- **Binaries needed**: **None new**. The existing 11 platform binaries already compile `src/cli/index.ts`, so the flag ships automatically. +- **NPM packages needed**: **None new**. Both `oh-my-opencode` and `oh-my-openagent` get the flag. +- **Bin shim needed**: **None new**. `bin/oh-my-opencode.js` passes all args through (`process.argv.slice(2)`). +- **Effort**: Minimal. Just add the flag and handle it in `cli-program.ts`. + +### Option B: `omo` as a new bin alias for the same shim +- **What to change**: Add `"omo": "bin/oh-my-opencode.js"` to root `package.json` `bin`. +- **Binaries needed**: **None new**. Same binaries, same entry point. +- **NPM packages needed**: **None new**. +- **Bin shim needed**: **None new**. The same `bin/oh-my-opencode.js` works; it reads `packageBaseName` from `package.json`, but that only affects platform package resolution (optionalDependencies), not the CLI behavior. +- **Caveat**: If you want `omo` to resolve platform packages under a different base name (e.g., `omo-darwin-arm64`), you would need new optionalDependencies + new platform packages. See Option D. + +### Option C: `omo-codex` as a separate CLI entry point (different `src/cli/index.ts`) +- **What to change**: Create `src/cli/codex-index.ts` with Codex-specific commands. Modify `script/build-binaries.ts` to build a second binary per platform (e.g., `bin/omo-codex`). +- **Binaries needed**: **11 new binaries** (one per platform). You must add a second `binary` field to each `PlatformTarget` in `build-binaries.ts` and build twice. +- **NPM packages needed**: **None new** if you ship the new binaries inside the existing platform packages. Just add a second `bin` entry to each platform `package.json`: + ```json + "bin": { + "oh-my-opencode": "./bin/oh-my-opencode", + "omo-codex": "./bin/omo-codex" + } + ``` +- **Bin shim needed**: **Optional**. You could add `bin/omo-codex.js` as a copy of `bin/oh-my-opencode.js` that resolves `omo-codex-{platform}` packages, OR you could reuse the same shim if the binary lives in the same package. +- **CI/workflow impact**: `publish-platform.yml` matrix builds would need to build + compress + publish the second binary. `build-binaries.ts` would need a second loop. + +### Option D: `omo-codex` as a completely separate package family +- **What to change**: New root package `omo-codex` with its own `optionalDependencies` (`omo-codex-darwin-arm64`, etc.), new platform packages, new JS shim, new publish workflow logic. +- **Binaries needed**: **11 new binaries**. +- **NPM packages needed**: **24 new packages** (main + 11 platform, each dual-published if desired). +- **Bin shim needed**: **New** (`bin/omo-codex.js`, copy of platform detection logic with `packageBaseName: "omo-codex"`). +- **CI/workflow impact**: Massive. New `publish-omo-codex.yml`, new OIDC trusted publisher entries for 12+ packages, new `optionalDependencies` in root package.json. +- **Effort**: Highest. Not recommended unless `omo-codex` is a genuinely separate product. + +### Summary Recommendation + +If `--codex` is just a mode/flag of the same CLI: **Option A + Option B** (add flag + add `omo` bin alias). This requires: +1. One-line addition to `package.json` `bin`: `"omo": "bin/oh-my-opencode.js"` +2. Adding `--codex` flag to `src/cli/cli-program.ts` +3. No new binaries, no new npm packages, no workflow changes. + +If `omo-codex` needs to be a **separate binary name** that users type: **Option C** — add a second binary to each platform package, but keep it in the same `oh-my-opencode` npm package family. This avoids the OIDC/publish overhead of Option D while giving you a distinct binary. + +Ready to proceed — no follow-up needed unless you want me to implement one of these options. + + + +``` + +**Tool: background_output** + +**Input:** +```json +{ + "task_id": "bg_487b60c3" +} +``` + +**Output:** +``` +Task Result + +Task ID: bg_487b60c3 +Description: Find config schema + plugin entry + how it loads +Duration: 59s +Session ID: ses_1a2037c49ffeD9SNh5Usb2WwBI + +--- + +The user wants an exhaustive analysis of the plugin module factory, config schema, and entry patterns to understand how to write a parallel Codex adapter. They want specific files read and analyzed. + +Let me break down the request: +1. Read `src/index.ts` in full +2. Read `src/testing/create-plugin-module.ts` in full +3. Read `src/plugin-config.ts` in full +4. List `src/config/schema/` (full depth) and read `src/config/schema/index.ts` if exists +5. Identify which schema fields are OpenCode-specific vs harness-agnostic +6. Identify the entry pattern: how does OpenCode discover and load this plugin? +7. Identify any existing "harness abstraction" or "harness:" field in config +8. Read `src/create-managers.ts`, `src/create-tools.ts`, `src/create-hooks.ts` (full) +9. Identify Core-vs-Adapter boundary: which managers/tools/hooks are pure logic vs OpenCode-specific +10. Return absolute paths + concrete excerpts + +I need to launch parallel reads for the files first. Let me start with the file reads and directory listing. + +Now I need to read the remaining files requested: +- `src/config/schema/index.ts` if exists (the directory listing shows no `index.ts`, but let me check if there's one) +- `src/create-managers.ts` +- `src/create-tools.ts` +- `src/create-hooks.ts` +- `src/config/schema/oh-my-opencode-config.ts` (the main schema entry) + +Also need to search for any "harness" abstraction or field in config. Let me launch parallel reads. + +Now I need to read more files to understand the entry pattern and the core-vs-adapter boundary. Let me read: +- `src/plugin-interface.ts` to see how OpenCode hooks are wired +- `src/plugin/types.ts` to see PluginContext +- `src/plugin/tool-registry.ts` to see how tools are registered +- `src/plugin/hooks/create-core-hooks.ts` to see the hook composition +- `src/config/index.ts` to see what's exported from config + +Also need to search for how OpenCode discovers the plugin (package.json, opencode.json, etc.). + +Now I need to understand the entry pattern better. How does OpenCode discover and load this plugin? I should look at: +1. The package.json main entry points +2. Any opencode.json configuration +3. The `postinstall.mjs` or bin scripts +4. The `src/plugin-handlers/` for config loading +5. The `src/cli/config-manager/config-context.ts` for the opencode-vs-openagent layout detection + +Also need to read some core package descriptions to understand the Core-vs-Adapter boundary. Let me read: +- `packages/prompts-core/package.json` (already saw it says "Harness-agnostic markdown prompt loading") +- `packages/model-core/package.json` +- `packages/rules-engine/package.json` +- `packages/agents-md-core/package.json` + +Also need to read `src/plugin/handlers/create-core-hooks.ts` to see the hook composition and identify which are pure logic vs OpenCode-specific. + +Let me also search for any existing "harness" abstraction in the codebase more broadly. + +Now I have a lot of information. Let me read a few more critical files to complete the analysis: +1. `src/plugin/handlers/create-session-hooks.ts` - to see what hooks are created and which are OpenCode-specific +2. `src/plugin/handlers/create-tool-guard-hooks.ts` +3. `src/plugin/handlers/create-transform-hooks.ts` +4. `src/plugin/handlers/create-continuation-hooks.ts` +5. `src/plugin/handlers/create-skill-hooks.ts` + +Also need to read the ROADMAP.md to understand the multi-harness vision. + +Let me also check if there's any `harness` field in the config schema by searching more specifically. + +Now I have a comprehensive view. Let me also read the ROADMAP.md to understand the multi-harness vision, and check a couple more files to understand the entry pattern (how OpenCode discovers the plugin). + +Now I have enough information to provide an exhaustive analysis. Let me structure the response according to the required format. + +Key findings to summarize: + +1. **Entry Pattern**: OpenCode discovers the plugin via `opencode.json`/`opencode.jsonc` `plugin` array containing `"oh-my-openagent"` or `"oh-my-opencode"`. The npm package `oh-my-opencode` exports `dist/index.js` which default-exports a `PluginModule = { id: "oh-my-openagent", server: Plugin }`. OpenCode loads this via `@opencode-ai/plugin` SDK. + +2. **Plugin Module Factory**: `src/index.ts` (18 lines) → `src/testing/create-plugin-module.ts` (186 lines). The factory is `createPluginModule(overrides?: Partial)` returning `{ id, server }`. The `server` is an async function `(input, _options) => Hooks` that runs 7 initialization steps. + +3. **Config Schema**: `src/config/schema/oh-my-opencode-config.ts` (102 lines) composes 30+ sub-schemas. No `index.ts` in `src/config/schema/` — barrel is at `src/config/index.ts`. No existing `harness:` field in config. + +4. **OpenCode-specific vs Harness-agnostic fields**: + - OpenCode-specific: `claude_code`, `disabled_hooks` (OpenCode hook names), `disabled_tools` (OpenCode tool names), `disabled_mcps` (OpenCode MCP names), `disabled_agents` (OpenCode agent names), `disabled_commands` (OpenCode commands), `experimental` (OpenCode experimental flags), `model_fallback` (OpenCode-specific fallback), `runtime_fallback` (OpenCode session.error reactive), `hashline_edit` (OpenCode edit tool integration), `new_task_system_enabled` (OpenCode task system), `openclaw` (OpenCode-specific bidirectional integration), `team_mode` (somewhat generic but currently OpenCode-specific implementation), `sisyphus_agent` (OpenCode-specific agent config), `ralph_loop` (OpenCode-specific), `background_task` (OpenCode-specific background agent integration), `notification` (OpenCode TUI toast), `tmux` (OpenCode tmux integration), `browser_automation_engine` (OpenCode-specific), `websearch` (OpenCode-specific), `i18n` (OpenCode-specific), `keyword_detector` (OpenCode message transform), `babysitting` (OpenCode-specific), `git_master` (generic but tied to OpenCode tool config), `start_work` (OpenCode-specific), `default_mode` (OpenCode-specific), `auto_update` (OpenCode-specific), `comment_checker` (generic logic but OpenCode hook integration), `skills` (generic), `agents` (generic), `categories` (generic), `agent_definitions` (generic), `agent_order` (generic), `disabled_providers` (generic), `mcp_env_allowlist` (generic), `model_capabilities` (generic), `_migrations` (generic). + +5. **Core-vs-Adapter Boundary**: + - **Pure Core (harness-agnostic)**: `packages/utils`, `packages/model-core`, `packages/rules-engine`, `packages/agents-md-core`, `packages/prompts-core`, `packages/comment-checker-core`, `packages/hashline-core`, `packages/boulder-state`, `packages/ast-grep-core`. These have no OpenCode dependencies. + - **OpenCode-specific Adapter layer**: `src/plugin-interface.ts` (11 hook handlers), `src/plugin/` (tool registry, hook composition, chat handlers), `src/create-managers.ts` (uses OpenCode `PluginContext`), `src/create-tools.ts` (uses OpenCode `ToolDefinition`), `src/create-hooks.ts` (uses OpenCode hook shapes), `src/testing/create-plugin-module.ts` (uses `@opencode-ai/plugin` types). + - **Managers**: + - `TmuxSessionManager` — somewhat generic (tmux is external) but wired to OpenCode sessions + - `BackgroundManager` — generic logic but OpenCode-specific integration (subagent sessions, `ctx.client`) + - `SkillMcpManager` — generic (MCP is standard) + - `ConfigHandler` — OpenCode-specific (6-phase pipeline registering with OpenCode) + - `ModelFallbackControllerAccessor` — generic logic + - **Tools**: Most tool implementations in `src/tools/` are generic (grep, glob, session manager, background task, skill, hashline edit) but wrapped in OpenCode `ToolDefinition` schema in `src/plugin/tool-registry.ts`. `call_omo_agent`, `interactive_bash`, `task` (delegate) are OpenCode-specific. + - **Hooks**: The hook factories in `src/hooks/` are mostly generic logic (comment checker, rules injector, context injector, keyword detector, etc.) but are composed into OpenCode hook shapes in `src/plugin/hooks/`. + +6. **No existing harness abstraction**: There is NO `harness:` field in config. No unified plugin interface. The ROADMAP explicitly says "We will not create a grand unified plugin interface that abstracts every harness." The strategy is to extract pure Core packages and write thin adapter shims per harness. + +7. **Codex adapter strategy**: + - Reuse Core packages (`@oh-my-opencode/*`) for pure logic + - Reuse config schema (`src/config/schema/`) — but need to filter OpenCode-specific fields or make them optional + - Write a new entry point (e.g., `src/codex/index.ts`) that exports Codex's plugin shape + - Replace `PluginContext` (OpenCode-specific) with Codex's equivalent context object + - Rewrite `src/plugin-interface.ts` equivalent for Codex's hook names + - Keep the same 7-step init pattern but replace OpenCode-specific steps (agent sort shim, OpenCode config context, OpenCode auth injection, etc.) + - The `createManagers`, `createTools`, `createHooks` factories are mostly reusable if dependency-injected properly + +Let me compile this into the required structured output with absolute paths and concrete excerpts. + + +**Literal Request**: Read specific entry/config/hook files and identify OpenCode-specific vs harness-agnostic boundaries for building a Codex adapter. + +**Actual Need**: Understand the exact plugin factory pattern, config schema composition, and where to draw the line between "reuse as-is" vs "rewrite for Codex" so a parallel adapter can be built without duplicating core logic. + +**Success Looks Like**: Absolute paths to every relevant file, concrete excerpts showing the entry pattern, a categorized list of which schema fields/managers/tools/hooks are pure vs OpenCode-coupled, and a clear next-step blueprint for the Codex adapter. + + + + +- /Users/yeongyu/local-workspaces/omodex/src/index.ts - 18-line plugin entry; default-exports `PluginModule` from `@opencode-ai/plugin` +- /Users/yeongyu/local-workspaces/omodex/src/testing/create-plugin-module.ts - 186-line factory; 7-step init returning `{ id: "oh-my-openagent", server }` +- /Users/yeongyu/local-workspaces/omodex/src/plugin-config.ts - 451-line multi-level JSONC config loader with Zod v4 validation +- /Users/yeongyu/local-workspaces/omodex/src/config/schema/oh-my-opencode-config.ts - 102-line root Zod schema composing 30+ sub-schemas +- /Users/yeongyu/local-workspaces/omodex/src/config/index.ts - barrel exports schema + types +- /Users/yeongyu/local-workspaces/omodex/src/create-managers.ts - 162-line factory for TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler, ModelFallbackControllerAccessor +- /Users/yeongyu/local-workspaces/omodex/src/create-tools.ts - 53-line factory assembling SkillContext + AvailableCategories + ToolRegistry +- /Users/yeongyu/local-workspaces/omodex/src/create-hooks.ts - 98-line 5-tier hook composer (Core + Continuation + Skill) +- /Users/yeongyu/local-workspaces/omodex/src/plugin-interface.ts - 92-line OpenCode hook handler wiring (11 handlers) +- /Users/yeongyu/local-workspaces/omodex/src/plugin/tool-registry.ts - 376-line tool assembly with config gates (20–39 tools) +- /Users/yeongyu/local-workspaces/omodex/src/plugin/types.ts - 26-line `PluginContext` derived from `@opencode-ai/plugin` `Plugin` parameters +- /Users/yeongyu/local-workspaces/omodex/src/plugin/hooks/create-core-hooks.ts - 53-line aggregator (Session + ToolGuard + Transform) +- /Users/yeongyu/local-workspaces/omodex/src/plugin/hooks/create-session-hooks.ts - 305-line 24 session hook factories +- /Users/yeongyu/local-workspaces/omodex/src/plugin/hooks/create-tool-guard-hooks.ts - 180-line 16+ tool-guard hook factories +- /Users/yeongyu/local-workspaces/omodex/src/plugin/hooks/create-transform-hooks.ts - 116-line 5+ transform hook factories +- /Users/yeongyu/local-workspaces/omodex/src/plugin/hooks/create-continuation-hooks.ts - 128-line 7 continuation hook factories +- /Users/yeongyu/local-workspaces/omodex/src/plugin/hooks/create-skill-hooks.ts - 50-line 2 skill hook factories +- /Users/yeongyu/local-workspaces/omodex/src/cli/config-manager/add-plugin-to-opencode-config.ts - 111-line OpenCode plugin registration logic +- /Users/yeongyu/local-workspaces/omodex/src/shared/plugin-identity.ts - plugin name constants (`oh-my-openagent` / `oh-my-opencode`) +- /Users/yeongyu/local-workspaces/omodex/ROADMAP.md - multi-harness architecture direction and non-goals +- /Users/yeongyu/local-workspaces/omodex/package.json - npm entry points (`main: ./dist/index.js`, `exports: { ".": { import: "./dist/index.js" } }`) + + + + +## 1. Plugin Entry Pattern — How OpenCode Discovers and Loads This Plugin + +OpenCode loads the plugin via **npm package name** in its `opencode.json`/`opencode.jsonc` `plugin` array: + +```jsonc +// ~/.config/opencode/opencode.jsonc +{ + "plugin": ["oh-my-openagent"] +} +``` + +The npm package `oh-my-opencode` (dual-published as `oh-my-openagent`) exports: + +```json +// /Users/yeongyu/local-workspaces/omodex/package.json +"main": "./dist/index.js", +"exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + }, + "./server": "./dist/index.js" +} +``` + +The built `dist/index.js` default-exports a `PluginModule` object: + +```typescript +// /Users/yeongyu/local-workspaces/omodex/src/index.ts +import type { PluginModule } from "@opencode-ai/plugin" +import { createPluginModule } from "./testing/create-plugin-module" + +const pluginModule: PluginModule = createPluginModule() +export default pluginModule +``` + +`PluginModule` shape is `{ id: string, server: Plugin }` where `Plugin` is an async function `(input, options) => Hooks`. OpenCode calls `server(input, options)` and receives back an object whose keys are OpenCode hook names (`tool`, `chat.message`, `event`, etc.). + +**For a Codex adapter**, you would create a new entry file (e.g., `src/codex/index.ts`) that exports Codex's equivalent plugin shape, reusing the same Core packages but wrapping them in Codex's API. + +--- + +## 2. Plugin Module Factory — Full Breakdown + +The factory lives in `src/testing/create-plugin-module.ts` (186 lines). It is **dependency-injected** via `PluginModuleDeps`: + +```typescript +// Excerpt from /Users/yeongyu/local-workspaces/omodex/src/testing/create-plugin-module.ts +export type PluginModuleDeps = { + initConfigContext: typeof initConfigContext + installAgentSortShim: typeof installAgentSortShim + loadPluginConfig: typeof loadPluginConfig + createManagers: typeof createManagers + createTools: typeof createTools + createHooks: typeof createHooks + createPluginInterface: typeof createPluginInterface + // ... 30+ other deps +} + +export function createPluginModule(overrides: Partial = {}): PluginModule { + const deps = { ...defaultPluginModuleDeps, ...overrides } + const serverPlugin: Plugin = async (input, _options): Promise => { + deps.installAgentSortShim() + deps.initConfigContext("opencode", null) + const pluginConfig = deps.loadPluginConfig(input.directory, input) + // ... 7-step initialization + const managers = deps.createManagers({ ctx: input, pluginConfig, ... }) + const toolsResult = await deps.createTools({ ctx: input, pluginConfig, managers }) + const hooks = deps.createHooks({ ctx: input, pluginConfig, managers, ... }) + const pluginInterface = deps.createPluginInterface({ ctx: input, pluginConfig, managers, hooks, tools: toolsResult.filteredTools }) + return { + ...pluginInterface, + "experimental.session.compacting": createSessionCompactingHandler(hooks), + "experimental.compaction.autocontinue": createCompactionAutocontinueHandler(hooks), + } + } + return { id: "oh-my-openagent", server: serverPlugin } +} +``` + +**Key insight**: The factory is already designed for testability via dependency injection. A Codex adapter can override `createPluginInterface` (and potentially `createManagers`/`createTools`/`createHooks`) to swap OpenCode-specific wiring for Codex-specific wiring while keeping the same init sequence. + +--- + +## 3. Config Schema — `src/config/schema/` + +There is **no `index.ts` inside `src/config/schema/`**. The barrel is at `src/config/index.ts`, which re-exports from `./schema` (TypeScript resolves `./schema/index.ts` if it existed, but here it resolves `./schema/oh-my-opencode-config.ts` because the package.json does not have an index there — actually the import `from "./schema"` likely resolves to `./schema/oh-my-opencode-config.ts` via tsconfig or bundler config, or there may be an implicit index). The directory contains **41 files** (30 schema + tests). + +### Root Schema (`oh-my-opencode-config.ts`) + +```typescript +// /Users/yeongyu/local-workspaces/omodex/src/config/schema/oh-my-opencode-config.ts +export const OhMyOpenCodeConfigSchema = z.object({ + $schema: z.string().optional(), + new_task_system_enabled: z.boolean().optional(), + default_run_agent: z.string().optional(), + agent_order: z.array(z.string().max(128)).max(64).optional(), + agent_definitions: AgentDefinitionsConfigSchema, + disabled_mcps: z.array(AnyMcpNameSchema).optional(), + disabled_agents: z.array(z.string()).optional(), + disabled_skills: z.array(BuiltinSkillNameSchema).optional(), + disabled_hooks: z.array(z.string()).optional(), + disabled_commands: z.array(BuiltinCommandNameSchema).optional(), + disabled_tools: z.array(z.string()).optional(), + disabled_providers: z.array(z.string()).optional(), + mcp_env_allowlist: z.array(z.string()).optional(), + hashline_edit: z.boolean().optional(), + model_fallback: z.boolean().optional(), + agents: AgentOverridesSchema.optional(), + categories: CategoriesConfigSchema.optional(), + claude_code: ClaudeCodeConfigSchema.optional(), + sisyphus_agent: SisyphusAgentConfigSchema.optional(), + comment_checker: CommentCheckerConfigSchema.optional(), + experimental: ExperimentalConfigSchema.optional(), + auto_update: z.boolean().optional(), + skills: SkillsConfigSchema.optional(), + ralph_loop: RalphLoopConfigSchema.optional(), + runtime_fallback: z.union([z.boolean(), RuntimeFallbackConfigSchema]).optional(), + background_task: BackgroundTaskConfigSchema.optional(), + notification: NotificationConfigSchema.optional(), + model_capabilities: ModelCapabilitiesConfigSchema.optional(), + openclaw: OpenClawConfigSchema.optional(), + i18n: I18nConfigSchema.optional(), + team_mode: TeamModeConfigSchema.optional(), + keyword_detector: KeywordDetectorConfigSchema.optional(), + babysitting: BabysittingConfigSchema.optional(), + git_master: GitMasterConfigSchema.default({ ... }), + browser_automation_engine: BrowserAutomationConfigSchema.optional(), + websearch: WebsearchConfigSchema.optional(), + tmux: TmuxConfigSchema.optional(), + sisyphus: SisyphusConfigSchema.optional(), + start_work: StartWorkConfigSchema.optional(), + default_mode: DefaultModeConfigSchema.optional(), + _migrations: z.array(z.string()).optional(), +}) +``` + +### OpenCode-Specific vs Harness-Agnostic Schema Fields + +| **Harness-Agnostic (reusable for Codex)** | **OpenCode-Specific (needs adapter shim or omission)** | +|---|---| +| `agents` (agent overrides: model, temp, prompt, etc.) | `claude_code` (Claude Code compatibility settings for OpenCode) | +| `categories` (task delegation categories) | `disabled_hooks` (OpenCode hook name enum) | +| `disabled_providers` (provider prefix denylist) | `disabled_tools` (OpenCode tool names) | +| `disabled_agents` (agent names — generic strings) | `disabled_mcps` (OpenCode MCP names) | +| `disabled_skills` (skill names) | `disabled_commands` (OpenCode command names) | +| `mcp_env_allowlist` (env var allowlist for MCP expansion) | `new_task_system_enabled` (OpenCode experimental task system) | +| `agent_definitions` (external agent definition paths) | `hashline_edit` (OpenCode edit tool integration) | +| `agent_order` (display order) | `model_fallback` (OpenCode proactive fallback) | +| `model_capabilities` (model capability overrides) | `runtime_fallback` (OpenCode reactive session.error fallback) | +| `skills` (skill loading config) | `experimental` (OpenCode feature flags: max_tools, preemptive_compaction, etc.) | +| `comment_checker` (AI slop detection config) | `ralph_loop` (OpenCode self-referential loop) | +| `git_master` (git commit footer settings) | `background_task` (OpenCode background agent concurrency) | +| `browser_automation_engine` (playwright/agent-browser provider) | `notification` (OpenCode TUI toast notifications) | +| `websearch` (exa/tavily provider config) | `openclaw` (OpenCode bidirectional event dispatch) | +| `i18n` (locale) | `sisyphus_agent` (OpenCode-specific Sisyphus agent config) | +| `team_mode` (team orchestration settings — *mostly generic* but currently OpenCode-integrated) | `keyword_detector` (OpenCode message-transform keyword injection) | +| `babysitting` (unstable agent monitoring) | `tmux` (OpenCode tmux pane integration) | +| `start_work` (auto_commit flag) | `default_mode` (ultrawork/ralph auto-activation for OpenCode) | +| `_migrations` (idempotent migration tracking) | `auto_update` (OpenCode plugin update checker) | + +**No `harness:` field exists** in the current schema. The ROADMAP explicitly rejects a "grand unified plugin interface." The strategy is: **extract pure logic into Core packages, write thin harness-specific adapters that import Core and wrap in the target harness API.** + +--- + +## 4. Core-vs-Adapter Boundary + +### Already Extracted Core Packages (harness-agnostic) + +These live under `/Users/yeongyu/local-workspaces/omodex/packages/` and have **zero imports from `src/` or `@opencode-ai/plugin`**: + +| Package | Purpose | Absolute Path | +|---|---|---| +| `@oh-my-opencode/utils` | deep-merge, snake-case, frontmatter, file-utils | `/Users/yeongyu/local-workspaces/omodex/packages/utils/` | +| `@oh-my-opencode/model-core` | Model resolution pipeline with ProviderCache DI | `/Users/yeongyu/local-workspaces/omodex/packages/model-core/` | +| `@oh-my-opencode/prompts-core` | Markdown prompt loading + bundled mode prompts | `/Users/yeongyu/local-workspaces/omodex/packages/prompts-core/` | +| `@oh-my-opencode/rules-engine` | Rule discovery + matching + AGENTS.md context | `/Users/yeongyu/local-workspaces/omodex/packages/rules-engine/` | +| `@oh-my-opencode/agents-md-core` | AGENTS.md walk-up discovery + injection | `/Users/yeongyu/local-workspaces/omodex/packages/agents-md-core/` | +| `@oh-my-opencode/ast-grep-core` | ast-grep types, pattern-hints, runner core | `/Users/yeongyu/local-workspaces/omodex/packages/ast-grep-core/` | +| `@oh-my-opencode/comment-checker-core` | apply-patch parser, binary runner | `/Users/yeongyu/local-workspaces/omodex/packages/comment-checker-core/` | +| `@oh-my-opencode/hashline-core` | Hashline edit primitives and diff helpers | `/Users/yeongyu/local-workspaces/omodex/packages/hashline-core/` | +| `@oh-my-opencode/boulder-state` | Work tracking state machine | `/Users/yeongyu/local-workspaces/omodex/packages/boulder-state/` | + +### Managers (`src/create-managers.ts`) + +| Manager | Pure Logic? | OpenCode Coupling | Notes | +|---|---|---|---| +| `TmuxSessionManager` | Mostly generic | Uses `ctx.serverUrl`, `ctx.directory` | Tmux is external; could be reused if Codex provides equivalent session tracking | +| `BackgroundManager` | Generic core | Uses `ctx.client` for subagent spawning | Core logic is harness-agnostic; needs harness-specific subagent spawn adapter | +| `SkillMcpManager` | Pure | None | MCP is standard protocol; fully reusable | +| `ConfigHandler` | OpenCode-specific | Implements OpenCode `config` hook | This is the 6-phase pipeline that registers agents/tools/MCPs/commands with OpenCode | +| `ModelFallbackControllerAccessor` | Pure | None | Just a controller accessor object | + +### Tools (`src/create-tools.ts` + `src/plugin/tool-registry.ts`) + +The **tool implementations** in `src/tools/` (grep, glob, session manager, background task, skill, hashline edit, look-at, delegate-task) are mostly generic business logic. The **OpenCode-specific layer** is the `ToolDefinition` wrapper in `src/plugin/tool-registry.ts` which assembles `Record` (OpenCode's required shape) and applies config gates. + +| Tool Family | Generic? | OpenCode Wrapper Location | +|---|---|---| +| `grep`, `glob`, `ast_grep_*` | Generic file/search tools | `src/plugin/tool-registry.ts` | +| `session_list`, `session_read`, `session_search`, `session_info` | Generic session introspection | `src/plugin/tool-registry.ts` | +| `background_output`, `background_cancel` | Generic background task polling | `src/plugin/tool-registry.ts` | +| `skill`, `skill_mcp` | Generic skill invocation | `src/plugin/tool-registry.ts` | +| `task` (delegate) | Generic subagent delegation | `src/plugin/tool-registry.ts` but uses `ctx.client` | +| `call_omo_agent` | OpenCode-specific | Uses OpenCode agent spawning | +| `interactive_bash` | Generic tmux REPL | Gated on `tmux` binary availability | +| `team_*` | Generic team orchestration | Currently wired to OpenCode `ctx.client` | +| `task_create`, `task_get`, `task_list`, `task_update` | Generic todo tracking | Gated on `experimental.task_system` | +| `edit` (hashline) | Generic hash-anchored edit | Gated on `hashline_edit` | + +### Hooks (`src/create-hooks.ts` + `src/plugin/hooks/`) + +The **hook factories** in `src/hooks/` implement generic logic (comment checking, rules injection, context injection, keyword detection, todo enforcement, etc.). The **OpenCode-specific layer** is in `src/plugin/hooks/` which wraps them into OpenCode `(input, output) => void` handlers and gates them via `disabled_hooks`. + +| Hook Tier | Count | Generic? | OpenCode Wrapper | +|---|---|---|---| +| Session hooks | 24 | Mostly generic | `src/plugin/hooks/create-session-hooks.ts` | +| Tool Guard hooks | 16 [+1] | Mostly generic | `src/plugin/hooks/create-tool-guard-hooks.ts` | +| Transform hooks | 5 [+2] | Mostly generic | `src/plugin/hooks/create-transform-hooks.ts` | +| Continuation hooks | 7 | Mostly generic | `src/plugin/hooks/create-continuation-hooks.ts` | +| Skill hooks | 2 | Mostly generic | `src/plugin/hooks/create-skill-hooks.ts` | + +**Notable OpenCode-specific hooks** that would need Codex equivalents: +- `chat.params` (Anthropic effort, think mode) — Codex may have different param injection points +- `chat.headers` (Copilot `x-initiator`) — Codex-specific if applicable +- `experimental.chat.messages.transform` — Codex may not have this exact hook +- `experimental.chat.system.transform` — Codex may not have this exact hook +- `experimental.session.compacting` / `experimental.compaction.autocontinue` — Codex session lifecycle may differ +- `tool.definition` / `tool.execute.before` / `tool.execute.after` — Codex likely has similar pre/post tool hooks +- `event` (session created/deleted/idle/error/status) — Codex likely has similar events + +--- + +## 5. Concrete Excerpts — Entry Pattern + +**How OpenCode registers the plugin** (`add-plugin-to-opencode-config.ts`): + +```typescript +// /Users/yeongyu/local-workspaces/omodex/src/cli/config-manager/add-plugin-to-opencode-config.ts +const pluginEntry = await getPluginNameWithVersion(currentVersion, PLUGIN_NAME) // "oh-my-openagent@4.4.0" +const config: OpenCodeConfig = { plugin: [pluginEntry] } +writeFileSync(path, JSON.stringify(config, null, 2) + "\n") +``` + +**Plugin identity constants** (`plugin-identity.ts`): + +```typescript +// /Users/yeongyu/local-workspaces/omodex/src/shared/plugin-identity.ts +export const PLUGIN_NAME = "oh-my-openagent" +export const LEGACY_PLUGIN_NAME = "oh-my-opencode" +export const PUBLISHED_PACKAGE_NAME = LEGACY_PLUGIN_NAME +export const CONFIG_BASENAME = "oh-my-openagent" +export const LEGACY_CONFIG_BASENAME = "oh-my-opencode" +``` + +**PluginContext type** (derived from OpenCode `Plugin` parameters): + +```typescript +// /Users/yeongyu/local-workspaces/omodex/src/plugin/types.ts +export type PluginContext = Parameters[0] +export type ToolsRecord = Record +``` + +**ConfigHandler** (the `config` hook handler that OpenCode calls): + +```typescript +// /Users/yeongyu/local-workspaces/omodex/src/plugin-interface.ts +config: managers.configHandler, +``` + +This `configHandler` is the 6-phase pipeline from `src/plugin-handlers/config-handler.ts` that registers agents, tools, MCPs, and commands with OpenCode. + + + + + +### Immediate Action: Codex Adapter Blueprint + +1. **Create a new entry package** (e.g., `packages/codex-adapter/` or `src/codex/`) with its own `package.json` that depends on the Core packages: + - `@oh-my-opencode/utils` + - `@oh-my-opencode/model-core` + - `@oh-my-opencode/prompts-core` + - `@oh-my-opencode/rules-engine` + - `@oh-my-opencode/agents-md-core` + - `@oh-my-opencode/hashline-core` + - `@oh-my-opencode/comment-checker-core` + - `@oh-my-opencode/boulder-state` + +2. **Reuse the config schema** (`src/config/schema/oh-my-opencode-config.ts`) but filter out OpenCode-specific fields at the adapter layer, or make them optional. The schema files themselves are pure Zod and have no OpenCode imports. + +3. **Write a Codex-specific `createPluginModule` equivalent** that mirrors the 7-step init from `src/testing/create-plugin-module.ts` but: + - Removes `installAgentSortShim()` (OpenCode-specific agent ordering hack) + - Replaces `initConfigContext("opencode", null)` with Codex config directory detection + - Removes `injectServerAuthIntoClient(input.client)` (OpenCode SDK auth) + - Replaces `loadPluginConfig(input.directory, input)` with Codex's config loading mechanism + - Keeps `createManagers`, `createTools`, `createHooks` but injects Codex-compatible implementations for `BackgroundManager` subagent spawning and `ConfigHandler` registration + +4. **Rewrite `src/plugin-interface.ts` for Codex hooks** — map the 11 OpenCode hook names to Codex's equivalent lifecycle points. The underlying hook logic in `src/hooks/` is mostly reusable; you mainly need to rewire the caller in `src/plugin/hooks/create-*-hooks.ts`. + +5. **Keep `src/tools/` implementations** — they are generic. Only the `ToolDefinition` wrapper in `src/plugin/tool-registry.ts` needs to be rewritten for Codex's tool schema. + +6. **Read `ROADMAP.md`** (`/Users/yeongyu/local-workspaces/omodex/ROADMAP.md`) before starting — it explicitly states: "We will not create a grand unified plugin interface that abstracts every harness." The recommended pattern is thin adapter shims that import Core and wrap in the target harness API. + +### Files to read next for implementation detail +- `/Users/yeongyu/local-workspaces/omodex/src/plugin-handlers/config-handler.ts` — understand the 6-phase config registration pipeline +- `/Users/yeongyu/local-workspaces/omodex/src/features/background-agent/index.ts` — understand BackgroundManager DI for subagent spawning +- `/Users/yeongyu/local-workspaces/omodex/src/hooks/` individual hook factories — confirm they have no OpenCode imports + + + +``` + +--- + +## Assistant (Sisyphus - Ultraworker · Opus 4.7 · 590.4s) + +_Thinking:_ + + 다섯 개의 백그라운드 작업을 모두 완료했고, 마지막 하나는 MVP에 필수적이지 않으니 나중에 결과를 확인하면 된다. 이제 codex-plugins의 구조를 정리하고 있는데, 다섯 개의 핵심 컴포넌트들을 파악하고 있다. + +omodex 인스톨러의 패턴을 살펴보니 commander 기반의 CLI 구조와 플랫폼별 바이너리 디스패치 방식을 사용하고 있고, PostHog 텔레메트리는 CLI 실행 시점에만 한 번 발생하며 기존 환경변수 설정을 그대로 활용할 수 있다. 빌드 및 배포 시스템은 여러 플랫폼 바이너리를 생성하는 방식으로 구성되어 있다. + +현재 로드맵에서는 Core 패키지 소비를 권장하지만, 실제로는 vendor 후 점진적 마이그레이션이 더 현실적이고, 이미 9개의 Core 패키지가 존재하며 패키지 컨벤션도 정립되어 있다. 계획으로는 `packages/codex-plugin/` 위치에 새 패키지를 추가하되, codex-plugins의 소스 코드만 선택적으로 가져오고 각 컴포넌트의 빌드 프로세스는 유지하면서 CLI에 `omo` 바이너리 엔트리를 추가하는 방식을 고려하고 있다. + +이제 CLI 변경으로 install 명령에 `--codex` 플래그를 추가하고, TypeScript로 포팅한 install-codex 모듈을 만들며, TUI 프롬프트에 Codex 설치 여부를 묻는 단계를 통합할 계획이다. 텔레메트리는 PostHog에 별도 이벤트를 추가하고 Codex 전용 activity 파일을 관리하면서, 글로벌 환경변수와 Codex 전용 플래그로 세밀하게 제어할 수 있도록 설정한다. 마지막으로 설치 가이드, 개인정보 정책, README, CHANGELOG를 업데이트해야 한다. + +호환성 측면에서는 기존 opencode 전용 설치는 유지하면서 `--codex` 플래그로 Codex를 함께 설치할 수 있게 하고, 플래그 없이 실행하면 TUI에서 둘 다 선택하도록 한다. 이제 plan agent를 호출해야 하는데, 이미 충분한 컨텍스트가 있으니 plan agent에게 현재까지의 배경 정보를 전달하면 정확한 계획을 얻을 수 있을 것 같다. 실제 구현 자체는 직관적이라 복잡하지 않을 것 같으니, plan agent 호출 후 momus로 검토한 다음 구현을 시작하자. + +작업 범위를 다시 정리해보니 핵심은 codex-plugins를 omodex로 이동하고, omo 인스톨러를 만들고, --codex 플래그를 추가하고, PostHog처럼 비활성화 토글을 지원하고, 기존 oh-my-opencode와 oh-my-openagent도 새 인스톨러를 사용할 수 있게 하는 것이다. 이를 위해 새로운 codex-plugin 워크스페이스 패키지를 만들어서 기존 codex-plugins에서 필요한 컴포넌트들을 가져오고, 새로운 install-codex 모듈과 telemetry 모듈을 작성하면 된다. I'm realizing the vendoring approach is too heavy—each component in codex-plugins has its own git repo, node_modules, and dist folder, which means pulling everything in would add 5MB+ of source code and require separate npm installs for each one. Instead, I'm thinking of a hybrid approach where I vendor the component source but commit pre-built dist files, then have the install flow copy those compiled artifacts directly to `~/.codex/plugins/cache/` so the build only happens once during the omodex publish workflow, with a follow-up phase to eventually migrate the Codex components to a different structure. + +For the build process itself, I can add a script to the codex-plugin package.json that runs npm ci and npm run build for each component directory, then CI handles that once and includes the dist folders in the npm publish. There's also the lsp component which has its own submodule pointing to lsp-tools-mcp—but omodex already has that same submodule, so I can just remove the duplicate and share the one that's already in the monorepo. + +Actually, the lsp component expects lsp-tools-mcp as an npm workspace dependency, which complicates things. I'm deciding to vendor all 5 components anyway and just accept the disk usage—keeping it simple is more important than optimizing for that. I'll preserve the original component repositories but strip out their .git directories during vendoring. + +Now I'm thinking through the build complexity: the components use npm and tsc while omodex is bun-based. The cleanest approach is to vendor the built dist/ artifacts alongside the source code, similar to how codex-plugins already handles it. The minified JavaScript is only around 500KB total, so it's manageable. I'll adjust the .gitignore to allow these dist directories in the vendored components. + +Rather than invoking the plan agent for validation, I think it's more efficient to just write out the implementation steps directly and let momus review the results—the complexity here doesn't really warrant the extra planning overhead. + +Actually, wait—the ULW mode rules explicitly require calling the plan agent for any non-trivial task, and this definitely qualifies. I need to invoke it properly, preserving the task_id for follow-ups. The background task exploring categories can keep running in parallel; I'll use those results if they arrive, but won't cancel it. Let me call the plan agent now. + +이제 모든 컨텍스트가 모였습니다. ULW 모드 mandatory 절차에 따라 **plan agent**를 호출해서 work plan을 구체화하고, 동시에 마지막 백그라운드 결과도 대기. + +**Tool: task** + +**Input:** +```json +{ + "subagent_type": "plan", + "description": "Plan codex-plugins port + omo installer + --codex flag + telemetry", + "run_in_background": false, + "load_skills": [], + "prompt": "Build a detailed work plan for the following user request, executed via a PR against `/Users/yeongyu/local-workspaces/omodex` (branch: dev).\n\n## USER REQUEST (Korean, distilled)\n\n> Port `../codex-plugins` into `omodex`, build an installer named `omo`, add a `--codex` flag, set up PostHog telemetry the same way OmO uses it (with a disable toggle), and make sure the existing `bunx oh-my-opencode install` / `bunx oh-my-openagent install` flows also work through the new `omo` installer codepath.\n\n## FULL CONTEXT ALREADY GATHERED\n\n### A. codex-plugins source repo (`/Users/yeongyu/local-workspaces/codex-plugins/`)\n- Local Codex marketplace. NOT a git repo at the root.\n- Contains one plugin namespace `omo` at `plugins/omo/` with 5 isolated components (each is its own vendored git repo - clones of `code-yeongyu/codex-{rules,comment-checker,lsp,ultrawork,ultragoal}`):\n - **rules** (TS, 4793 LOC): `SessionStart`/`UserPromptSubmit`/`PostToolUse`/`PostCompact` hooks injecting `AGENTS.md`/`CLAUDE.md`/`.omo/rules/**`. Runtime no-deps.\n - **comment-checker** (TS, 1228 LOC): `PostToolUse` hook runs `@code-yeongyu/comment-checker` binary after `apply_patch`/`edit`/etc.\n - **lsp** (TS, 5208 LOC + Python 2): Codex hooks + nested `packages/lsp-tools-mcp/` MCP server (SAME submodule URL as omodex/packages/lsp-tools-mcp: `https://github.com/code-yeongyu/lsp-tools-mcp`).\n - **ultrawork** (Python only, 331 LOC): `ultrawork-detector.py` injects 5,821-char directive on `\\b(?:ultrawork|ulw)\\b` match. `sync-agents.py` copies bundled `agents/*.toml` into `CODEX_HOME/agents`.\n - **ultragoal** (TS, 5839 LOC): Durable multi-goal orchestration with `.omo/ultragoal/` state, steering directives via `UserPromptSubmit`.\n- Component sizes: each ~111M with node_modules (109M) + dist (~200KB) + .git (~2MB). Source only: ~1-5MB total.\n- Aggregate manifest at `plugins/omo/.codex-plugin/plugin.json` declaring `skills: ./skills/, hooks: ./hooks/hooks.json, mcpServers: ./.mcp.json`.\n- Aggregate `hooks/hooks.json` dispatches to component CLIs via `node \"${PLUGIN_ROOT}/components//dist/cli.js\" hook ` or `python3 \"${PLUGIN_ROOT}/components/ultrawork/hooks/*.py\"`.\n- Aggregate `.mcp.json` registers `lsp` stdio server at `./components/lsp/packages/lsp-tools-mcp/dist/cli.js`.\n- `.agents/plugins/marketplace.json` declares marketplace `code-yeongyu-codex-plugins` with one plugin `omo`.\n- `scripts/install-local.mjs` is the existing Node installer:\n - Reads marketplace.json\n - For each plugin: `npm install && npm run build` in source\n - Copies to `~/.codex/plugins/cache////` (filter excludes .git/node_modules)\n - Runs `npm install --omit=dev` in cache\n - Rewrites `.mcp.json` paths to absolute\n - Writes `~/.codex/config.toml` blocks: `[features] plugins=true plugin_hooks=true`, `[marketplaces.]`, `[plugins.\"@\"]`, `[hooks.state.\"\"]` with SHA-256 trusted_hash\n - Links package.json `bin` entries to `~/.local/bin/`\n- Components are npm-based (npm@11.12.1), TypeScript via `tsc -p tsconfig.build.json`, vitest tests. Aggregate root has `npm workspaces`.\n\n### B. omodex target repo (`/Users/yeongyu/local-workspaces/omodex/`)\n- Bun-only runtime. ESM. Zod v4 config schemas. Commander.js CLI.\n- Plugin entry: `src/index.ts` → `src/testing/create-plugin-module.ts` → 7-step init.\n- CLI entry: `src/cli/index.ts` → Commander program in `src/cli/cli-program.ts` with 8 commands (install/run/doctor/get-local-version/version/refresh-model-capabilities/mcp-oauth/boulder).\n- bin entries (`package.json` lines 20-23): `\"oh-my-opencode\": \"bin/oh-my-opencode.js\"`, `\"oh-my-openagent\": \"bin/oh-my-opencode.js\"`. Both point to same JS shim.\n- `bin/oh-my-opencode.js` is a Node shim that detects platform/arch/libc/AVX2, resolves `oh-my-opencode-` package, spawnSyncs binary with `process.argv.slice(2)` (passes ALL args through).\n- 11 compiled platform binaries via `bun build --compile` from `src/cli/index.ts`. Output: `packages/oh-my-opencode-/bin/oh-my-opencode`.\n- Dual npm publish: `oh-my-opencode` + `oh-my-openagent` (rename package.json via jq in `.github/workflows/publish.yml`).\n- workspace packages (root package.json lines 8-19): rules-engine, ast-grep-core, ast-grep-mcp, utils, model-core, prompts-core, comment-checker-core, hashline-core, boulder-state, agents-md-core.\n- `packages/lsp-tools-mcp` is a git SUBMODULE pointing to SAME repo as codex-lsp's nested lsp-tools-mcp.\n- Convention for Core packages: `@oh-my-opencode/`, version `0.1.0`, `type: \"module\"`, `private: true`, exports `./src/index.ts` directly (no build for core), `bun-types`, `tsgo --noEmit`.\n- Convention for MCP packages (ast-grep-mcp): has `build` script using `bun build src/cli.ts --outdir dist --target node --format esm`, has `bin` entry, root `package.json files` includes its `dist/`.\n\n### C. CLI installer architecture\n- `src/cli/install.ts` routes to TUI or non-TUI installer based on `args.tui`.\n- `src/cli/cli-installer.ts` (150 LOC): validation → OpenCode check → addPluginToOpenCodeConfig → writeOmoConfig.\n- `src/cli/tui-installer.ts`: interactive @clack/prompts flow.\n- `src/cli/tui-install-prompts.ts`: subscription prompts per provider.\n- `src/cli/install-validators.ts`: validateNonTuiArgs/argsToConfig/detectedToInitialValues.\n- `src/cli/types.ts`: InstallArgs (claude/openai/gemini/copilot/opencode-zen/zai-coding-plan/kimi-for-coding/opencode-go/vercel-ai-gateway/skip-auth), InstallConfig, DetectedConfig.\n- `src/cli/config-manager/`: 28 files for OpenCode config manipulation. Key: `add-plugin-to-opencode-config.ts` writes `oh-my-openagent@` to `~/.config/opencode/opencode.json(c)` plugin array. `write-omo-config.ts` writes `~/.config/opencode/oh-my-openagent.json(c)`.\n\n### D. PostHog telemetry (current state)\n- `src/shared/posthog.ts` (188 LOC): hardcoded API key `phc_CFJhj5HyvA62QPhvyaUCtaq23aUfznnijg5VaaGkNk74`, single event `omo_daily_active`, sha256(`PUBLISHED_PACKAGE_NAME + \":\" + hostname`) distinct_id.\n- `src/shared/posthog-activity-state.ts` (85 LOC): dedup via `~/.local/share/oh-my-opencode/posthog-activity.json` UTC-day check.\n- `src/shared/plugin-identity.ts`: PLUGIN_NAME=\"oh-my-openagent\", PUBLISHED_PACKAGE_NAME=\"oh-my-opencode\", CACHE_DIR_NAME=\"oh-my-opencode\".\n- Opt-out env vars: `OMO_SEND_ANONYMOUS_TELEMETRY=0/false/no` or `OMO_DISABLE_POSTHOG=1/true`.\n- Only call site in production: `src/cli/run/runner.ts` calls `trackActive(distinctId, \"run_started\")`. `createPluginPostHog()` exists but unused.\n\n### E. ROADMAP direction (`/Users/yeongyu/local-workspaces/omodex/ROADMAP.md`)\n- Multi-harness refactor in progress. Future Pi and Codex adapters MUST consume the Core packages layer.\n- \"We will NOT create a grand unified plugin interface that abstracts every harness.\"\n- Adapter shims should be thin wrappers around Core packages.\n\n## CONSTRAINTS\n\n1. **Behavior preservation**: existing `bunx oh-my-opencode install` and `bunx oh-my-openagent install` MUST continue to work unchanged. `--codex` is purely additive.\n2. **No path aliases** in src/ (e.g., `@/`). Use relative imports within a module, barrel imports across modules.\n3. **No emojis** in code or comments.\n4. **No `as any`, `@ts-ignore`, `@ts-expect-error`**.\n5. **No catch-all files** (`utils.ts`, `helpers.ts`, etc).\n6. **250 pure LOC ceiling** per file (rule: `.omo/rules/file-size-architectural-smell.md`).\n7. **TDD discipline**: regression test for new behavior FIRST, then implement.\n8. **Bun only**: never npm/yarn/pnpm at the root. But the vendored Codex components themselves use npm internally (we cannot rewrite them all in this PR).\n9. **Atomic commits**: separate concerns into discrete commits (vendor, installer, telemetry, docs).\n10. **PRs into dev MUST use `--merge` (merge commit), NOT squash/rebase.**\n\n## DESIGN CHOICES TO MAKE\n\nThe plan must decide and justify:\n\n1. **Where does the Codex plugin code live?** Options:\n - (a) `packages/codex-plugin/` as a new workspace package (consistent with ROADMAP layering)\n - (b) Top-level `codex-plugin/` directory (non-workspace)\n - (c) Under `src/codex/` (adapter shim model)\n\n2. **How are the 5 components shipped?** Options:\n - (a) Vendor source ONLY, build at npm-publish time via CI (smaller git, slower publish)\n - (b) Vendor source AND prebuilt dist/ (larger git, faster install, matches existing codex-plugins pattern)\n - (c) Rewrite components to consume omodex Core packages (out of scope for this PR per ROADMAP)\n\n3. **How does the `omo install --codex` flow install the Codex plugin?** Options:\n - (a) Port `scripts/install-local.mjs` from Node to TypeScript inside `src/cli/install-codex/` and invoke from CLI\n - (b) Embed `install-local.mjs` verbatim as a runtime script and shell out to it\n - (c) Re-implement using existing omodex config-manager primitives\n\n4. **PostHog telemetry separation**:\n - Same PostHog project + new event name `omo_codex_daily_active`?\n - Or new project + new API key?\n - Single global opt-out (`OMO_SEND_ANONYMOUS_TELEMETRY=0`) or separate per-product opt-out (`OMO_CODEX_DISABLE_POSTHOG=1`)?\n\n5. **Bin entry strategy**: add `\"omo\": \"bin/oh-my-opencode.js\"` to root `package.json`. Should the JS shim ALSO be renamed/aliased? (Probably no - same shim, just one more bin name.)\n\n6. **TUI flow**: should `omo install` (no flags) show a single combined wizard asking about BOTH OpenCode providers AND Codex installation? Or should `--codex` be a separate pass?\n\n## DELIVERABLES (what the plan must produce)\n\nProduce a plan with:\n- A wave-based parallel execution graph (which tasks can run in parallel, which are sequential)\n- Per-task: WHERE (file paths), WHY (which scenario it advances), HOW (atomic steps), VERIFY (test/diagnostic command)\n- A scenario contract: at least 3 binary-observable scenarios that must PASS at completion, with their real-surface evidence (bunx invocation transcripts, `~/.codex/config.toml` diff, posthog event capture)\n- A list of files to CREATE vs EDIT (paths only, no full content)\n- Acceptance criteria mapped to scenarios\n- Explicit answers to the 6 design choices above\n- Identification of risks and blockers\n- A test-first ordering: which regression tests are written before which implementation\n\nThe plan will be handed off to a sub-agent for execution. Be exhaustive, leave nothing implicit." +} +``` + +**Output:** +``` +Task completed in 6m 45s. + +Agent: plan +⚠️ Model routing: parent used anthropic/claude-opus-4-7, this subagent used anthropic/claude-opus-4-6 (via category: unknown) + +--- + +Now I have all four exploration results. Let me synthesize everything and build the comprehensive work plan. I have: + +1. **CLI Installer Architecture** - Complete understanding of the install flow, types, config managers +2. **PostHog Telemetry** - Complete understanding of tracking, opt-out, distinct_id +3. **Codex-plugins Source** - Complete understanding of all 5 components, install-local.mjs, hooks +4. **Workspace Packages** - Complete understanding of conventions, build system, CI/CD + +Now I need to make the 6 design decisions and build the detailed plan. + +For the first decision about where the Codex plugin code lives, I'm weighing three options: creating it as a new workspace package, placing it at the top level as a non-workspace directory, or nesting it under src/codex as an adapter shim. The ROADMAP explicitly states we won't create a unified plugin interface and that adapter shims should be thin wrappers, but the codex plugin components are currently vendored npm-based components with their own build systems rather than consuming omodex Core packages, which is planned as future work. + +Option (a) as a workspace package would conflict with Bun's dependency management since the plugin uses npm internally. Option (b) at the top level breaks convention since top-level directories serve specific purposes. Option (c) under src/codex would inappropriately mix vendored npm code with the Bun-native source tree. I'm leaning toward a hybrid approach: placing it in `packages/codex-plugin/` as a directory but excluding it from the workspace array to keep it isolated while maintaining a logical structure. + +The real constraint here is that the codex components have their own npm node_modules and build systems that need to be vendored. Since the ROADMAP envisions future adapters consuming Core packages but this PR is just porting existing code, I need a self-contained location for the vendored codex-plugin code with its own npm-based build system, separate from the Bun workspace. The installer code that handles this would sit in `src/cli/`. + +For shipping the components, I'm weighing whether to vendor just source code and build at publish time versus vendoring prebuilt dist files. The existing installer already builds at install time, but since we're embedding this in the npm package itself, vendoring the prebuilt dist makes more sense—it lets `omo install --codex` just copy files without requiring npm to be available during installation. + +The installer workflow would then copy the vendored components into the cache directory, run `npm install --omit=dev` for runtime dependencies, rewrite the paths in the config file, and update the main config. This approach keeps the user-facing install fast while still handling any runtime dependency setup needed. + +Now I'm thinking through how to implement the `omo install --codex` command itself. The existing install script handles a lot—reading the marketplace manifest, building plugins, copying files, installing dependencies, rewriting paths, linking binaries, computing hashes, and pruning the cache. Rather than embedding it as a shell script or reimplementing everything from scratch, I should port it to TypeScript and integrate it directly into the CLI structure in `src/cli/install-codex/`. That way it fits naturally with the existing architecture and I can leverage the config-manager primitives where they apply. + +For PostHog telemetry, keeping it in the same project makes sense since Codex is part of the OMO product family. I'll use a distinct event name like `omo_codex_daily_active` to separate Codex usage signals from OpenCode, and the distinct_id should track individual users across both products. + +For opt-out behavior, the existing environment variables `OMO_SEND_ANONYMOUS_TELEMETRY=0` or `OMO_DISABLE_POSTHOG=1` should handle all telemetry globally—no need for per-product controls. + +The bin entry strategy is straightforward: add `"omo"` to the root package.json pointing to the existing JS shim, which already detects the platform and spawns the correct binary. All three command names share this same entry point. + +For the TUI flow, running `omo install` without flags shows the OpenCode wizard, while `omo install --codex` triggers the Codex-specific flow. They write to different config locations and should remain separate, though you could run both in one command. But I need to reconsider the requirement—the existing `bunx oh-my-opencode install` and `bunx oh-my-openagent install` commands should also work through the new `omo` installer, which means the routing logic needs to handle all three entry points correctly. I'm realizing the `--codex` flag should work additively—when passed, it runs the Codex installer after the standard OpenCode flow completes, whether in TUI or non-TUI mode. For users who want Codex-only installation, I could use a combination like `--codex --skip-auth` to bypass the OpenCode provider prompts, or keep it simple and just make `--codex` always additive to the base install. + +Now I'm mapping out the implementation: I need to create the vendored Codex plugin source tree under `packages/codex-plugin/`, then build out a new installer module at `src/cli/install-codex/` that handles the build, caching, and symlinking logic similar to the existing local installer. + +Setting up the module structure... I need to reconsider the file structure with the 250 LOC limit in mind. The Codex installer logic from the existing script is around 400-500 lines total, so I'll need to split it across multiple focused files to keep each one manageable. I'm also thinking through how to handle the vendored code from codex-plugins, which has about 5 components that I'll need to compress and integrate. + +For the vendoring strategy, I'm planning to copy the plugins/omo directory into packages/codex-plugin while preserving the component structure and prebuilt dist directories, then add a standalone package.json for that directory outside the workspace. At runtime, the installer will need to locate this vendored code within the npm package, copy it to the Codex cache directory, run a lean install, rewrite the MCP paths, link binaries, compute hook hashes, and update the config file. + +Now I'm realizing the vendored code needs to be included in the npm publish via the root package.json's files array, so I need to add packages/codex-plugin/ to that list. The installer will then read from the installed package location and copy the contents to the Codex cache at runtime. + +Finalizing the directory structure... + +For PostHog telemetry, I want to keep it consistent with the existing CLI approach—same client creation and the single production call tracking daily active users with deduplication. + +The question is whether to create a separate `omo_codex_daily_active` event or add a `source: "codex"` property to the existing event. The simplest approach is adding a `codex_installed: boolean` property to the current `omo_daily_active` event, which avoids duplicating the tracking logic. + +Since the user wants Codex telemetry set up the same way OmO uses it with a disable toggle, I should track when the Codex plugin installs and potentially when it runs with the plugin active—though the plugin components themselves run inside Codex, so I need to think through where that instrumentation actually lives. + +For this PR, install-time tracking is the right scope: emit an `omo_codex_install` event when `omo install --codex` completes, using the same PostHog API key, distinct_id derivation, and opt-out environment variables as OmO. + +Now I'm breaking this down into waves—Wave 1 handles vendoring the Codex plugin source, adding the bin entry, and writing regression and installer tests in parallel, then Wave 2 adds the `--codex` flag to the CLI after those foundations are in place. + +Continuing with the remaining waves: Wave 2 also covers implementing the Codex installer module and its PostHog telemetry, Wave 3 wires everything into the routing logic and updates the CI/CD pipeline, and Wave 4 runs end-to-end tests to verify all three installation scenarios work correctly. + +Wait, I'm realizing I need to be stricter about test-first ordering—the regression tests should come before any new implementation, and I should write unit tests for the new Codex functionality before touching the actual implementation code. then implement." So for each feature: +1. Write the test that will verify the feature +2. Implement the feature +3. Verify the test passes + +Let me restructure the work into waves. First, I'll vendor the codex-plugin source and add the basic CLI scaffolding—the "omo" bin entry, the codex flag to InstallArgs, and the --codex option to Commander. Then I'll write regression and unit tests for the Codex installer module, cache, config, manifest, and PostHog telemetry. After tests pass, I'll implement the actual Codex installer and telemetry modules in parallel. Once those are done, I'll wire everything together across install.ts, cli-installer.ts, and tui-installer.ts. Finally, I'll update the package.json files list to include the vendored plugin and run the full CI/CD verification. + +For commits, I'm thinking: first commit vendors the plugin source as one large isolated change, second adds the CLI scaffolding, third implements the installer with tests, fourth adds telemetry with tests, fifth wires everything together with integration tests, and sixth handles the CI/CD updates. + +Now I need to think through some practical implementation details. The lsp-tools-mcp submodule appears in both projects, so I'll need to flatten it into regular files in the vendored copy rather than keeping it as a git submodule reference. The installer will need to run npm commands in the cache directory, which means checking that npm is available on the system and providing a helpful error message if it's not. For writing the TOML config file, I could either add a library or use string manipulation like the existing install-local.mjs approach does. The binary symlinks created in ~/.local/bin/ also need some consideration for cross-platform compatibility. + +The cache directory should follow Codex's standard location at ~/.codex/plugins/cache/ to stay compatible with the native plugin system. For the marketplace naming, I'm weighing whether to keep the existing `code-yeongyu-codex-plugins` name for compatibility or use something like `oh-my-opencode-codex` since we're embedding it directly in the npm package. There's a trade-off between maintaining compatibility with existing installations and using a more appropriate name for the embedded version. + +On the TOML handling side, I need to figure out how the installer will mutate the config file. The codex-plugins code likely uses a TOML library for this, and I'm considering using something lightweight like `@iarna/toml` or `smol-toml` as a devDependency since the installer runs at install time rather than build time. + +Actually, wait—the installer gets compiled into the Bun binary via `bun build --compile`, so any dependencies are bundled at build time anyway. `smol-toml` is a good choice here since it's small and handles both parsing and stringifying. + +Now I'm ready to write out the plan. The user also specified three binary-observable scenarios to validate: backward compatibility with the existing install command, a Codex-specific install flow, and presumably a third scenario I should define based on the requirements. + +Let me also double-check what the user's asking for: vendoring the Codex plugin code into `omodex`, adding `omo` as a bin entry, the `--codex` flag for the install command, and PostHog telemetry configured the same way OmO uses it with daily active tracking. + +I need to ensure backward compatibility with existing installer flows. Given the 250 LOC constraint, I'll need to split the Codex installer across multiple focused modules—one for path resolution, another for manifest and marketplace parsing, separate handlers for cache operations and MCP config rewriting, TOML config mutation, and SHA-256 verification logic. + +Now I'm weighing whether to include the vendored codex-plugin code in the npm package's `files` array, which is necessary since the installer reads from it at runtime, but this could bloat the package significantly with dist and source files from rules, comment-checker, LSP components, and other utilities. +All four exploration tasks are complete. I now have comprehensive context on: +- CLI installer architecture (types, routing, TUI/non-TUI flows, config managers) +- PostHog telemetry (factory functions, opt-out, daily dedup, sole call site) +- codex-plugins source (5 components, hooks.json, install-local.mjs step-by-step) +- Workspace packages (conventions, build system, CI/CD, platform binaries) + +Let me now build the plan. + +--- + +# Plan: Port codex-plugins into omodex, build `omo` installer with `--codex` flag + +## Context + +**User Request**: Port the local `codex-plugins` marketplace into `omodex`, add an `omo` CLI alias, a `--codex` install flag, PostHog telemetry matching the existing OmO pattern, and ensure backward compatibility of `bunx oh-my-opencode install` / `bunx oh-my-openagent install`. + +**Codebase State**: omodex is a Bun-only OpenCode plugin with 11 agents, 54-61 hooks, Commander.js CLI, and an existing install wizard writing to `~/.config/opencode/` and `.opencode/`. codex-plugins is a separate npm-based repo with 5 isolated components (rules, comment-checker, lsp, ultrawork, ultragoal) and a Node.js installer writing to `~/.codex/`. + +--- + +## Design Decisions (Justified) + +### Decision 1: Where does the Codex plugin code live? + +**Choice: `packages/codex-plugin/` as a new directory, NOT in the workspace array.** + +Rationale: +- Consistent with ROADMAP layering (packages/ houses modules that will eventually become Core-consuming adapters). +- The components use npm + tsc + vitest internally -- they cannot participate in the Bun workspace yet. +- Keeping them out of the workspace array avoids Bun trying to resolve their npm deps. +- Cleaner than top-level `codex-plugin/` (packages/ is the established home for sub-packages) and cleaner than `src/codex/` (would pollute the Bun-native source tree). + +### Decision 2: How are the 5 components shipped? + +**Choice: (b) Vendor source AND prebuilt dist/.** + +Rationale: +- The existing codex-plugins pattern ships prebuilt dist/. Including dist/ means `omo install --codex` can copy files to the cache without running tsc at install time. +- Exclude `.git/` and `node_modules/` from vendored copy (they add 111MB per component; source + dist is ~200KB per component). +- CI will rebuild dist/ before npm publish to ensure freshness. +- `npm install --omit=dev` is still needed at install time for runtime deps (picomatch, comment-checker binary, lsp-tools-mcp). +- The lsp-tools-mcp submodule gets flattened: copy its source/dist as regular files, not a git submodule reference. + +### Decision 3: How does `omo install --codex` install the Codex plugin? + +**Choice: (a) Port install-local.mjs to TypeScript in `src/cli/install-codex/`.** + +Rationale: +- The existing installer is ~500 LOC of modern ESM across 7 files -- well-suited for a TypeScript port. +- TypeScript integrates naturally with the existing CLI architecture and gets compiled into the platform binary. +- Embedding the Node script (option b) is fragile. Re-implementing from scratch using config-manager (option c) is unnecessary since the config targets are fundamentally different (TOML vs JSONC, different directory structures). +- For TOML writing, use `smol-toml` (3KB, modern, Bun-compatible) -- it gets bundled at compile time. + +### Decision 4: PostHog telemetry + +**Choice: Same PostHog project, new event name `omo_codex_install`, single global opt-out.** + +Rationale: +- Same project keeps analytics unified (same API key: `phc_CFJhj5HyvA62QPhvyaUCtaq23aUfznnijg5VaaGkNk74`). +- Event `omo_codex_install` fires once at `omo install --codex` completion (no daily dedup needed -- install is a one-time event). +- The same distinct_id derivation (SHA256 of `oh-my-opencode:hostname`) maintains user consistency. +- `OMO_SEND_ANONYMOUS_TELEMETRY=0` and `OMO_DISABLE_POSTHOG=1` disable ALL telemetry (both OpenCode and Codex). No per-product opt-out -- unnecessary complexity for the same product family. + +### Decision 5: Bin entry strategy + +**Choice: Add `"omo": "bin/oh-my-opencode.js"` to root `package.json`.** + +Rationale: +- The existing JS shim handles platform detection and binary resolution. It doesn't care what name invoked it. +- All three names (`oh-my-opencode`, `oh-my-openagent`, `omo`) share the same shim and the same compiled binary. +- Zero additional code needed -- just one line in package.json. + +### Decision 6: TUI flow + +**Choice: `--codex` is a purely additive flag. Separate flow, not combined wizard.** + +Rationale: +- `omo install` (no --codex) behaves identically to `bunx oh-my-opencode install` -- backward compat preserved. +- `omo install --codex` runs the normal OpenCode install AND THEN runs the Codex install step. +- The two install targets are fundamentally different: OpenCode writes JSONC to `~/.config/opencode/`, Codex writes TOML to `~/.codex/`. Combining them into one wizard would create confusing UX. +- In non-TUI mode: `omo install --codex --no-tui --claude yes ...` runs both installers sequentially. +- In TUI mode: `omo install --codex` shows the OpenCode wizard, then a separate Codex install spinner. + +--- + +## Task Dependency Graph + +| Task | Depends On | Reason | +|------|------------|--------| +| T1: Vendor codex-plugin source | None | Starting point, copies files from codex-plugins | +| T2: Add `omo` bin entry | None | One-line package.json edit, no deps | +| T3: Add `--codex` CLI types | None | Type additions only, no implementation | +| T4: Add smol-toml dependency | None | `bun add smol-toml` -- needed for TOML writing | +| T5: Write backward-compat regression tests | T3 | Needs types to exist, verifies existing install unaffected | +| T6: Write Codex installer unit tests | T1, T3, T4 | Needs vendored code structure + types + TOML dep | +| T7: Write Codex telemetry tests | T3 | Needs types, tests PostHog integration | +| T8: Implement Codex installer module | T6 | TDD: tests written first, then implementation | +| T9: Implement Codex telemetry | T7 | TDD: tests written first, then implementation | +| T10: Wire --codex into install routing | T8, T9 | Connects installer + telemetry to CLI flow | +| T11: Update package.json files array | T1 | Ensures vendored code ships in npm | +| T12: Update CI for codex-plugin | T8, T11 | CI must build codex dist before packaging | +| T13: End-to-end scenario verification | T10, T12 | Final gate: all 3 scenarios pass | + +## Parallel Execution Graph + +``` +Wave 1 (Start immediately - no dependencies): +├── T1: Vendor codex-plugin source into packages/codex-plugin/ +├── T2: Add "omo" bin entry to package.json +├── T3: Add --codex flag types (InstallArgs, Commander option) +└── T4: Add smol-toml dependency + +Wave 2 (After Wave 1 completes - tests first): +├── T5: Write backward-compat regression tests +├── T6: Write Codex installer unit tests +└── T7: Write Codex telemetry tests + +Wave 3 (After Wave 2 completes - implementation): +├── T8: Implement Codex installer module +└── T9: Implement Codex telemetry + +Wave 4 (After Wave 3 completes - wiring): +├── T10: Wire --codex into install routing +└── T11: Update package.json files array + +Wave 5 (After Wave 4 completes - CI & verification): +├── T12: Update CI for codex-plugin build +└── T13: End-to-end scenario verification + +Critical Path: T1 → T6 → T8 → T10 → T13 +Estimated Parallel Speedup: ~45% faster than sequential +``` + +--- + +## Tasks + +### Task 1: Vendor codex-plugin source into packages/codex-plugin/ + +**Description**: Copy the omo plugin from `../codex-plugins/plugins/omo/` into `packages/codex-plugin/`, stripping `.git/` and `node_modules/` from each component. Flatten the lsp-tools-mcp submodule into regular files. + +**Delegation Recommendation**: +- Category: `quick` - Straightforward file copy with filtering +- Skills: [] - No specialized skills needed, just file operations + +**Skills Evaluation**: +- OMITTED `programming`: No code writing, just file copying +- OMITTED `git-master`: Not a git operation + +**Depends On**: None +**Acceptance Criteria**: +- `packages/codex-plugin/.codex-plugin/plugin.json` exists and is valid JSON +- `packages/codex-plugin/hooks/hooks.json` exists +- `packages/codex-plugin/.mcp.json` exists +- All 5 component directories exist under `packages/codex-plugin/components/` +- Each TS component has both `src/` and `dist/` directories +- `packages/codex-plugin/components/ultrawork/hooks/ultrawork-detector.py` exists +- `packages/codex-plugin/components/lsp/packages/lsp-tools-mcp/dist/cli.js` exists (flattened, not submodule) +- No `.git/` or `node_modules/` directories anywhere in the vendored tree +- `packages/codex-plugin/` is NOT in root `package.json` workspaces array + +**Files to CREATE**: +- `packages/codex-plugin/` (entire directory tree -- copied from `../codex-plugins/plugins/omo/`) +- `packages/codex-plugin/marketplace.json` (copied from `../codex-plugins/.agents/plugins/marketplace.json`, path references updated) + +**Atomic steps**: +1. Create `packages/codex-plugin/` directory +2. Copy `../codex-plugins/plugins/omo/.codex-plugin/`, `hooks/`, `.mcp.json`, `skills/`, `README.md` +3. For each TS component (rules, comment-checker, lsp, ultragoal): copy `src/`, `dist/`, `package.json`, `tsconfig.build.json`, `tsconfig.json`, `README.md` -- skip `.git/`, `node_modules/`, `coverage/` +4. For ultrawork: copy entire directory minus `.git/`, `node_modules/` +5. For lsp: additionally copy `packages/lsp-tools-mcp/` from the component's submodule (initialized copy at `../codex-plugins/plugins/omo/components/lsp/packages/lsp-tools-mcp/`), minus `.git/` +6. Copy marketplace.json, update the `source` path reference to point at `packages/codex-plugin/` relative to repo root +7. Verify no `.git` directories remain: `find packages/codex-plugin -name .git -type d` + +**VERIFY**: `ls packages/codex-plugin/components/` shows 5 directories; `find packages/codex-plugin -name .git -type d` returns empty + +--- + +### Task 2: Add `omo` bin entry to package.json + +**Description**: Add `"omo": "bin/oh-my-opencode.js"` to the `bin` field in root `package.json`. + +**Delegation Recommendation**: +- Category: `quick` - Single-line JSON edit +- Skills: [] - Trivial edit + +**Skills Evaluation**: +- OMITTED all: Single-line edit needs no specialized knowledge + +**Depends On**: None +**Acceptance Criteria**: +- `package.json` has three bin entries: `oh-my-opencode`, `oh-my-openagent`, `omo` -- all pointing to `bin/oh-my-opencode.js` +- `bun run build` still succeeds + +**Files to EDIT**: +- `package.json` (add one line to `bin` object) + +**VERIFY**: `cat package.json | grep -A4 '"bin"'` shows three entries + +--- + +### Task 3: Add `--codex` CLI flag types + +**Description**: Add the `codex?: boolean` field to `InstallArgs` in types.ts and register the `--codex` option in Commander in cli-program.ts. + +**Delegation Recommendation**: +- Category: `quick` - Two small edits +- Skills: [`programming`] - TypeScript type modifications + +**Skills Evaluation**: +- INCLUDED `programming`: TypeScript strict types, ensures correct typing +- OMITTED others: Not relevant to type edits + +**Depends On**: None +**Acceptance Criteria**: +- `InstallArgs.codex` is typed as `boolean | undefined` +- `cli-program.ts` registers `--codex` with description "Also install the Codex plugin" +- `bun run typecheck` passes +- Existing install flow behavior unchanged (codex is undefined by default) + +**Files to EDIT**: +- `src/cli/types.ts` (add `codex?: boolean` to `InstallArgs`) +- `src/cli/cli-program.ts` (add `.option("--codex", "Also install the Codex plugin")` to install command, pass `opts.codex` into args) + +**VERIFY**: `bun run typecheck` passes + +--- + +### Task 4: Add smol-toml dependency + +**Description**: Add `smol-toml` as a runtime dependency for TOML parsing/writing needed by the Codex config installer. + +**Delegation Recommendation**: +- Category: `quick` - Single command +- Skills: [] - Package management + +**Depends On**: None +**Acceptance Criteria**: +- `smol-toml` appears in `package.json` dependencies +- `bun install` succeeds +- `import { parse, stringify } from "smol-toml"` resolves + +**Files to EDIT**: +- `package.json` (dependency added by `bun add smol-toml`) +- `bun.lock` (auto-updated) + +**VERIFY**: `bun add smol-toml && bun run typecheck` + +--- + +### Task 5: Write backward-compat regression tests + +**Description**: Write tests proving that the existing install flow is unaffected by the --codex addition. When `codex` is undefined/false, no Codex-related code runs. + +**Delegation Recommendation**: +- Category: `deep` - Needs understanding of full install flow to write meaningful regression tests +- Skills: [`programming`] - TypeScript test writing with Bun test + +**Skills Evaluation**: +- INCLUDED `programming`: TDD discipline, Bun test patterns, given/when/then style +- OMITTED others: Not relevant + +**Depends On**: T3 (types must exist) +**Acceptance Criteria**: +- Tests verify: `install({tui: false, claude: "yes", gemini: "no", copilot: "no"})` does NOT attempt Codex operations +- Tests verify: `install({tui: false, claude: "yes", gemini: "no", copilot: "no", codex: false})` does NOT attempt Codex operations +- Tests mock the config-manager functions and assert they are called with the same arguments as before +- All tests pass with `bun test src/cli/install-codex-compat.test.ts` + +**Files to CREATE**: +- `src/cli/install-codex-compat.test.ts` + +**VERIFY**: `bun test src/cli/install-codex-compat.test.ts` + +--- + +### Task 6: Write Codex installer unit tests (TDD) + +**Description**: Write the full unit test suite for the Codex installer module BEFORE implementation. Tests should cover: path resolution, manifest parsing, cache copy, MCP path rewriting, hook trust hashing, TOML config writing, binary linking, and error cases. + +**Delegation Recommendation**: +- Category: `deep` - Complex test suite requiring understanding of codex-plugins installer internals +- Skills: [`programming`] - TypeScript TDD, Bun test, mock patterns + +**Skills Evaluation**: +- INCLUDED `programming`: TDD-first, strict types, 250 LOC ceiling per file, given/when/then +- OMITTED `debugging`: Not debugging, writing new tests + +**Depends On**: T1 (vendored code to reference), T3 (types), T4 (smol-toml) +**Acceptance Criteria**: +- Test file(s) exist and are syntactically valid +- Tests import from `./install-codex/` (will fail until T8 implements) +- Tests cover at minimum: + - `resolveCodexPaths()`: defaults, env overrides, custom args + - `parseMarketplaceManifest()`: valid parse, missing fields, corrupt JSON + - `copyToCache()`: creates target dir, excludes .git/node_modules, atomic replacement + - `rewriteMcpPaths()`: relative to absolute path conversion + - `computeHookTrustHashes()`: SHA-256 matches expected output for known hooks.json + - `writeCodexConfig()`: creates new config.toml, updates existing, enables features/marketplace/plugin/hooks + - `installCodexPlugin()`: end-to-end orchestration (mocked I/O) + - Error cases: missing npm, missing codex home, corrupt manifests + +**Files to CREATE**: +- `src/cli/install-codex/codex-paths.test.ts` +- `src/cli/install-codex/codex-manifest.test.ts` +- `src/cli/install-codex/codex-cache.test.ts` +- `src/cli/install-codex/codex-config-writer.test.ts` +- `src/cli/install-codex/codex-hook-trust.test.ts` +- `src/cli/install-codex/index.test.ts` + +**VERIFY**: `bun test src/cli/install-codex/ --bail` (expected: tests exist but fail since module not yet implemented) + +--- + +### Task 7: Write Codex telemetry tests (TDD) + +**Description**: Write tests for the Codex install telemetry BEFORE implementation. Tests should verify event emission, opt-out behavior, and property shape. + +**Delegation Recommendation**: +- Category: `quick` - Small focused test file +- Skills: [`programming`] - TypeScript TDD + +**Skills Evaluation**: +- INCLUDED `programming`: Test patterns, mock PostHog +- OMITTED others: Not relevant + +**Depends On**: T3 (types) +**Acceptance Criteria**: +- Tests verify `trackCodexInstall()` emits `omo_codex_install` event with correct properties +- Tests verify opt-out via `OMO_DISABLE_POSTHOG=1` suppresses the event +- Tests verify opt-out via `OMO_SEND_ANONYMOUS_TELEMETRY=0` suppresses the event +- Tests verify distinct_id matches existing derivation pattern + +**Files to CREATE**: +- `src/shared/codex-telemetry.test.ts` + +**VERIFY**: `bun test src/shared/codex-telemetry.test.ts --bail` (expected: fails since module not implemented) + +--- + +### Task 8: Implement Codex installer module + +**Description**: Port the install-local.mjs logic into TypeScript at `src/cli/install-codex/`. Each file must be under 250 LOC. Use `smol-toml` for TOML operations. + +**Delegation Recommendation**: +- Category: `deep` - Complex multi-file TypeScript implementation porting from JavaScript +- Skills: [`programming`] - Strict TypeScript, 250 LOC ceiling, ESM, no any + +**Skills Evaluation**: +- INCLUDED `programming`: TypeScript strict mode, no `as any`, 250 LOC ceiling, parse-don't-validate +- OMITTED `refactor`: Not refactoring existing code, writing new code + +**Depends On**: T6 (tests must exist first -- TDD) +**Acceptance Criteria**: +- All unit tests from T6 pass +- Each file under 250 pure LOC +- No `as any`, `@ts-ignore`, or `@ts-expect-error` +- `bun run typecheck` passes +- Module exports `installCodexPlugin(options: CodexInstallOptions): Promise` + +**Files to CREATE**: +- `src/cli/install-codex/index.ts` (barrel + orchestrator, <200 LOC) +- `src/cli/install-codex/codex-paths.ts` (path resolution, <80 LOC) +- `src/cli/install-codex/codex-manifest.ts` (marketplace + plugin manifest parsing, <100 LOC) +- `src/cli/install-codex/codex-cache.ts` (build, copy, prune, link operations, <200 LOC) +- `src/cli/install-codex/codex-mcp-rewriter.ts` (rewrite .mcp.json paths, <80 LOC) +- `src/cli/install-codex/codex-config-writer.ts` (TOML config mutation, <200 LOC) +- `src/cli/install-codex/codex-hook-trust.ts` (SHA-256 fingerprinting, <100 LOC) +- `src/cli/install-codex/types.ts` (Codex-specific types, <80 LOC) + +**Key implementation notes**: +- `codex-paths.ts`: Reads `CODEX_HOME` env (default `~/.codex`), `CODEX_LOCAL_BIN_DIR` env (default `~/.local/bin`). Resolves vendored plugin path relative to the installed package root using `import.meta.dir` or `import.meta.resolve`. +- `codex-cache.ts`: Uses `Bun.spawn` to run `npm install --omit=dev` in the cache directory. Uses `fs.cp` with `{ recursive: true, filter }` for atomic copy. Filter excludes `.git` and `node_modules`. +- `codex-config-writer.ts`: Uses `smol-toml` `parse()` and `stringify()`. Reads existing `~/.codex/config.toml`, merges sections, writes back. Creates file if absent. +- `codex-hook-trust.ts`: Computes SHA-256 of canonical JSON for each command hook. Same algorithm as `scripts/install/hook-trust.mjs`. +- `codex-mcp-rewriter.ts`: Reads `.mcp.json`, rewrites relative `args` paths to absolute pointing into cache dir. + +**VERIFY**: `bun test src/cli/install-codex/` -- all tests pass + +--- + +### Task 9: Implement Codex telemetry + +**Description**: Create `src/shared/codex-telemetry.ts` exporting `trackCodexInstall()`. Same PostHog project, same distinct_id, new event name `omo_codex_install`, same opt-out vars. + +**Delegation Recommendation**: +- Category: `quick` - Small focused module mirroring existing posthog.ts patterns +- Skills: [`programming`] - TypeScript, mirroring existing pattern + +**Skills Evaluation**: +- INCLUDED `programming`: TypeScript strict types +- OMITTED others: Not relevant + +**Depends On**: T7 (tests must exist first -- TDD) +**Acceptance Criteria**: +- All tests from T7 pass +- `trackCodexInstall()` uses `createCliPostHog()` from existing posthog.ts +- Event name is `omo_codex_install` +- Properties include `codex_plugin_version`, `marketplace_name`, and all standard shared properties +- Respects `OMO_DISABLE_POSTHOG` and `OMO_SEND_ANONYMOUS_TELEMETRY` opt-outs +- Under 100 LOC + +**Files to CREATE**: +- `src/shared/codex-telemetry.ts` (<100 LOC) + +**VERIFY**: `bun test src/shared/codex-telemetry.test.ts` -- all tests pass + +--- + +### Task 10: Wire --codex into install routing + +**Description**: Modify the install entry point, CLI installer, and TUI installer to call the Codex installer when `--codex` is passed. + +**Delegation Recommendation**: +- Category: `deep` - Needs careful integration with existing install flow, must not break backward compat +- Skills: [`programming`] - TypeScript, CLI integration + +**Skills Evaluation**: +- INCLUDED `programming`: TypeScript strict types, careful integration +- OMITTED others: Not relevant + +**Depends On**: T8 (Codex installer), T9 (Codex telemetry) +**Acceptance Criteria**: +- `omo install --codex --no-tui --claude yes --gemini no --copilot no` runs OpenCode install THEN Codex install +- `omo install --no-tui --claude yes --gemini no --copilot no` (no --codex) runs ONLY OpenCode install +- `omo install --codex` in TUI mode shows OpenCode wizard THEN Codex install step +- Codex install failure does not prevent OpenCode install from completing (fail independently) +- Backward-compat tests from T5 still pass +- Telemetry fires on successful Codex install + +**Files to EDIT**: +- `src/cli/install.ts` (add Codex routing after OpenCode install) +- `src/cli/cli-installer.ts` (call installCodexPlugin + trackCodexInstall when args.codex) +- `src/cli/tui-installer.ts` (add Codex install spinner when args.codex) + +**VERIFY**: `bun test src/cli/` -- all tests pass including T5 regression tests + +--- + +### Task 11: Update package.json files array + +**Description**: Add `packages/codex-plugin/` to the root `package.json` `files` array so the vendored Codex plugin code ships in the npm package. + +**Delegation Recommendation**: +- Category: `quick` - Single JSON edit +- Skills: [] - Trivial + +**Depends On**: T1 (vendored code must exist) +**Acceptance Criteria**: +- `package.json` `files` array includes `"packages/codex-plugin/"` +- `npm pack --dry-run` shows codex-plugin files included + +**Files to EDIT**: +- `package.json` (add to `files` array) + +**VERIFY**: `npm pack --dry-run 2>&1 | grep codex-plugin` shows entries + +--- + +### Task 12: Update CI for codex-plugin build + +**Description**: Update CI and publish workflows to build codex-plugin components before packaging. + +**Delegation Recommendation**: +- Category: `quick` - Small YAML edits to existing workflow files +- Skills: [] - Workflow YAML edits + +**Skills Evaluation**: +- OMITTED all: Standard CI YAML modifications + +**Depends On**: T8 (installer must exist), T11 (files array must include codex-plugin) +**Acceptance Criteria**: +- `ci.yml` build job runs `npm run build` in each TS component under `packages/codex-plugin/components/` before `bun run build` +- `publish.yml` publish-main job ensures codex-plugin dist/ is fresh before `npm publish` +- CI still passes on dev branch + +**Files to EDIT**: +- `.github/workflows/ci.yml` (add codex-plugin build step) +- `.github/workflows/publish.yml` (add codex-plugin build step before publish) + +**VERIFY**: CI workflow syntax is valid (`actionlint` if available, or manual review) + +--- + +### Task 13: End-to-end scenario verification + +**Description**: Verify all 3 binary-observable scenarios pass. + +**Delegation Recommendation**: +- Category: `deep` - Requires running real commands and verifying system state +- Skills: [`programming`, `debugging`] - May need debugging if scenarios fail + +**Skills Evaluation**: +- INCLUDED `programming`: Test verification +- INCLUDED `debugging`: If scenarios fail, needs root-cause analysis +- OMITTED others: Not relevant + +**Depends On**: T10 (wiring), T12 (CI) +**Acceptance Criteria**: All 3 scenarios below pass. + +--- + +## Scenario Contracts + +### Scenario 1: Backward Compatibility + +**Command**: `bunx oh-my-opencode install --no-tui --claude yes --gemini no --copilot no --skip-auth` + +**Observable Evidence**: +- Exit code 0 +- `~/.config/opencode/opencode.json(c)` contains `oh-my-openagent@` in plugins array +- `.opencode/oh-my-openagent.jsonc` is created/updated with Claude model config +- NO files written to `~/.codex/` +- NO `omo_codex_install` PostHog event emitted +- Console output does NOT mention "Codex" + +### Scenario 2: Codex Install via `omo` + +**Command**: `omo install --codex --no-tui --claude yes --gemini no --copilot no --skip-auth` + +**Observable Evidence**: +- Exit code 0 +- OpenCode configs written (same as Scenario 1) +- `~/.codex/plugins/cache/code-yeongyu-codex-plugins/omo/0.1.0/` exists with all 5 components +- `~/.codex/plugins/cache/.../components/rules/node_modules/picomatch/` exists (npm install ran) +- `~/.codex/config.toml` contains: + ```toml + [features] + plugins = true + plugin_hooks = true + + [plugins."omo@code-yeongyu-codex-plugins"] + enabled = true + + [hooks.state."omo@code-yeongyu-codex-plugins:hooks/hooks.json:post_tool_use:0:0"] + trusted_hash = "sha256:..." + ``` +- `~/.local/bin/codex-rules` symlink exists (or equivalent binaries) +- Console output includes "Codex plugin installed successfully" + +### Scenario 3: Telemetry Opt-Out + +**Command**: `OMO_DISABLE_POSTHOG=1 omo install --codex --no-tui --claude yes --gemini no --copilot no --skip-auth` + +**Observable Evidence**: +- Exit code 0 +- Both OpenCode and Codex configs written normally +- PostHog client returns no-op (verified via test mock -- in production, no HTTP request to `us.i.posthog.com`) +- Console output still shows telemetry notice with opt-out instructions + +--- + +## Files Summary + +### Files to CREATE + +| Path | Purpose | LOC Est. | +|------|---------|----------| +| `packages/codex-plugin/` | Vendored codex plugin tree | ~12K (copied) | +| `packages/codex-plugin/marketplace.json` | Marketplace manifest (updated paths) | ~15 | +| `src/cli/install-codex/index.ts` | Codex installer orchestrator + barrel | ~180 | +| `src/cli/install-codex/types.ts` | CodexInstallOptions, CodexInstallResult | ~60 | +| `src/cli/install-codex/codex-paths.ts` | Path resolution | ~70 | +| `src/cli/install-codex/codex-manifest.ts` | Manifest parsing | ~90 | +| `src/cli/install-codex/codex-cache.ts` | Cache copy, prune, link | ~190 | +| `src/cli/install-codex/codex-mcp-rewriter.ts` | .mcp.json path rewriting | ~70 | +| `src/cli/install-codex/codex-config-writer.ts` | TOML config mutation | ~180 | +| `src/cli/install-codex/codex-hook-trust.ts` | SHA-256 hook fingerprinting | ~90 | +| `src/cli/install-codex/codex-paths.test.ts` | Tests | ~80 | +| `src/cli/install-codex/codex-manifest.test.ts` | Tests | ~100 | +| `src/cli/install-codex/codex-cache.test.ts` | Tests | ~150 | +| `src/cli/install-codex/codex-config-writer.test.ts` | Tests | ~150 | +| `src/cli/install-codex/codex-hook-trust.test.ts` | Tests | ~80 | +| `src/cli/install-codex/index.test.ts` | Integration tests | ~120 | +| `src/cli/install-codex-compat.test.ts` | Backward-compat regression | ~100 | +| `src/shared/codex-telemetry.ts` | Codex install event tracking | ~80 | +| `src/shared/codex-telemetry.test.ts` | Tests | ~100 | + +### Files to EDIT + +| Path | Change | +|------|--------| +| `package.json` | Add `"omo"` bin entry, add `smol-toml` dep, add `packages/codex-plugin/` to files | +| `src/cli/types.ts` | Add `codex?: boolean` to InstallArgs | +| `src/cli/cli-program.ts` | Add `--codex` Commander option | +| `src/cli/install.ts` | Add Codex routing after OpenCode install | +| `src/cli/cli-installer.ts` | Call installCodexPlugin when args.codex | +| `src/cli/tui-installer.ts` | Add Codex install spinner when args.codex | +| `.github/workflows/ci.yml` | Add codex-plugin build step | +| `.github/workflows/publish.yml` | Add codex-plugin build step | + +--- + +## Commit Strategy (Atomic) + +| # | Commit Message | Scope | Tasks | +|---|---------------|-------|-------| +| 1 | `feat: vendor codex-plugin source into packages/codex-plugin` | Vendoring only, no code changes | T1 | +| 2 | `feat: add omo bin entry and --codex CLI flag` | Types + package.json, no implementation | T2, T3, T4 | +| 3 | `test: add backward-compat regression tests for install flow` | Tests only | T5 | +| 4 | `test: add Codex installer and telemetry unit tests (red)` | Tests only (expected to fail) | T6, T7 | +| 5 | `feat: implement Codex installer module (src/cli/install-codex)` | Implementation, tests go green | T8 | +| 6 | `feat: implement Codex install telemetry` | Implementation, tests go green | T9 | +| 7 | `feat: wire --codex flag into install routing` | Integration wiring | T10, T11 | +| 8 | `ci: add codex-plugin build steps to CI and publish workflows` | CI/CD only | T12 | + +--- + +## Risks & Blockers + +| Risk | Impact | Mitigation | +|------|--------|------------| +| `npm` not on PATH at install time | Codex install fails (can't install runtime deps) | Check for npm binary early, emit clear error: "npm is required for --codex. Install it from https://nodejs.org/" | +| lsp-tools-mcp submodule not initialized in codex-plugins | Vendoring misses lsp MCP dist | Build/init the submodule before vendoring: `cd ../codex-plugins/plugins/omo/components/lsp && npm run bootstrap` | +| smol-toml bundling with Bun | TOML library may not bundle cleanly | Test: `bun build src/cli/index.ts --target bun` with smol-toml imported. smol-toml is pure JS, should bundle fine. Fallback: use `@iarna/toml`. | +| Vendored dist/ staleness | Prebuilt dist may diverge from source | CI commit 8 ensures dist/ is rebuilt before packaging. Add a git hook or CI check: `npm run build && git diff --exit-code packages/codex-plugin/*/dist/` | +| Package size increase | ~1MB extra in npm tarball from vendored code | Acceptable. Current package is already ~5MB with platform binary stubs. 1MB is a 20% increase. | +| Codex config.toml format changes | Future Codex releases may change config format | Pin to known Codex config format. Log a version warning if `~/.codex/config.toml` has unknown sections. | +| Windows: symlink creation in ~/.local/bin | Windows doesn't support Unix symlinks by default | Skip binary linking on Windows. Codex CLI doesn't run on Windows currently. Add platform guard in codex-cache.ts. | + +--- + +## Success Criteria + +1. `bun test` passes (all existing + new tests) +2. `bun run typecheck` passes +3. `bun run build` succeeds +4. All 3 scenarios produce their expected observable evidence +5. `npm pack --dry-run` includes `packages/codex-plugin/` files +6. No file exceeds 250 pure LOC +7. PR passes CI on dev branch + +--- + +## TODO List (ADD THESE) + +> CALLER: Add these TODOs using TodoWrite and execute by wave. + +### Wave 1 (Start Immediately - No Dependencies) + +- [ ] **T1. Vendor codex-plugin source** + - What: Copy `../codex-plugins/plugins/omo/` into `packages/codex-plugin/`, strip `.git/` and `node_modules/`, flatten lsp-tools-mcp submodule, create marketplace.json with updated paths + - Depends: None + - Blocks: T6, T11 + - Category: `quick` + - Skills: [] + - QA: `ls packages/codex-plugin/components/` shows 5 dirs; `find packages/codex-plugin -name .git -type d` returns empty + +- [ ] **T2. Add `omo` bin entry** + - What: Add `"omo": "bin/oh-my-opencode.js"` to `package.json` bin field + - Depends: None + - Blocks: T13 + - Category: `quick` + - Skills: [] + - QA: `grep omo package.json` shows the bin entry + +- [ ] **T3. Add `--codex` CLI flag types** + - What: Add `codex?: boolean` to `InstallArgs` in `src/cli/types.ts`; add `.option("--codex", "Also install the Codex plugin")` to install command in `src/cli/cli-program.ts`; pass `opts.codex` into the InstallArgs object + - Depends: None + - Blocks: T5, T6, T7, T10 + - Category: `quick` + - Skills: [`programming`] + - QA: `bun run typecheck` passes + +- [ ] **T4. Add smol-toml dependency** + - What: `bun add smol-toml` + - Depends: None + - Blocks: T6, T8 + - Category: `quick` + - Skills: [] + - QA: `grep smol-toml package.json` shows entry + +### Wave 2 (After Wave 1 Completes - Tests First) + +- [ ] **T5. Write backward-compat regression tests** + - What: Create `src/cli/install-codex-compat.test.ts` testing that install without --codex does NOT run any Codex operations. Mock config-manager functions, assert they are called unchanged. Test both `codex: undefined` and `codex: false`. + - Depends: T3 + - Blocks: T10 + - Category: `deep` + - Skills: [`programming`] + - QA: `bun test src/cli/install-codex-compat.test.ts` -- all tests pass + +- [ ] **T6. Write Codex installer unit tests (TDD - red phase)** + - What: Create 6 test files under `src/cli/install-codex/*.test.ts` covering all installer functions: paths, manifest, cache, config-writer, hook-trust, index orchestration. Tests should be complete and correct but will fail until T8 implements the module. + - Depends: T1, T3, T4 + - Blocks: T8 + - Category: `deep` + - Skills: [`programming`] + - QA: Test files exist and parse cleanly (`bun test src/cli/install-codex/ --bail 2>&1 | head -20` shows test discovery) + +- [ ] **T7. Write Codex telemetry tests (TDD - red phase)** + - What: Create `src/shared/codex-telemetry.test.ts` testing `trackCodexInstall()`: event emission, opt-out via both env vars, correct properties shape, distinct_id consistency. + - Depends: T3 + - Blocks: T9 + - Category: `quick` + - Skills: [`programming`] + - QA: Test file exists and parses cleanly + +### Wave 3 (After Wave 2 Completes - Implementation) + +- [ ] **T8. Implement Codex installer module** + - What: Create 8 TypeScript files under `src/cli/install-codex/` porting the install-local.mjs logic. Each file under 250 LOC. Use smol-toml for TOML. Use Bun.spawn for npm. Use fs.cp with filter for cache copy. All T6 tests must go green. + - Depends: T6 + - Blocks: T10 + - Category: `deep` + - Skills: [`programming`] + - QA: `bun test src/cli/install-codex/` -- all tests pass; `bun run typecheck` passes + +- [ ] **T9. Implement Codex telemetry** + - What: Create `src/shared/codex-telemetry.ts` (<100 LOC) exporting `trackCodexInstall()`. Reuse `createCliPostHog()` and `getPostHogDistinctId()` from posthog.ts. Event: `omo_codex_install`. All T7 tests must go green. + - Depends: T7 + - Blocks: T10 + - Category: `quick` + - Skills: [`programming`] + - QA: `bun test src/shared/codex-telemetry.test.ts` -- all tests pass + +### Wave 4 (After Wave 3 Completes - Wiring) + +- [ ] **T10. Wire --codex into install routing** + - What: Edit `src/cli/install.ts`, `src/cli/cli-installer.ts`, `src/cli/tui-installer.ts` to call `installCodexPlugin()` + `trackCodexInstall()` when `args.codex === true`, AFTER the OpenCode install step. Codex failure should not prevent OpenCode install from completing. + - Depends: T8, T9 + - Blocks: T13 + - Category: `deep` + - Skills: [`programming`] + - QA: `bun test src/cli/` -- all tests pass including T5 regression + +- [ ] **T11. Update package.json files array** + - What: Add `"packages/codex-plugin/"` to the `files` array in root `package.json` + - Depends: T1 + - Blocks: T12 + - Category: `quick` + - Skills: [] + - QA: `npm pack --dry-run 2>&1 | grep codex-plugin` shows entries + +### Wave 5 (After Wave 4 Completes - CI & Verification) + +- [ ] **T12. Update CI for codex-plugin build** + - What: Add build steps in `.github/workflows/ci.yml` and `.github/workflows/publish.yml` to run `npm install && npm run build` in each TS component under `packages/codex-plugin/components/` before the main bun build step + - Depends: T8, T11 + - Blocks: T13 + - Category: `quick` + - Skills: [] + - QA: Workflow YAML is syntactically valid + +- [ ] **T13. End-to-end scenario verification** + - What: Run all 3 scenarios from the Scenario Contracts section above. Verify each observable evidence point. Document results. + - Depends: T10, T12 + - Blocks: None (final gate) + - Category: `deep` + - Skills: [`programming`, `debugging`] + - QA: All 3 scenarios pass; `bun test` passes; `bun run typecheck` passes; `bun run build` succeeds + +## Execution Instructions + +1. **Wave 1**: Fire T1, T2, T3, T4 IN PARALLEL (no dependencies) + ``` + task(category="quick", load_skills=[], prompt="T1: Vendor codex-plugin source...") + task(category="quick", load_skills=[], prompt="T2: Add omo bin entry...") + task(category="quick", load_skills=["programming"], prompt="T3: Add --codex CLI flag types...") + task(category="quick", load_skills=[], prompt="T4: Add smol-toml dependency...") + ``` + +2. **Wave 2**: After Wave 1 completes, fire T5, T6, T7 IN PARALLEL + ``` + task(category="deep", load_skills=["programming"], prompt="T5: Write backward-compat regression tests...") + task(category="deep", load_skills=["programming"], prompt="T6: Write Codex installer unit tests...") + task(category="quick", load_skills=["programming"], prompt="T7: Write Codex telemetry tests...") + ``` + +3. **Wave 3**: After Wave 2 completes, fire T8, T9 IN PARALLEL + ``` + task(category="deep", load_skills=["programming"], prompt="T8: Implement Codex installer module...") + task(category="quick", load_skills=["programming"], prompt="T9: Implement Codex telemetry...") + ``` + +4. **Wave 4**: After Wave 3 completes, fire T10, T11 IN PARALLEL + ``` + task(category="deep", load_skills=["programming"], prompt="T10: Wire --codex into install routing...") + task(category="quick", load_skills=[], prompt="T11: Update package.json files array...") + ``` + +5. **Wave 5**: After Wave 4 completes, fire T12, T13 sequentially + ``` + task(category="quick", load_skills=[], prompt="T12: Update CI for codex-plugin build...") + task(category="deep", load_skills=["programming", "debugging"], prompt="T13: End-to-end scenario verification...") + ``` + +6. **Final**: After all waves complete, create atomic commits per commit strategy, then create PR via `gh pr create --base dev --merge` + + +session_id: ses_1a1fe170cffeI3udQDQcxLg3fS +task_id: ses_1a1fe170cffeI3udQDQcxLg3fS +subagent: plan + + +to continue: task(task_id="ses_1a1fe170cffeI3udQDQcxLg3fS", load_skills=[], run_in_background=false, prompt="...") +``` + +--- + +## User + +계획 세우고 그 작업 자체는 ultrabrain / deep 역할별로 할당해서 진행해주셈 + +--- + +## User + + +[ALL BACKGROUND TASKS COMPLETE] + +**Completed:** +- `bg_984b7a80`: Map CLI installer + bin structure +- `bg_d544d440`: Find PostHog/telemetry in omodex +- `bg_0baa8bd3`: Research Codex plugin/extension API +- `bg_f89ae6de`: Map packages/ layering + how adapters are wired +- `bg_424806df`: Look at sibling oh-my-codex repo for prior art +- `bg_9524ffd0`: Map codex-plugins repo +- `bg_f8d4250d`: Find install docs + uninstall + privacy policy +- `bg_58841818`: Find build script / publish workflow / platform binary system +- `bg_487b60c3`: Find config schema + plugin entry + how it loads +- `bg_4c8f991c`: Find agent definitions + categories + skills used by Sisyphus + +Use `background_output(task_id="")` to retrieve each result. + + + +--- + +## Assistant (Sisyphus - Ultraworker · Opus 4.7 · 42.0s) + +_Thinking:_ + + All the background tasks are done, so I'm pulling the final result on agent definitions and then building out a comprehensive plan to hand off to the specialists. The user was clear about wanting me to create the plan and then assign the actual execution to ultrabrain and deep based on their roles. + +I need to grab that last background result, synthesize everything into a coherent strategy, set up a git worktree for the PR workflow, and then dispatch the implementation work to ultrabrain for architectural decisions and deep for autonomous research and implementation in parallel. I need to break down the actual work into what ultrabrain should decide versus what deep agents should execute. Ultrabrain handles the architectural choices—whether to vendor the full codex-plugins or just the source files, how to structure the telemetry module with toggles, and how the bin routing works across existing platforms. Deep agents then handle the concrete implementation: setting up the worktree, moving files, updating CLI logic, wiring up the installer, and adding tests. Given the scale of this (5 components with separate dependencies), I'm leaning toward vendoring just the source files rather than the entire package to keep the diff manageable, which is a key decision for ultrabrain to formalize. + +마지막 배경 결과 회수 + worktree 셋업 + 계획 + 디스패치를 병렬로 시작. + +**Tool: background_output** + +**Input:** +```json +{ + "task_id": "bg_4c8f991c" +} +``` + +**Output:** +``` +Task Result + +Task ID: bg_4c8f991c +Description: Find agent definitions + categories + skills used by Sisyphus +Duration: 3m 26s +Session ID: ses_1a2041ee8ffeCnbmy21p4Xqy5y + +--- + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants a comprehensive catalog of all agent definitions under `src/agents/`. This is a large codebase search task. I need to: + +1. List every file under `src/agents/` (3 levels deep) +2. For each agent: model defaults, prompt source, permissions, tools whitelist +3. Identify the agent factory pattern +4. Identify registration mechanism +5. Identify delegate-task constants +6. Identify how OpenCode-specific lifecycle hooks interact with agents + +Let me start by exploring the directory structure and then dive into specific files. I'll use parallel tool calls to speed this up. + +First, let me get the directory listing and search for key patterns simultaneously. + +The user wants me to create an anchored summary from the conversation history. Looking at the conversation, the user made a single complex request to catalog all agent definitions under `src/agents/` in the omodex codebase. I initiated multiple tool calls (all identical parallel calls due to the system trying to get comprehensive coverage) but haven't actually received the detailed file contents back yet - the tool results show directory listings and grep results but were truncated. + +Wait, looking more carefully at the conversation history, I see that there were many repeated identical tool calls (read, grep, grep, grep) that all returned similar truncated results. The actual work hasn't been completed yet - I was in the process of gathering information when the context window apparently got full or the system triggered a compaction. + +Let me analyze what actually happened: +1. User requested a comprehensive catalog of agents under `src/agents/` +2. I initiated many parallel tool calls to explore the directory structure and search for patterns +3. The tool calls returned directory listings and grep matches, but many were truncated +4. No actual deep file reading was completed +5. The conversation is now being compacted/summarized before continuing + +So the summary should reflect: +- Goal: Catalog all 11 agent definitions under `src/agents/` for Codex adapter planning +- Constraints: Need absolute paths, concrete excerpts, specific details about model defaults, prompt sources, permissions, tools whitelist, factory patterns, registration mechanisms, delegate-task constants, and OpenCode lifecycle hooks +- Progress: Started exploration with directory listing and grep searches; no deep file analysis completed yet +- Next steps: Need to read actual agent source files (sisyphus.ts, oracle.ts, librarian.ts, explore.ts, multimodal-looker.ts, metis.ts, momus.ts, atlas/agent.ts, hephaestus/gpt-5-3-codex.ts, sisyphus-junior/, prometheus/) and supporting files +- Active context: `src/agents/` directory contains 47 entries including 11 agent directories/files + +Let me structure this properly according to both templates requested. The user provided a standard template AND a system directive with additional required sections. I need to merge these or follow the system directive since it's labeled as a "SYSTEM DIRECTIVE". Actually, looking carefully, the user said "Create a new anchored summary from the conversation history above" and provided the template, then there's a system directive at the end. The system directive says "When summarizing this session, you MUST include the following sections". So I should use the structure from the system directive primarily, but the user also said "Output exactly the Markdown structure shown inside