Skip to content
Merged
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
56 changes: 53 additions & 3 deletions plugins/claude/skills/new_user/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,65 @@ Guide a new user through what DeepWork can do and help them get started.

## Flow

### 0. Run setup
### 0. Check dependencies and run setup

Before anything else, run the setup command to ensure the user's environment is configured:
#### 0a. Check for `uv`

The DeepWork MCP server requires `uv` (specifically `uvx`). Check if it is installed:

```bash
command -v uv
```

**If `uv` is NOT found**, install it:

- On macOS/Linux:
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```
- On Windows (PowerShell):
```powershell
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
```

After installing, verify it works:
```bash
uv --version
```

If `uv` was just installed, set `UV_WAS_INSTALLED=true` (you will need this later).

#### 0b. Reload if `uv` was just installed

If `UV_WAS_INSTALLED=true` (from step 0a), the MCP server could not have started when this session began because `uvx` was missing. Use `AskUserQuestion` to tell the user:

> I just installed `uv`, which DeepWork's MCP server needs to run. For everything to work, please type `/reload-plugins` now, then come back and tell me it's done.

Wait for the user to confirm they have reloaded. Do not proceed until they confirm.

#### 0c. Run setup

Run the setup command to configure Claude Code settings (marketplace, plugin, MCP permissions, auto-update):

```bash
uvx deepwork setup
```

This configures Claude Code settings (marketplace, plugin, MCP permissions, auto-update). Proceed regardless of the output.
Proceed regardless of the output.

#### 0d. Verify the MCP server is running

Call `get_workflows` (using the `mcp__plugin_deepwork_deepwork__get_workflows` tool). If it succeeds, the server is healthy — continue. If it errors, tell the user:

> The DeepWork MCP server isn't responding. This usually means `uv` isn't on your PATH or the plugin needs a restart. Try quitting Claude Code completely and reopening it, then run `/deepwork:new_user` again.

Stop the onboarding if the server is not reachable — continuing without it will just produce more confusing errors.

#### 0e. macOS note (macOS only)

If the platform is macOS, briefly mention:

> **Heads up**: during reviews or workflows that scan files, macOS may pop up permission dialogs for Photos, Dropbox, or other locations outside this project. These are safe to **deny** — DeepWork only needs access to your project directory and the review will still complete fine.

### 1. GitHub star (optional)

Expand Down
25 changes: 13 additions & 12 deletions src/deepwork/setup/claude.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,20 @@
"repo": "Unsupervisedcom/deepwork",
}
PLUGIN_KEY = "deepwork@deepwork-plugins"
MCP_PERMISSION = "mcp__plugin_deepwork_deepwork__*"
# Permissions granting full access to .deepwork/ in every project.
# Leading slash makes the path project-root-relative (per Claude Code docs),
# so these rules apply to `.deepwork/**/*` in each project, not `~/.deepwork/`.
DEEPWORK_DIR_PERMISSIONS = [
# All permissions to add to settings.permissions.allow.
ALLOW_PERMISSIONS = [
# MCP tools
"mcp__plugin_deepwork_deepwork__*",
# .deepwork/ directory access (leading slash = project-root-relative)
"Read(/.deepwork/**/*)",
"Write(/.deepwork/**/*)",
"Edit(/.deepwork/**/*)",
# Bash commands the plugin routinely runs (uv cache glob covers hash-varying paths)
"Bash(deepwork:*)",
"Bash(uvx deepwork:*)",
"Bash(~/.cache/uv/archive-v0/*/bin/deepwork:*)",
"Bash(command -v uv)",
"Bash(uv --version)",
]


Expand Down Expand Up @@ -65,15 +71,10 @@ def claude_setup() -> list[str]:
enabled_plugins[PLUGIN_KEY] = True
changes.append(f"Enabled plugin '{PLUGIN_KEY}'")

# 3. Ensure MCP tool permission is in allow list
# 3. Ensure all required permissions are in allow list
permissions = settings.setdefault("permissions", {})
allow = permissions.setdefault("allow", [])
if MCP_PERMISSION not in allow:
allow.append(MCP_PERMISSION)
changes.append(f"Added '{MCP_PERMISSION}' to permissions.allow")

# 4. Ensure full access to .deepwork/ in every project
for perm in DEEPWORK_DIR_PERMISSIONS:
for perm in ALLOW_PERMISSIONS:
if perm not in allow:
allow.append(perm)
changes.append(f"Added '{perm}' to permissions.allow")
Expand Down
15 changes: 6 additions & 9 deletions tests/unit/test_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@

from deepwork.cli.main import cli
from deepwork.setup.claude import (
DEEPWORK_DIR_PERMISSIONS,
ALLOW_PERMISSIONS,
MARKETPLACE_KEY,
MCP_PERMISSION,
PLUGIN_KEY,
claude_setup,
)
Expand All @@ -40,7 +39,8 @@ class TestClaudeSetupFreshFile:
# YOU MUST NOT MODIFY THIS TEST UNLESS THE REQUIREMENT CHANGES
def test_creates_settings(self, claude_home: Path) -> None:
changes = claude_setup()
assert len(changes) == 6
# 1 marketplace + 1 plugin + len(ALLOW_PERMISSIONS) permissions
assert len(changes) == 2 + len(ALLOW_PERMISSIONS)
settings = _read_settings(claude_home)

# marketplace registered
Expand All @@ -53,11 +53,8 @@ def test_creates_settings(self, claude_home: Path) -> None:
# plugin enabled
assert settings["enabledPlugins"][PLUGIN_KEY] is True

# MCP permission
assert MCP_PERMISSION in settings["permissions"]["allow"]

# .deepwork directory permissions (project-relative via leading slash)
for perm in DEEPWORK_DIR_PERMISSIONS:
# all permissions present
for perm in ALLOW_PERMISSIONS:
assert perm in settings["permissions"]["allow"]


Expand Down Expand Up @@ -103,7 +100,7 @@ def test_creates_claude_dir(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatc
monkeypatch.setattr(Path, "home", staticmethod(lambda: fake_home))

changes = claude_setup()
assert len(changes) == 6
assert len(changes) == 2 + len(ALLOW_PERMISSIONS)
assert (fake_home / ".claude" / "settings.json").exists()


Expand Down
Loading