From dx-hub
Initialize a hub directory for multi-repo orchestration. Discovers sibling repos, merges configs, validates CLI compatibility. Use when setting up hub mode for the first time. Trigger on "init hub", "set up hub", "multi-repo setup".
npx claudepluginhub easingthemes/dx-aem-flow --plugin dx-hubThis skill is limited to using the following tools:
You set up a `.hub/` directory that orchestrates work across multiple repos via dx-core hub mode.
Initializes Harness projects with CLAUDE.md, Plans.md, .claude/settings.json, hooks, and agent configs. Supports Node.js/Python/Go/Rust detection; subcommands for CI/CD, Codex CLI, memory, mirrors, agents.
Initializes or updates multi-repo workspaces from dev-config-template by collecting project info, filling CLAUDE.md placeholders, cloning sub-repos, configuring dev environments, and syncing template files.
Interactive wizard configures repositories for Claude Code best practices by creating CLAUDE.md, slash commands, agents, hooks, and permissions. Activates on 'setup claude', 'init claude', or repo setup requests.
Share bugs, ideas, or general feedback.
You set up a .hub/ directory that orchestrates work across multiple repos via dx-core hub mode.
digraph hub_init {
"Validate CLI" [shape=box];
"CLI compatible?" [shape=diamond];
"STOP: CLI incompatible" [shape=doublecircle];
"Determine hub path" [shape=box];
"Hub already exists?" [shape=diamond];
"Confirm reinit" [shape=diamond];
"STOP: User cancelled" [shape=doublecircle];
"Discover repos" [shape=box];
"Present repos" [shape=box];
"User selects repos" [shape=diamond];
"Build config" [shape=box];
"Create hub structure" [shape=box];
"Configure Claude Code settings" [shape=box];
"Generate CLAUDE.md" [shape=box];
"Offer workspace file" [shape=diamond];
"Create .code-workspace" [shape=box];
"Summary" [shape=doublecircle];
"Validate CLI" -> "CLI compatible?";
"CLI compatible?" -> "Determine hub path" [label="yes"];
"CLI compatible?" -> "STOP: CLI incompatible" [label="no"];
"Determine hub path" -> "Hub already exists?";
"Hub already exists?" -> "Confirm reinit" [label="yes"];
"Hub already exists?" -> "Discover repos" [label="no"];
"Confirm reinit" -> "Discover repos" [label="yes, reinit"];
"Confirm reinit" -> "STOP: User cancelled" [label="no"];
"Discover repos" -> "Present repos";
"Present repos" -> "User selects repos";
"User selects repos" -> "Build config" [label="confirmed"];
"User selects repos" -> "STOP: User cancelled" [label="none selected"];
"Build config" -> "Create hub structure";
"Create hub structure" -> "Configure Claude Code settings";
"Configure Claude Code settings" -> "Generate CLAUDE.md";
"Generate CLAUDE.md" -> "Offer workspace file";
"Offer workspace file" -> "Create .code-workspace" [label="yes"];
"Offer workspace file" -> "Summary" [label="no"];
"Create .code-workspace" -> "Summary";
}
Run:
claude --version
claude -p --help 2>&1 | grep -q 'output-format'
Both must succeed. If claude --version fails, the CLI is not installed. If output-format is absent, the CLI version is too old to support hub dispatch (requires --output-format flag for machine-readable output).
Fail with clear message:
ERROR: Hub mode requires Claude Code CLI with --output-format support.
- Install: https://docs.anthropic.com/en/docs/claude-code
- Minimum version: one that supports `claude -p --output-format`
Print the error message from "Validate CLI". STOP.
If the user provided an argument, use it as the hub path. Otherwise default to ../.hub relative to the current working directory.
Resolve to an absolute path for all subsequent operations:
HUB_PATH=$(realpath "${ARGUMENT:-../.hub}")
Print: Hub path: $HUB_PATH
Check if $HUB_PATH/.ai/config.yaml exists.
Print:
Hub already exists at $HUB_PATH
Reinitializing will overwrite config.yaml and CLAUDE.md (state/ and existing specs are preserved).
Continue? [y/N]
Wait for user input.
Print: Hub init cancelled. Existing hub at $HUB_PATH is unchanged. STOP.
Scan sibling directories (parent of $HUB_PATH) for repos that contain .ai/config.yaml with a scm: key.
Strategy 1 — filesystem scan:
PARENT=$(dirname "$HUB_PATH")
for dir in "$PARENT"/*/; do
cfg="$dir/.ai/config.yaml"
if [ -f "$cfg" ] && grep -q '^scm:' "$cfg"; then
echo "$dir"
fi
done
For each candidate, read .ai/config.yaml and extract:
name — the directory name (basename)scm.project — ADO project name (may be absent)scm.base-branch — default branch (may be absent, fallback main)Strategy 2 — fallback (no siblings found): If no siblings are discovered, ask the user:
No repos with dx config found in <parent>.
Enter repo paths manually (absolute or relative to hub, comma-separated), or press Enter to abort:
Parse the paths and load their configs the same way.
Exclude the hub directory itself from the list.
Display discovered repos as a numbered checklist:
Discovered repos with dx config:
[1] repo-alpha (branch: develop, project: MyProject)
[2] repo-beta (branch: main, project: MyProject)
[3] repo-gamma (branch: main, project: OtherProject)
Select repos to include in hub (e.g. 1,2 or all):
Wait for user input.
0 → go to "STOP: User cancelled"Accept all to include every discovered repo.
Merge selected repos into a hub config.yaml:
hub:
enabled: true
terminal-delay: 5
state-ttl: 7d
repos:
- name: <dir-name>
path: ../<dir-name>
base-branch: <scm.base-branch from repo config, default: main>
capabilities: [<fe|be — infer from repo name or ask user>]
ado-project: <scm.project from repo config, omit if absent>
The capabilities field is used by /dx-hub-dispatch to auto-detect which repos a ticket needs. Common values: fe (frontend), be (backend). If unsure, ask the user during repo selection. A repo can have multiple capabilities: [fe, be].
One entry per selected repo. Paths are relative to the hub directory. No hardcoded org URLs, project names, or credentials.
Create the hub directory layout:
mkdir -p "$HUB_PATH/.ai/specs"
mkdir -p "$HUB_PATH/.ai/rules"
mkdir -p "$HUB_PATH/.claude/rules"
mkdir -p "$HUB_PATH/state"
Write $HUB_PATH/.ai/config.yaml with the content built in "Build config".
Write $HUB_PATH/.gitignore:
state/
.ai/specs/
Install hub rules:
Copy rule templates from the dx-hub plugin's templates/rules/ directory to $HUB_PATH/.claude/rules/:
for tpl in ${CLAUDE_PLUGIN_DIR}/templates/rules/*.md.template; do
dest="$HUB_PATH/.claude/rules/$(basename "$tpl" .template)"
if [ ! -f "$dest" ]; then
cp "$tpl" "$dest"
fi
done
Strip the .template suffix. Do not overwrite existing files (user may have customized them).
Report: "Installed hub rules: "
The hub directory needs Claude Code settings so that plugins and MCP servers are available when the user opens the hub in Claude Code. Read these from the first selected sibling repo — its .claude/settings.json was created by /dx-init.
Step 1 — Read sibling settings:
Pick the first selected repo. Read <repo-path>/.claude/settings.json. Extract:
extraKnownMarketplaces — the marketplace source(s)enabledPlugins — which plugins are enabledenabledMcpjsonServers — which MCP servers are enabled (if present)If the first repo has no .claude/settings.json, try the next selected repo. If none have it, warn:
WARNING: No sibling repo has .claude/settings.json — plugins won't be available in the hub.
Run /dx-init in at least one repo first, then re-run /dx-hub-init.
Skip this step (do not create settings files) and continue to "Generate CLAUDE.md".
Step 2 — Write .claude/settings.json:
Check if $HUB_PATH/.claude/settings.json already exists.
Write/merge the following structure:
{
"plansDirectory": ".ai/specs",
"env": {
"COPILOT_CUSTOM_INSTRUCTIONS_DIRS": ".claude/rules"
},
"attribution": {
"commit": "",
"pr": ""
},
"enabledMcpjsonServers": <copied from sibling, or ["ado"] as minimum>,
"enabledPlugins": <copied from sibling>,
"extraKnownMarketplaces": <copied from sibling>
}
Do NOT copy permissions from the sibling — the hub is an orchestrator directory, not a code repo. Let the user build up permissions naturally through Claude Code prompts.
Step 3 — Write .claude/settings.local.json:
Check if $HUB_PATH/.claude/settings.local.json already exists.
.claude/settings.local.json. If yes, copy its env block (secrets like AEM_INSTANCES, API keys). If no, create a minimal placeholder:{
"env": {}
}
Report: "Created .claude/settings.local.json — add credentials if needed for hub dispatch."
Step 4 — Create .mcp.json:
The hub needs project-level MCP servers so the user can read tickets, check PRs, and query docs directly from the hub directory. Read the sibling repo's .mcp.json and copy relevant servers.
<repo-path>/.mcp.json.mcpServers object. The hub is an orchestration directory — it benefits from having all the same MCP servers (ADO for tickets/PRs, context7 for docs, Atlassian if configured)..mcp.json: Warn and skip:
WARNING: No sibling repo has .mcp.json — MCP tools (ADO, etc.) won't be available in the hub.
Run /dx-init in at least one repo first, then re-run /dx-hub-init.
If $HUB_PATH/.mcp.json already exists on reinit: Read it and merge — add missing server entries but do not overwrite existing ones (user may have customized args, added servers).
Step 5 — Add vscode-automator MCP server:
The hub's dispatch mechanism uses the vscode-automator MCP server to open VS Code terminals. Add it to the merged MCP config:
{
"vscode-automator": {
"command": "node",
"args": ["<path-to-dx-aem-flow>/tools/vscode-automator/server.mjs"],
"type": "stdio"
}
}
Resolve <path-to-dx-aem-flow> from the plugin's installed location. If the plugin is installed via marketplace, the path is relative to the marketplace cache. If you cannot resolve the absolute path, use a relative path from the hub directory to the tools/vscode-automator/server.mjs file.
Write $HUB_PATH/.mcp.json:
{
"mcpServers": <merged mcpServers from sibling + vscode-automator>
}
Report: "Created .mcp.json — MCP servers: + vscode-automator"
Write $HUB_PATH/CLAUDE.md:
# Hub — Multi-Repo Orchestrator
This is a hub directory — it contains no code. It orchestrates work
across multiple repos via dx-core hub mode.
## Repos
<!-- populated by dx-hub-init, do not edit manually -->
<list of repo names and paths from config>
## Commands
No build commands. This directory dispatches to repos.
## MCP Servers
ADO MCP is configured — use `mcp__ado__wit_get_work_item` and
`mcp__ado__wit_get_work_items_batch_by_ids` to read tickets directly.
## Specs & Progress
Check sibling repos for dx workflow output:
- Specs live in `<repo-path>/.ai/specs/<ticket-id>-<slug>/`
- See `.claude/rules/hub-orchestration.md` for the full spec directory convention
## Rules
- Never edit code files from this directory
- Use /dx-hub-status to check in-flight work
- Dispatch happens via hub-enabled dx-core skills
- Config lives in `.ai/config.yaml` — edit it to add/remove repos
- See `.claude/rules/` for detailed hub behavior rules
Replace the <list of repo names and paths from config> placeholder with the actual repo list formatted as:
- **repo-alpha** → `../repo-alpha` (branch: develop)
- **repo-beta** → `../repo-beta` (branch: main)
Ask:
Create a VS Code workspace file at $HUB_PATH/hub.code-workspace?
This lets you open all repos side-by-side in VS Code. [y/N]
Write $HUB_PATH/hub.code-workspace:
{
"folders": [
{ "name": "hub", "path": "." },
{ "name": "<repo-name>", "path": "../<repo-name>" }
],
"settings": {}
}
One folder entry per selected repo, plus the hub itself as the first entry. Use the repo directory name as the name field.
Print:
## Hub Initialized
**Location:** $HUB_PATH
**Repos:** <N> repos configured
**Terminal delay:** 5s (configurable via hub.terminal-delay)
**Workspace file:** <created at hub.code-workspace | not created>
### Files created:
- `.ai/config.yaml` — hub config with repo registry
- `.claude/settings.json` — marketplace, plugins, MCP servers (from sibling repo)
- `.claude/settings.local.json` — local env vars / secrets placeholder
- `.claude/rules/` — hub convention rules
- `.mcp.json` — MCP servers (ADO, context7, etc. from sibling repo)
- `CLAUDE.md` — hub instructions for Claude
- `state/` — runtime dispatch state (gitignored)
- `.gitignore` — ignores state and specs
### Plugins:
- **Marketplace:** <marketplace name from sibling>
- **Enabled:** <list of enabled plugins>
- **MCP servers:** <list of enabled MCP servers>
### Next steps:
- Open $HUB_PATH in Claude Code to use hub mode
- Run `/dx-hub-status` to verify connectivity
- Run `/dx-hub-dispatch` with a ticket ID to start coordinated work
/dx-hub-init
Scans .. for sibling repos with dx config, prompts for selection, creates ../.hub/ with merged config, CLAUDE.md, and state directory.
/dx-hub-init /workspace/my-hub
Same as above but creates the hub at the specified absolute path.
/dx-hub-init
If ../.hub/.ai/config.yaml already exists, prompts for confirmation before overwriting config and CLAUDE.md. State and existing specs are preserved.
Cause: claude --version failed or --output-format flag is not available in the installed CLI version.
Fix: Update Claude Code CLI to the latest version. Hub dispatch relies on claude -p --output-format json for machine-readable subagent output.
Cause: Sibling directories either have no .ai/config.yaml, or their config does not contain a scm: key.
Fix: Run /dx-init in each repo first to generate the config. Then re-run /dx-hub-init. Alternatively, enter paths manually when prompted.
Cause: Re-running init overwrites the full repo list.
Fix: Edit .ai/config.yaml directly to append a new entry under repos:. Follow the existing format (name, path, base-branch, ado-project).
Cause: No sibling repo had .claude/settings.json when hub-init ran, so marketplace and plugin settings were not copied.
Fix: Run /dx-init in at least one sibling repo first, then re-run /dx-hub-init. The init reads extraKnownMarketplaces and enabledPlugins from the first sibling's .claude/settings.json.
Cause: Relative paths in hub.code-workspace are resolved from the hub directory. If repos moved, paths break.
Fix: Edit hub.code-workspace to update the path values, or re-run /dx-hub-init to regenerate it.
.ai/config.yaml in each repohub/config.yaml are always relative to the hub directory (e.g., ../repo-name)state/ and .ai/specs/ are never deleted during reinit