Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,19 @@ For bonus points, try `/deepwork learn` after running your workflow as well, and
</details>


### OpenClaw

OpenClaw support is installed from the bundle in [`plugins/openclaw/`](./plugins/openclaw/), while the DeepWork runtime comes from an installed `deepwork` CLI.

See [plugins/openclaw/README.md](./plugins/openclaw/README.md) for the full instructions. The short version is:

1. Clone this repo.
2. Install a DeepWork runtime that supports `deepwork serve --platform openclaw`.
3. Install the OpenClaw bundle from `plugins/openclaw/`.
4. Restart the OpenClaw gateway.

Most users should stop there. If you are testing unreleased DeepWork changes or OpenClaw is launching the wrong DeepWork binary, the OpenClaw guide also covers the exact `mcp.servers.deepwork` override to use.

---

## The Problem
Expand Down
7 changes: 7 additions & 0 deletions plugins/openclaw/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "deepwork",
"description": "Framework for AI-powered multi-step workflows with quality gates in OpenClaw",
"version": "0.11.0",
"skills": ["skills"],
"hooks": ["hooks"]
}
8 changes: 8 additions & 0 deletions plugins/openclaw/.mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"mcpServers": {
"deepwork": {
"command": "uvx",
"args": ["deepwork", "serve", "--platform", "openclaw"]
}
}
}
216 changes: 216 additions & 0 deletions plugins/openclaw/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# DeepWork for OpenClaw

This bundle lets OpenClaw use DeepWork's workflow and review MCP tools without relying on Claude-specific hooks.

It packages three things together:

- OpenClaw skills for DeepWork workflows and reviews
- an OpenClaw bootstrap hook that injects DeepWork session guidance
- an MCP config that starts `uvx deepwork serve --platform openclaw`

## What This Bundle Adds

When OpenClaw installs this directory as a bundle, it loads:

- [`.codex-plugin/plugin.json`](./.codex-plugin/plugin.json) so the directory is detected as a Codex bundle
- [`skills/deepwork/SKILL.md`](./skills/deepwork/SKILL.md) for workflow execution guidance
- [`skills/review/SKILL.md`](./skills/review/SKILL.md) for review execution guidance
- [`hooks/deepwork-openclaw-bootstrap/HOOK.md`](./hooks/deepwork-openclaw-bootstrap/HOOK.md) and [`handler.ts`](./hooks/deepwork-openclaw-bootstrap/handler.ts) to inject session and resume context into OpenClaw bootstrap
- [`.mcp.json`](./.mcp.json) so OpenClaw exposes DeepWork MCP tools as `deepwork__<tool_name>`

This is an OpenClaw-native bundle shape. It does not depend on Claude's `hooks.json` automation.

## Prerequisites

- OpenClaw with bundle support
- a DeepWork runtime that supports `deepwork serve --platform openclaw`
- `uv` installed, because the bundle launches DeepWork with `uvx`
- a Git repository for the target project

DeepWork stores job definitions under `.deepwork/` and may create work branches while executing workflows. If the target project is not already a Git repository, initialize it first.

## Install

### 1. Clone DeepWork

OpenClaw installs the bundle from this directory, so start by cloning the DeepWork repo:

```bash
git clone https://github.com/Unsupervisedcom/deepwork.git
cd deepwork
```

If you are testing an unreleased branch, check out that branch before continuing. Otherwise stay on the default branch or a released tag.

### 2. Install DeepWork

```bash
uv tool install deepwork
```

This installs the `deepwork` CLI that the OpenClaw bundle launches over MCP.

Verify that the installed runtime supports OpenClaw:

```bash
deepwork serve --platform openclaw
```

If that command fails, upgrade to a newer DeepWork release before installing the bundle.

### 3. Install the OpenClaw bundle

Install the bundle from this checkout:

```bash
openclaw plugins install /path/to/deepwork/plugins/openclaw
openclaw plugins inspect deepwork
openclaw gateway restart
```

Expected output from `openclaw plugins inspect deepwork`:

- `Format: bundle`
- bundle subtype `codex`
- skill roots from `skills/`
- a hook pack from `hooks/`
- an MCP server named `deepwork`

## First Run

Start a new OpenClaw session after installing the bundle.

Typical user prompts:

- `Use DeepWork to create a workflow for shipping release notes.`
- `Use DeepWork to run the tutorial_writer workflow.`
- `Use DeepWork review on this change set.`

The agent should then:

