SLOPSHOPPER

codex

Lets Claude hand tasks to Codex (gpt-6.1-sol)

newguardtoolprocess
v0.1.0no licenseupdated 2026-10-16arjunkambj/claude-mods/codex
A shopper browsing a rack in a slop shop
README

Arjun's Claude Code mods

Four small mods for Claude Code. Install the ones you want.

ModWhat it does
codexClaude can hand a task to Codex (OpenAI's gpt-6.1-sol), like a code review or a bug hunt. It runs in the background so the chat isn't blocked.
imagegenClaude can make and edit images through Codex, and shows the finished images right in the chat.
devserver-limitStops Claude from starting a dev server when 2 are already running. Good for laptops with little memory.
done-soundPlays a chime when a task that took over a minute finishes.

Install

In a Claude Code terminal session, type one line per mod:

/plugin install codex --marketplace arjunkambj/claude-mods
/plugin install imagegen --marketplace arjunkambj/claude-mods
/plugin install devserver-limit --marketplace arjunkambj/claude-mods
/plugin install done-sound --marketplace arjunkambj/claude-mods

The first time, it asks to add the marketplace: press y. Then pick a scope (Enter picks "user", so it works in every project).

What you need

  • A Mac. imagegen and done-sound use macOS tools and sounds.
  • For codex and imagegen: the Codex CLI installed and signed in (codex login). Images count against your Codex plan.
Source 1 files
hooks/register.ts 101 lines
1import type { Register } from 'claude-code'
2
3const CODEX_TOOL = /^mcp__codex__codex$/
4const CODEX_MODEL = 'gpt-6.1-sol'
5const EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max'] as const
6// The codex tool runs only inside this background agent, so a long Codex run never blocks the main chat.
7const RUNNER = 'codex:runner'
8const RUNNER_PROMPT =
9  'You pass one task to Codex and bring back its answer. Call the codex tool exactly once with the task you were ' +
10  'given, word for word, as `task`. If the task names an effort level or says Codex may edit files, set `effort` or ' +
11  '`canEdit` to match. Then reply with Codex\'s answer exactly as it came back: add nothing, cut nothing.'
12
13type CodexInput = {
14  task: string
15  description?: string
16  effort?: (typeof EFFORTS)[number]
17  canEdit?: boolean
18}
19
20export const register: Register = on => {
21  on('session.start', async ($, e, next) => {
22    const started = await next(e)
23    await $.tool.register({
24      name: 'codex',
25      description:
26        `Only works inside the ${RUNNER} agent: from the main chat, spawn that agent with the Agent tool instead. ` +
27        `Hands a task to Codex (OpenAI's ${CODEX_MODEL}) running as a separate agent in this project, and returns its final answer. ` +
28        'Codex is great at code review and bug finding: use it for a second opinion on a diff, a hunt for bugs in a ' +
29        'file or feature, or checking a fix. Give it a self-contained task (it does not see this conversation): what to ' +
30        'look at, what to check, and how to report. Effort defaults to xhigh, which suits reviews; use max for the ' +
31        'hardest bugs and lower levels for quick checks. It runs read-only unless canEdit is true.',
32      inputSchema: {
33        type: 'object',
34        properties: {
35          task: { type: 'string', description: 'The full, self-contained instructions for Codex.' },
36          description: { type: 'string', description: 'A 3-5 word label for the task.' },
37          effort: { type: 'string', enum: EFFORTS, description: 'Reasoning effort; default xhigh.' },
38          canEdit: { type: 'boolean', description: 'Let Codex edit files in the project; default false.' },
39        },
40        required: ['task'],
41      },
42      isDeferred: false,
43    })
44    await $.agent.register({
45      name: 'runner',
46      description:
47        `Runs a task on Codex (OpenAI's ${CODEX_MODEL}) in the background and returns its answer; use this, never the ` +
48        'codex tool directly. Great for code review, bug hunts and checking a fix. The prompt is the whole task for ' +
49        'Codex (it does not see this conversation): what to look at, what to check, how to report. Add "effort: max" ' +
50        'for the hardest bugs or a lower level for quick checks (default xhigh), and "canEdit: true" to let it edit files.',
51      prompt: RUNNER_PROMPT,
52      tools: ['mcp__codex__codex'],
53      model: 'haiku',
54      effort: 'low',
55      background: true,
56      omitClaudeMd: true,
57    })
58    return started
59  })
60
61  on('tool.call', { tool: CODEX_TOOL }, async ($, e, next) => {
62    if (e.agentId === undefined) {
63      return { deny: `Run Codex through the Agent tool with subagent_type "${RUNNER}" so it runs in the background.` }
64    }
65    const input = e as unknown as CodexInput
66    const effort = input.effort ?? 'xhigh'
67
68    const it = $.process
69      .spawn({
70        argv: [
71          'codex', 'exec',
72          '-m', CODEX_MODEL,
73          '-c', `model_reasoning_effort="${effort}"`,
74          '-s', input.canEdit ? 'workspace-write' : 'read-only',
75          '--skip-git-repo-check', '--color', 'never',
76          input.task,
77        ],
78      })
79      [Symbol.asyncIterator]()
80    let answer = ''
81    let errors = ''
82    for (;;) {
83      if (next.signal.aborted) {
84        await it.return?.(undefined as never)
85        return { result: 'Codex run stopped.' }
86      }
87      const step = await it.next()
88      if (step.done) {
89        if (step.value.code !== 0) {
90          return { result: `Codex failed (exit ${step.value.code ?? step.value.signal}).\n${errors.slice(-4000)}` }
91        }
92        break
93      }
94      if (step.value.stream === 'stdout') answer += step.value.text
95      else errors += step.value.text
96    }
97
98    return { result: answer.trim() || 'Codex finished without an answer.' }
99  })
100}
101