Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ Then start a new session and define your first job:

> **Note:** DeepWork stores job definitions in `.deepwork/jobs/` and creates work branches in Git. Your project folder should be a Git repository. If it isn't, run `git init` first, or ask Claude to do so.

### Codex

When you run the DeepWork MCP server with `--platform codex`, DeepWork bootstraps
repo-local Codex hooks for you by ensuring:

- `.codex/config.toml` enables `codex_hooks`
- `.codex/hooks.json` contains the DeepWork `SessionStart` and `PostToolUse` handlers

This keeps the Codex hook setup checked into the project instead of relying on a
manual one-time local setup step.

---

## The Problem
Expand Down
7 changes: 6 additions & 1 deletion doc/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ The serve command:
- Creates `.deepwork/tmp/` lazily for session state
- Launches the FastMCP server (stdio or SSE transport)
- No config file required — works out of the box
- When started with `--platform codex`, also ensures repo-local Codex hook files
exist under `.codex/` so SessionStart and PostToolUse DeepWork hooks are enabled

### 2. Hook Command (`hook.py`)

Expand Down Expand Up @@ -181,6 +183,10 @@ Platform-specific delivery is now handled by plugins in `plugins/`:
- **Claude Code**: `plugins/claude/` — installed as a Claude Code plugin via marketplace
- **Gemini CLI**: `plugins/gemini/` — skill files copied to `.gemini/skills/`

Codex hook integration is repo-local rather than plugin-local today. When the MCP
server starts with `--platform codex`, DeepWork ensures `.codex/config.toml`
enables `codex_hooks` and `.codex/hooks.json` contains the DeepWork hook entries.

Each plugin contains static files (skill, hooks, MCP config) rather than generated content. The shared skill body lives in `platform/skill-body.md` as the single source of truth.

---
Expand Down Expand Up @@ -1109,4 +1115,3 @@ deepwork serve --transport sse --port 8000
- [JSON Schema](https://json-schema.org/)
- [Model Context Protocol](https://modelcontextprotocol.io/)
- [FastMCP Documentation](https://github.com/jlowin/fastmcp)

21 changes: 21 additions & 0 deletions src/deepwork/cli/codex_hook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Internal Codex hook entrypoints for DeepWork."""

from __future__ import annotations

import sys

import click

from deepwork.codex_hooks import CodexHookSetupError, run_codex_hook


@click.command(name="codex-hook", hidden=True)
@click.argument("hook_name", type=click.Choice(["session_start", "post_tool_use"]))
def codex_hook(hook_name: str) -> None:
"""Run a DeepWork Codex hook and emit the JSON response expected by Codex."""
raw_input = sys.stdin.read() if not sys.stdin.isatty() else ""
try:
click.echo(run_codex_hook(hook_name, raw_input))
except CodexHookSetupError as e:
click.echo(f"Error: {e}", err=True)
sys.exit(1)
2 changes: 2 additions & 0 deletions src/deepwork/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ def cli() -> None:


# Import commands
from deepwork.cli.codex_hook import codex_hook # noqa: E402
from deepwork.cli.hook import hook # noqa: E402
from deepwork.cli.install import install, sync # noqa: E402
from deepwork.cli.jobs import jobs # noqa: E402
from deepwork.cli.review import review # noqa: E402
from deepwork.cli.serve import serve # noqa: E402

cli.add_command(codex_hook)
cli.add_command(hook)
cli.add_command(jobs)
cli.add_command(review)
Expand Down
10 changes: 5 additions & 5 deletions src/deepwork/cli/review.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
@click.option(
"--instructions-for",
"instructions_for",
type=click.Choice(["claude"]),
type=click.Choice(["claude", "codex"]),
required=True,
help="Target platform for review instructions.",
)
Expand Down Expand Up @@ -54,15 +54,15 @@ def review(

\b
# Pipe from git
git diff --name-only HEAD~3 | deepwork review --instructions-for claude
git diff --name-only HEAD~3 | deepwork review --instructions-for codex

\b
# Glob (shell expands the pattern)
printf '%s\n' src/**/*.py | deepwork review --instructions-for claude
printf '%s\n' src/**/*.py | deepwork review --instructions-for codex

\b
# find
find src -name '*.py' | deepwork review --instructions-for claude
find src -name '*.py' | deepwork review --instructions-for codex
"""
project_root = Path(path).resolve()

Expand Down Expand Up @@ -101,7 +101,7 @@ def review(
sys.exit(1)

# Step 5: Format and output
if instructions_for == "claude":
if instructions_for in {"claude", "codex"}:
output = format_for_claude(task_files, project_root)
click.echo(output)

Expand Down
Loading
Loading