1. Read the injected DeepWork bootstrap note.
2. Use the current OpenClaw `sessionId` as DeepWork `session_id`.
3. Call `deepwork__get_active_workflow` before starting something new if prior DeepWork state exists.
4. Use `deepwork__get_workflows` and `deepwork__start_workflow` to execute workflows.
5. Before `deepwork__finished_step`, compare your payload to `step_expected_outputs` or call `deepwork__validate_step_outputs`.
6. Use `deepwork__get_review_instructions` and launch review tasks with `sessions_spawn`.

## Runtime Contract

This bundle deliberately keeps the DeepWork runtime mostly unchanged and adapts OpenClaw to it.

- DeepWork `session_id` maps to the current OpenClaw `sessionId`
- DeepWork `agent_id` is usually left unset in OpenClaw
- the bootstrap hook writes a synthetic note into bootstrap context so the agent sees the correct `session_id`
- if DeepWork state already exists for the current session, the hook tells the agent to call `deepwork__get_active_workflow`

DeepWork session state for this bundle lives under:

```text
.deepwork/tmp/sessions/openclaw/session-<sessionId>/state.json
```

## Reviews in OpenClaw

DeepWork quality gates can return review tasks. In OpenClaw, those should be run as parallel sub-agents with `sessions_spawn`.

That is why this bundle includes a separate OpenClaw review skill and platform-specific quality-gate formatting. The Claude formatter path is still separate and unchanged.

## Current Limitation

This first OpenClaw adapter scopes DeepWork state to the current OpenClaw session.

That means:

- resume works reliably inside the same OpenClaw session
- `deepwork__get_active_workflow` works after compaction or reset for that same session
- spawned OpenClaw child sessions do not yet share one root DeepWork workflow stack the way Claude Code can

This is a host-context limitation, not a workflow-engine limitation. The current OpenClaw bootstrap hook surface does not expose enough parent/root session metadata to recreate DeepWork's Claude-style shared root session model.

## Troubleshooting

### The DeepWork tools do not appear in OpenClaw

Check:

- the bundle was installed from this directory, not the repo root
- `openclaw plugins inspect deepwork` shows a bundle with an MCP server
- you restarted the OpenClaw gateway after installation
- you started a fresh OpenClaw session after the restart
- the runtime itself starts cleanly:

```bash
uvx deepwork --version
uvx deepwork serve --platform openclaw
```

If `uvx` works in your shell but OpenClaw still does not expose the tools, use the pinned top-level `mcp.servers.deepwork` override shown in the troubleshooting steps below so the gateway launches an exact binary instead of relying on `PATH` or `uvx` resolution.

### I am testing unreleased DeepWork changes from a local checkout

Register the checkout as an editable `uv` tool:

```bash
uv tool install -e /path/to/deepwork
```

This makes `uvx deepwork` resolve to your checkout instead of whatever version is published.

If OpenClaw is still launching the wrong binary, add a top-level `mcp.servers.deepwork` override that points to the exact `deepwork` executable you want:

```json
{
"mcp": {
"servers": {
"deepwork": {
"command": "/absolute/path/to/deepwork",
"args": ["serve", "--platform", "openclaw"]
}
}
}
}
```

Restart the OpenClaw gateway after changing the override.

### OpenClaw is launching the wrong DeepWork binary

Check both launch paths explicitly:

```bash
uvx deepwork --version
deepwork --version
```

Then point OpenClaw at the exact binary you want with a top-level `mcp.servers.deepwork` override:

```json
{
"mcp": {
"servers": {
"deepwork": {
"command": "/absolute/path/to/deepwork",
"args": ["serve", "--platform", "openclaw"]
}
}
}
}
```

Restart the OpenClaw gateway after changing the override.

### The agent starts a second workflow instead of resuming

Tell the agent to call `deepwork__get_active_workflow` first. That is the intended resume path for OpenClaw after session restore, compaction, or ambiguity about current state.

## Note for Existing Claude Users

If you already use the Claude Code DeepWork plugin on this machine, you may already have a working DeepWork runtime via `uvx`. Before installing DeepWork separately, check:

```bash
uvx deepwork --version
uvx deepwork serve --platform openclaw
```

If that works, you can use the existing runtime. If it fails, install DeepWork explicitly with `uv tool install deepwork` and then continue with the steps above.
19 changes: 19 additions & 0 deletions plugins/openclaw/hooks/deepwork-openclaw-bootstrap/HOOK.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
name: deepwork-openclaw-bootstrap
description: "Inject DeepWork session and resume guidance into OpenClaw bootstrap context"
metadata:
{
"openclaw":
{
"emoji": "🧭",
"events": ["agent:bootstrap"],
"install": [{ "id": "deepwork", "kind": "bundled", "label": "Bundled with DeepWork OpenClaw plugin" }],
},
}
---

