Create Workspace
A skill for scaffolding structured, multi-repo development workspaces optimized for parallel work by multiple agents and human developers.
Workspace Structure
{workspace-name}/
├── workspace.yaml # manifest: repos, worktrees, deps, metadata
├── CLAUDE.md # project-wide agent context and conventions
├── .gitignore # ignores sketch/ directory
├── .claude/
│ └── settings.json # permissions for coding agents
├── repositories/
│ └── {repoName}/
│ ├── main/ # regular clone at default branch (worktree parent)
│ └── worktrees/
│ └── {worktreeName}/ # git worktree checkouts
├── docs/ # cross-repo design docs, ADRs, specs
├── deps/
│ └── {depName}/ # full clones of dependency repos
├── tasks/ # task assignments and coordination
└── sketch/ # .gitignored agent scratch space
Workflows
1. Create a New Workspace
When the user asks to create a workspace, follow these steps:
Step 1: Gather information. Ask the user for:
- Workspace name (will be the root directory name)
- A short description of the project/task
- Where to create the workspace. Offer the current working directory as the default option, and let the user specify a different path. The workspace will be created as a subdirectory at the chosen location (i.e.,
{chosen-path}/{workspace-name}/). - Repositories to include (and which worktrees/branches to create). Accept any of these formats:
- HTTPS URL:
https://github.com/user/repo.git - SSH URL:
git@github.com:user/repo.git - GitHub shorthand:
user/repoorUsername/repoName
- HTTPS URL:
- Dependency repositories (if any), in the same formats above.
If the user provides a workspace.yaml file or its contents, parse it directly instead of asking.
Resolving repository references:
When the user provides a GitHub shorthand (user/repo) instead of a full URL:
- Try
ghCLI first: Rungh repo view user/repo --json url -q .urlto get the HTTPS URL. This works if the user hasghinstalled and authenticated. - Try GitHub MCP: If
ghCLI is not available, use the GitHub MCPget_file_contentsorsearch_repositoriestool to verify the repository exists and get its URL. - Fallback — web search: If neither
ghCLI nor GitHub MCP is available, use web search to find the repository URL, then ask the user to confirm before cloning.
Once resolved, clone using the full URL. Store the resolved URL in workspace.yaml.
Step 2: Create the directory structure.
mkdir -p {path}/{workspace-name}/{repositories,docs,deps,tasks,sketch}
Where {path} is the location chosen in Step 1 (defaults to the current working directory).
Step 3: Generate the workspace.yaml manifest.
Use the template from assets/workspace.yaml.template as a reference. The manifest should
capture all repositories, their worktrees, and dependencies. Write it to {workspace-name}/workspace.yaml.
Step 4: Resolve and clone repositories.
First, resolve any GitHub shorthand references to full URLs (see "Resolving repository references" above).
Then, for each repository in the manifest:
# Clone the repository into the main/ directory
git clone {resolved-url} {workspace-root}/repositories/{repoName}/main
# For each worktree, create a branch and worktree
cd {workspace-root}/repositories/{repoName}/main
git worktree add ../worktrees/{worktreeName} -b {branchName}
If the branch already exists on the remote, use checkout instead of -b:
git worktree add ../worktrees/{worktreeName} {branchName}
Important worktree notes:
- The
main/clone is the worktree parent. Agents should avoid switching branches inmain/. - Each worktree is an independent working directory with its own HEAD, index, and working tree.
- Multiple agents can work on different worktrees of the same repo simultaneously without conflicts.
Step 5: Clone dependencies.
For each dependency in the manifest:
# Full clone (not shallow — deps may contain bugs or ongoing work to analyze)
git clone {url} {workspace-name}/deps/{depName}
# If a specific ref is specified, check it out
cd {workspace-name}/deps/{depName}
git checkout {ref}
Step 6: Generate the CLAUDE.md.
Use the template from assets/CLAUDE.md.template as a starting point. Populate it with:
- The workspace description from the manifest
- The list of repositories with their purposes
- The list of worktrees and what each is for
- The list of dependencies
- Cross-repo relationships (ask the user if not obvious)
Step 7: Create the .gitignore.
Write a .gitignore at the workspace root:
sketch/
Step 8: Set up agent permissions.
Create .claude/settings.json at the workspace root using the modular permission system.
Permissions are built from composable modules in assets/permissions/.
mkdir -p {workspace-name}/.claude
8a. Start with required modules. Two modules are always included:
_base— Read, Glob, Grep, WebSearch, git read-only, worktree management, general utilities._security— Deny rules for destructive operations (rm -rf,sudo, force push,git reset --hard) and sensitive file access (.env, SSH keys, cloud credentials, PEM/key files).
Note: .env.example and .env.template files are intentionally not blocked — agents need to read these to understand the environment variable setup.
8b. Auto-detect optional modules. Scan the cloned repositories for files that indicate a tech stack.
Use the detect field in each module file to match. Modules with "always_suggest": true are
always included in the suggestion list regardless of detection signals. Modules with an empty
detect array and no always_suggest flag are not auto-detected (they must be manually selected).
| Module | Detection signals |
|---|---|
github | .git directory (any git repo) |
context7 | (always suggest — has always_suggest: true in module file) |
nodejs | package.json |
python | requirements.txt, pyproject.toml, setup.py, setup.cfg, Pipfile |
rust | Cargo.toml |
go | go.mod |
docker | Dockerfile, docker-compose.yaml, docker-compose.yml, compose.yaml, compose.yml |
playwright | playwright.config.ts, playwright.config.js |
8c. Present the selection to the user. Show which modules were auto-detected and let them adjust:
I detected the following permission modules based on your repositories:
github— GitHub MCP tools and gh CLInodejs— npm/yarn/pnpm/bun build, test, lint, installpython— pytest, mypy, ruff, pip, poetry, uvrust— cargo build, test, clippy, addgo— go test, build, vet, moddocker— Docker inspection, lifecycle, composeplaywright— browser automation and inspectioncontext7— library documentation lookupWould you like to add, remove, or adjust any of these?
Wait for the user to confirm or adjust before proceeding.
8d. Ask about custom permissions. After module selection, ask:
Would you like to add any custom permission rules? You can specify:
- Tools or commands to auto-allow (e.g.,
Bash(terraform plan *))- Tools or commands to require confirmation (e.g.,
Bash(terraform apply *))- Tools or commands to always block (e.g.,
Bash(terraform destroy *))Or skip this step if the modules above cover your needs.
If the user provides custom rules, validate the syntax (must follow Claude Code permission format: Tool, Tool(specifier), or Tool(glob*pattern)) and add them to the appropriate tier.
8e. Preview the merged permissions. Before writing, show the user a summary of the final configuration:
Permission preview (modules:
_base,_security,github,nodejs,docker,context7):
Tier Count Examples Allow N Read,Bash(git log *),mcp__plugin_github_github__issue_read,Bash(npm run *)Ask N Bash(git push *),mcp__plugin_github_github__create_pull_request,Bash(npm install *)Deny N Bash(rm -rf *),Bash(git push --force *),Read(./**/.env)
Replace _N_ with the actual deduplicated counts computed from the merged module files.
Full JSON will be written to
.claude/settings.json. Does this look good?
Wait for the user to confirm. If they want changes, loop back to 8c or 8d.
8f. Write the settings file. Merge all selected modules:
- Read each selected module JSON from
assets/permissions/. - Union all
allowarrays, then allaskarrays, then alldenyarrays. - Deduplicate each array (preserve insertion order).
- If the user provided custom rules, append them to the appropriate arrays.
- Write the merged result as
.claude/settings.json:
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [ ... ],
"ask": [ ... ],
"deny": [ ... ]
}
}
Important: Record which modules were included by adding a top-level _modules key to the settings file. This key is ignored by Claude Code but allows the skill to know what's active for future additions/removals:
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"_modules": ["_base", "_security", "github", "nodejs", "docker", "context7"],
"permissions": { ... }
}
Step 9: Confirm completion. Summarize what was created:
- Number of repositories cloned
- Number of worktrees created
- Number of dependencies cloned
- Location of the workspace
2. Add a Repository to an Existing Workspace
When the user asks to add a repo to an existing workspace:
- Read the existing
workspace.yaml - Clone the repo into
repositories/{repoName}/main/ - Create any requested worktrees
- Update
workspace.yamlwith the new repository entry - Update
CLAUDE.mdto include the new repository
3. Add a Worktree to an Existing Repository
When the user asks to add a worktree:
- Read
workspace.yamlto find the repository - Create the worktree:
cd {workspace}/repositories/{repoName}/main git worktree add ../worktrees/{worktreeName} -b {branchName} - Update
workspace.yamlwith the new worktree entry
4. Add a Dependency
When the user asks to add a dependency:
- Clone the dependency into
deps/{depName}/ - Optionally check out a specific ref
- Update
workspace.yaml - Update
CLAUDE.md
5. Show Workspace Status
When the user asks about workspace status:
- Read
workspace.yaml - For each repository and worktree, run
git statusandgit log --oneline -3 - Report: current branches, uncommitted changes, recent commits
6. Remove a Worktree
When the user asks to remove a worktree:
- Run
git worktree removefrom the main clone - Update
workspace.yaml
7. Manage Workspace Permissions
A standalone workflow for adding, removing, previewing, or customizing permission modules
in an existing workspace. This operates on the .claude/settings.json file at the workspace root.
Triggers: "add permissions", "set up github permissions", "add docker permissions to workspace", "show workspace permissions", "remove python permissions", "add custom permissions".
7a. Add Permission Modules
When the user asks to add permissions (e.g., "add github and docker permissions"):
- Read the existing
.claude/settings.jsonat the workspace root. - Check the
_modulesarray to see what's already active. - Read the requested module JSON files from
assets/permissions/. - Show a preview of what will be added:
Adding modules:
github,dockerAlready active:_base,_security,nodejsNew rules being added:
Tier New rules Examples Allow +34 mcp__plugin_github_github__issue_read,Bash(docker ps *)Ask +37 mcp__plugin_github_github__create_pull_request,Bash(docker build *)Deny +3 Bash(docker system prune *)Proceed?
- On confirmation, merge the new module rules into the existing arrays (deduplicate).
- Update the
_modulesarray. - Write back
.claude/settings.json.
7b. Remove Permission Modules
When the user asks to remove permissions (e.g., "remove docker permissions"):
- Read
.claude/settings.jsonand the_modulesarray. - Verify the module is active. If not, inform the user.
- Cannot remove
_baseor_security— these are required. Warn the user if they try. - Show a preview of what will be removed:
Removing module:
dockerRules that will be removed: 11 allow, 10 ask, 3 deny Proceed?
- On confirmation, read the module's JSON file to get its rule list.
- For each rule in the module being removed, check all other active modules' JSON files
(from the remaining
_modulesarray). Only remove the rule fromsettings.jsonif no other active module also declares the same rule. This prevents breaking shared rules. - Update the
_modulesarray (remove the module name). - Write back
.claude/settings.json.
7c. List Active Permissions
When the user asks about current permissions (e.g., "show workspace permissions", "what permissions are set up"):
- Read
.claude/settings.json. - Display the active modules from
_modulesand a summary:
Active permission modules:
Module Description Allow Ask Deny _baseCore tools, git read, utilities N N 0 _securityDestructive ops, sensitive files 0 0 N githubGitHub MCP + gh CLI N N 0 nodejsnpm/yarn/pnpm/bun N N 0 Custom User-defined rules N N N Total (deduplicated) N N N Compute counts from the actual module JSON files. Do not hardcode counts.
- If the user asks for details on a specific tier or module, show the actual rules.
7d. Add Custom Permissions
When the user asks to add custom permissions (e.g., "allow terraform plan", "block kubectl delete"):
- Read the existing
.claude/settings.json. - Ask the user what rules they want. Accept natural language and translate to permission syntax:
- "allow terraform plan" →
Bash(terraform plan *)inallow - "ask before terraform apply" →
Bash(terraform apply *)inask - "block kubectl delete" →
Bash(kubectl delete *)indeny - "allow the Jira MCP read tools" →
mcp__jira__get_*etc. inallow
- "allow terraform plan" →
- Show a preview with the translated rules:
Custom rules to add:
Tier Rule Allow Bash(terraform plan *)Allow Bash(terraform show *)Ask Bash(terraform apply *)Deny Bash(terraform destroy *)Does this look right?
- On confirmation, add to the appropriate arrays in
.claude/settings.json. - Custom rules are tracked separately — they are NOT associated with any module, so removing a module won't affect them.
7e. Preview Current Settings File
When the user asks to preview the full settings (e.g., "show me the full permissions JSON"):
- Read
.claude/settings.json. - Display the full JSON contents.
- Optionally offer to open it in the user's editor.
Conventions
- Never modify the
main/clone's branch — it anchors all worktrees. Document this in CLAUDE.md. - Worktree names should match branch names when possible for clarity. If the branch has slashes (e.g.,
feature/auth), use a slugified name for the worktree directory (e.g.,feature-auth). - The
sketch/directory is ephemeral — agents can write anything there. It is always gitignored. - The
tasks/directory is for coordination between agents and humans. Files here describe work items, assignments, and status. - The
docs/directory is for durable design documentation that outlives any single task. - Permissions are always project-scoped. All permission configuration goes in the workspace's
.claude/settings.json(project-level), never in~/.claude/settings.json(user-level). Project-level settings are portable, version-controllable, and scoped to the workspace — they don't leak into the user's other projects. If the user asks to set permissions globally, explain the trade-offs (affects all projects, not shareable with collaborators) and confirm before proceeding. If they still want global changes, direct them to edit~/.claude/settings.jsonmanually rather than doing it for them.
Error Handling
- If a
git clonefails, report the error and continue with remaining repos. Mark failed repos in the output. - If a worktree branch already exists locally, use
git worktree add ../worktrees/{name} {branch}without-b. - If a worktree directory already exists, warn the user and skip unless they confirm overwriting.
- If
workspace.yamlalready exists when creating a new workspace, ask before overwriting.