https://github.com/ehzawad/claude-opinion
A Codex CLI skill that pipes context to Claude Code for a second opinion.
https://github.com/ehzawad/claude-opinion
claude claude-ai claude-code claude-code-plugin codex codex-cli skills
Last synced: about 2 months ago
JSON representation
A Codex CLI skill that pipes context to Claude Code for a second opinion.
- Host: GitHub
- URL: https://github.com/ehzawad/claude-opinion
- Owner: ehzawad
- Created: 2026-04-21T07:46:00.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-04-23T20:35:23.000Z (about 2 months ago)
- Last Synced: 2026-04-23T22:19:38.548Z (about 2 months ago)
- Topics: claude, claude-ai, claude-code, claude-code-plugin, codex, codex-cli, skills
- Language: Python
- Homepage:
- Size: 37.1 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# claude-opinion
An OpenAI Codex CLI skill that brings Anthropic's Claude Code into your work as a distinct second model. You, Codex, and Claude in the loop. Install once; invoke from any Codex project.
Mirror of [ehzawad/codex-opinion](https://github.com/ehzawad/codex-opinion) (which brings Codex into Claude Code); this reverses the direction.
## Prerequisites
- [OpenAI Codex CLI](https://developers.openai.com/codex/cli) — authenticated (`codex` in terminal)
- [Claude Code](https://claude.ai/code) — authenticated (`claude auth status` should show logged in)
Both must be logged in and working in your terminal before using this skill.
## Install
For a first-time install, clone the skill directly into Codex's user-level skills directory:
```bash
mkdir -p ~/.agents/skills
git clone https://github.com/ehzawad/claude-opinion.git ~/.agents/skills/claude-opinion
```
This is a user-level install: Codex reads user skills from `$HOME/.agents/skills` and follows symlinked skill folders. If you are developing the skill from a separate checkout, symlink that checkout into the same user-level directory:
```bash
cd /path/to/claude-opinion
mkdir -p ~/.agents/skills
ln -s "$(pwd)" ~/.agents/skills/claude-opinion
```
Codex usually detects newly installed skills automatically. Restart Codex if `$claude-opinion` does not appear.
## Update
To update an installed checkout to the latest version:
```bash
python3 ~/.agents/skills/claude-opinion/scripts/update_skill.py
```
The updater fast-forwards your local checkout from the remote default branch and refuses to run if that checkout has local edits. If you installed the skill by symlinking a development checkout into `~/.agents/skills`, the updater still works, but it updates the underlying source repo rather than the symlink itself.
You can still update manually with git if you prefer:
```bash
git -C ~/.agents/skills/claude-opinion pull --ff-only
```
## Usage
```text
$claude-opinion
```
Or naturally via phrases like "ask claude," "second opinion," "another perspective."
Use `$claude-opinion` for deterministic skill invocation. Codex reserves `/` for built-in slash commands; named skills are invoked via `$`.
## How it works
The script ships stdin to Claude via `claude -p --output-format json`, sets the highest supported `--effort` level, and adds a short generic review directive on `--append-system-prompt`. Stdin stays as pure context. On the first call per project, the script lets Claude allocate the session ID and persists the returned `session_id` (via compare-and-save — see Session management below). Follow-up calls resume the same session via `--resume `, so Claude carries accumulated project knowledge across Codex sessions.
Codex reconciles Claude's response against its own assessment and reports the reconciled output to the user.
```mermaid
sequenceDiagram
participant U as User
participant C as Codex CLI
participant S as ask_claude.py
participant X as Claude Code
U->>C: $claude-opinion (or natural trigger)
C->>C: Compose adaptive context
C->>S: Pipe context via stdin
S->>X: claude -p --output-format json
(env stripped, highest effort, fresh or resume)
X-->>S: {result, is_error, session_id, ...}
S->>S: Parse outer JSON, check is_error
S-->>C: Claude's analysis via stdout
C-->>U: Reconciles and reports
```
## Session management
One Claude session per project, stored at `$XDG_STATE_HOME/claude-opinion/{project-hash}.json` (default `~/.local/state/claude-opinion/...`). State writes are serialized by an `fcntl` lock and use generation-aware reads:
- **Stale-session clearing** is compare-and-clear: the file is only removed if its current `session_id` still matches the one we tried to resume, so a parallel invocation that has already written a fresh ID is preserved.
- **Fresh-call save** is compare-and-save: the new session_id only overwrites state if the current state still matches what we observed at entry (or the file is empty). If a parallel invocation has already persisted a different ID since we started, our save is skipped with a stderr warning, and the next call resumes theirs.
- **Resume-success save** uses the same compare-and-save guard. Claude can rotate the session ID on `--resume`, and a sibling invocation may write a different fresh/resumed ID while we're blocked in `claude --resume `; saving unconditionally would clobber it.
If a successful call returns a result but no `session_id`, the script prints a warning, returns the answer, and skips the session save — next call starts fresh rather than discarding the user's answer.
If the state file becomes corrupt (e.g. JSON garbled by an external writer or another tool's crash), the next call quarantines it under `{project-hash}.json.corrupt.{nanoseconds}.{pid}` and warns with the full path. The follow-up save persists a fresh session_id normally — the corrupt file is preserved for inspection rather than silently overwritten or trapped in a fresh-then-refuse-save loop. The whole load/quarantine sequence runs under the state lock so a sibling save can't slip valid data in between the failed parse and the rename.
If the rename itself fails (e.g. directory permissions, read-only FS), the script aborts with an error rather than spending on a `claude -p` call that won't be persistable; remove or fix the state directory and rerun.
Other resume failures surface as hard errors with Claude's stderr.
Set `CLAUDE_OPINION_SESSION_KEY` before launching Codex to scope state to that session — the state file becomes `{project-hash}-{session-hash}.json` and the session gets its own Claude thread.
See [DESIGN.md](DESIGN.md) for the session-management flowchart and JSON protocol diagram.
## Security
Claude runs with `--dangerously-skip-permissions` — no approval prompts. This gives Claude full read/write access to your machine so it can thoroughly inspect and analyze the current project. A short safety directive (*"do not modify files or run mutating commands; provide analysis only"*) is appended to whatever instruction is active — built-in *and* user-supplied — so a benign custom instruction like *"focus on test coverage"* still runs analysis-only by default. Pass `--allow-edit` to opt out (only do this if you genuinely want Claude to edit files, e.g. *"review and fix the migration"*); `--no-default-instruction` skips everything for raw passthrough. Do not use this skill on untrusted projects or with untrusted input.
## Configuration
The script uses your Claude Code default model and other non-overridden settings. It explicitly selects the highest effort level advertised by the installed Claude CLI: `max` when available, otherwise the next highest known level (`xhigh`, `high`, `medium`, `low`). If the CLI has no `--effort` support, the flag is omitted. No model is hardcoded. Permission bypass is overridden by the skill (see Security above).
The `claude -p` subprocess is bounded by `CLAUDE_OPINION_TIMEOUT` (env var, default `600` seconds), and it runs in its own process group so a timeout kills the whole tree (claude itself plus any tool subprocesses it spawned during execution) — `subprocess.run`'s built-in timeout signals only the direct child. Set a larger value if you regularly run very long opinions; non-numeric or non-positive values fall back to the default rather than disabling the timeout. The one-shot `claude --help` probe used to detect supported `--effort` levels is bounded separately at 10 seconds so a hung help call can't wedge the script before the protected `claude -p` call ever runs.
## Subprocess auth routing
The script strips `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, and `ANTHROPIC_BASE_URL` from the child `claude` process's environment so Claude.ai subscription auth wins over API-key or proxy-gateway routing (see [anthropics/claude-code#2051](https://github.com/anthropics/claude-code/issues/2051)). Without stripping, a present `ANTHROPIC_API_KEY` routes billing to the API key — which may be a different, possibly-empty balance than the subscription.
The script also intentionally does not use `--bare`. Current Claude Code CLI help documents that `--bare` disables OAuth and keychain auth reads, so bare mode cannot use a Claude.ai subscription login.
If you specifically *want* API-key or proxy routing for this skill, set `CLAUDE_OPINION_KEEP_ANTHROPIC_ENV=1` in your environment to skip the strip.
## License
MIT