# DeepWork OpenClaw Bootstrap

Injects a small synthetic bootstrap note that tells the agent which `session_id`
to use for DeepWork MCP tools in the current OpenClaw session, and whether it
should try `deepwork__get_active_workflow` to restore prior DeepWork state.
109 changes: 109 additions & 0 deletions plugins/openclaw/hooks/deepwork-openclaw-bootstrap/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import fs from "node:fs";
import path from "node:path";

const SYNTHETIC_NOTES = [
{
name: "BOOTSTRAP.md",
relativePath: ".deepwork/tmp/openclaw/DEEPWORK_OPENCLAW_BOOTSTRAP.md",
},
{
name: "TOOLS.md",
relativePath: ".deepwork/tmp/openclaw/DEEPWORK_OPENCLAW.md",
},
] as const;

function readTrimmedString(value: unknown): string {
return typeof value === "string" ? value.trim() : "";
}

const handler = async (event: any) => {
if (event?.type !== "agent" || event?.action !== "bootstrap") {
return;
}

const context = event.context ?? {};
if (!Array.isArray(context.bootstrapFiles)) {
return;
}

const workspaceDir = readTrimmedString(context.workspaceDir);
const sessionId = readTrimmedString(context.sessionId);
if (!workspaceDir || !sessionId) {
return;
}

const sessionKey = readTrimmedString(context.sessionKey) || "(unknown)";
const agentId = readTrimmedString(context.agentId) || "(unknown)";
const syntheticNotes = SYNTHETIC_NOTES.map((note) => ({
...note,
path: path.join(workspaceDir, note.relativePath),
}));
const statePath = path.join(
workspaceDir,
".deepwork",
"tmp",
"sessions",
"openclaw",
`session-${sessionId}`,
"state.json",
);
const hasActiveState = fs.existsSync(statePath);

const content = `# DeepWork OpenClaw Runtime

Use these values when calling DeepWork MCP tools from this OpenClaw session:

- session_id: \`${sessionId}\`
- session_key: \`${sessionKey}\`
- agent_id: \`${agentId}\`
- workspace_dir: \`${workspaceDir}\`

Guidance:

- Use the current OpenClaw session's \`sessionId\` as DeepWork \`session_id\`.
- Ignore any stale \`BOOTSTRAP.md\` files or hardcoded \`session_id\` values elsewhere in the workspace. The current OpenClaw session values above win.
- In OpenClaw, leave DeepWork \`agent_id\` unset unless you intentionally want a separate agent-scoped DeepWork state file.
- DeepWork relative paths are rooted at \`workspace_dir\`, not the plugin bundle directory.
- ${
hasActiveState
? "DeepWork state already exists for this session. Call `deepwork__get_active_workflow` before starting a new workflow unless you are sure you want a second one."
: "No DeepWork state has been detected for this session yet."
}
- Before \`deepwork__finished_step\`, compare your outputs to \`step_expected_outputs\` or call \`deepwork__validate_step_outputs\`.
- For review work returned by DeepWork quality gates, prefer parallel OpenClaw sub-agents via \`sessions_spawn\`.
- Spawn all requested review sub-agents before waiting for completions.
- Keep DeepWork instruction paths workspace-relative; do not rewrite them as absolute host paths.
- Omit \`timeoutSeconds\` on review spawns so the runtime default applies. If a timeout value is required, use \`0\`.
- After all review spawns are accepted, use \`sessions_yield\` while you wait for completion events.
`;

for (const note of syntheticNotes) {
try {
fs.mkdirSync(path.dirname(note.path), { recursive: true });
fs.writeFileSync(note.path, content, "utf8");
} catch {
// Best-effort persistence for runtime session hints. The in-memory bootstrap
// injection below still gives the model the same guidance if disk writes fail.
}
}

context.bootstrapFiles = context.bootstrapFiles
.filter((file: any) => {
const filePath = readTrimmedString(file?.path);
const fileName = readTrimmedString(file?.name);
if (fileName === "BOOTSTRAP.md") {
return false;
}
return !syntheticNotes.some((note) => note.path === filePath);
})
.concat(
syntheticNotes.map((note) => ({
name: note.name,
path: note.path,
content,
missing: false,
})),
);
};

export default handler;
Loading
Loading