| name | setup-orchestrator |
| description | Skill for installing Claude-Code-Tunnels (Project Orchestrator). Installs the PO into the current project directory, registers workspaces, and connects messenger channels — all in one run. Execute with /claude-code-tunnels:setup-orchestrator. |
Claude-Code-Tunnels Setup
Installs Claude-Code-Tunnels (Project Orchestrator) into the user's project directory.
The PO discovers sub-projects/workspaces and delegates tasks via claude-agent-sdk query(cwd=workspace/).
Plugin Source
This plugin directory contains the orchestrator code and templates.
PLUGIN_DIR = the directory two levels above this SKILL.md (the plugin root).
Included files: orchestrator/, templates/, orchestrator.yaml, install.sh, requirements.txt
Rules
- Never proceed without asking the user — all environment variables and paths must be confirmed by the user
- However, auto-detected values are presented as numbered choices first — the user only needs to enter a number
- Do not modify the original code logic. Only change paths and configuration
- Preserve existing CLAUDE.md content. Append only when necessary
- The ARCHIVE/ directory must never be committed to git
Phase 0: Environment Preflight (CRITICAL — must run first)
The Orchestrator depends on the Python runtime, pip, and the Claude SDK.
Installation paths and versions vary by system, so the current environment must be verified against requirements before installation.
If any check fails → do not proceed to the next step until it is resolved.
0-1. Python Runtime
Why it is needed: the entire orchestrator is written in Python, and claude-agent-sdk requires Python 3.10+.
Auto-detect available Python installations on the system:
candidates=()
for cmd in python3 python python3.12 python3.11 python3.10; do
full=$(command -v "$cmd" 2>/dev/null) || continue
ver=$("$full" -c "import sys; v=sys.version_info; print(f'{v.major}.{v.minor}')" 2>/dev/null) || continue
major=${ver%%.*}; minor=${ver#*.}
if [ "$major" -ge 3 ] && [ "$minor" -ge 10 ]; then
candidates+=("$full ($cmd $ver)")
fi
done
Present the detected results as numbered choices:
Select a Python 3.10+ runtime.
The Orchestrator code and claude-agent-sdk will run using this Python.
[1] /usr/bin/python3 (python3 3.11.5) <- detected
[2] /usr/local/bin/python3.12 (python3.12 3.12.1) <- detected
[3] Enter manually
Number or path:
- User enters
1 or 2 → set that path as PYTHON_CMD
- User enters
3 or a direct path → verify that path's version and use it
- Zero candidates detected → "Could not find Python 3.10+. Please enter the path manually."
0-2. pip
Why it is needed: used to install and verify Python packages such as claude-agent-sdk, aiohttp, and pyyaml.
pip_candidates=()
for cmd in "$PYTHON_CMD -m pip" pip3 pip; do
if $cmd --version &>/dev/null 2>&1; then
pip_candidates+=("$cmd")
fi
done
Select pip. It will be used to install dependency packages.
[1] /usr/bin/python3 -m pip (pip 23.2.1) <- detected
[2] Enter manually
Number or path:
0-3. Claude Code CLI
Why it is needed: claude-agent-sdk internally calls the claude CLI binary. Without it, query() calls will fail.
claude_path=$(command -v claude 2>/dev/null)
0-4. Required Python Packages
Why they are needed: each package serves a distinct role.
claude-agent-sdk: the core library for invoking Claude Code programmatically from Python
aiohttp: used by channel adapters (Telegram polling) and the remote listener to handle async HTTP
pyyaml: parses the orchestrator.yaml configuration file
declare -A pkg_status
for pkg in claude_agent_sdk aiohttp yaml; do
if $PYTHON_CMD -c "import $pkg" 2>/dev/null; then
pkg_status[$pkg]="OK"
else
pkg_status[$pkg]="NOT INSTALLED"
fi
done
If any packages are missing:
The following packages are not installed:
- claude-agent-sdk (Claude SDK — orchestrator cannot run without it)
- aiohttp (async HTTP — channel/remote connections will fail without it)
Install command: $PIP_CMD install claude-agent-sdk aiohttp pyyaml
[1] Install now
[2] Skip (install manually later)
Number:
Preflight Results
Environment Preflight Results
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Python: /usr/bin/python3 (3.11.5) ✓
pip: /usr/bin/python3 -m pip (23.2.1) ✓
Claude CLI: /usr/local/bin/claude (1.0.35) ✓
claude-agent-sdk: 0.3.0 ✓
aiohttp: 3.9.1 ✓
pyyaml: 6.0.1 ✓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
All checks passed. Proceed with setup? (yes/no)
Phase 1: Collect User Input
Now that the environment check is complete, determine the installation location and channels.
Auto-detect possible values and present them as numbered choices. The user only needs to enter a number.
1-1. PROJECT_ROOT
Present the current directory and its parent as candidates:
cwd=$(pwd)
parent=$(dirname "$cwd")
candidates=()
for d in "$cwd" "$parent"; do
subdir_count=$(find "$d" -maxdepth 1 -mindepth 1 -type d ! -name '.*' | wc -l)
if [ "$subdir_count" -ge 1 ]; then
candidates+=("$d (${subdir_count} subdirectories)")
fi
done
Select the project root directory.
Sub-projects/workspaces must reside inside this directory.
[1] /home/user/my-projects (4 subdirectories) <- current location
[2] /home/user (7 subdirectories) <- parent
[3] Enter manually
Number or absolute path:
Validation: test -d && test -w
1-2. ARCHIVE_PATH
Select the credential storage path.
Slack/Telegram tokens and similar secrets will be stored here. (excluded from git)
[1] $PROJECT_ROOT/ARCHIVE <- recommended default
[2] Enter manually
Number or absolute path:
1-3. CHANNELS
Select the messenger channels to connect.
The Orchestrator will receive messages from these channels and execute tasks.
Multiple selections allowed — separate numbers with commas (e.g. 1,3)
[1] slack — Slack Socket Mode (no public IP required)
[2] telegram — Telegram Bot long polling (no public IP required)
[3] Configure later (skip)
Number:
Input Validation (mandatory)
test -d "$PROJECT_ROOT" || echo "ERROR: $PROJECT_ROOT does not exist."
test -w "$PROJECT_ROOT" || echo "ERROR: $PROJECT_ROOT is not writable."
mkdir -p "$ARCHIVE_PATH" 2>/dev/null || echo "ERROR: Failed to create $ARCHIVE_PATH."
If validation fails → re-present choices for that item only. Do not automatically substitute a value.
Phase 2: Copy Orchestrator Code
Show the list of files to be copied and confirm with the user:
PLUGIN_DIR="<plugin root path>"
echo "The following files will be copied to $PROJECT_ROOT:"
echo " orchestrator/ <- Python package (PO, executor, router, channels)"
echo " .claude/rules/ <- delegation, task-log, notification rules"
echo " start-orchestrator.sh <- startup script (uses $PYTHON_CMD)"
echo "Proceed? (yes/no)"
cp -r $PLUGIN_DIR/orchestrator/ $PROJECT_ROOT/orchestrator/
mkdir -p $PROJECT_ROOT/.claude/rules/
cp $PLUGIN_DIR/templates/rules/*.md $PROJECT_ROOT/.claude/rules/
sed "s|python3|$PYTHON_CMD|g" $PLUGIN_DIR/templates/start-orchestrator.sh.template \
> $PROJECT_ROOT/start-orchestrator.sh
chmod +x $PROJECT_ROOT/start-orchestrator.sh
Phase 3: Generate orchestrator.yaml
Generate using the collected user inputs, then display the content and confirm:
root: $PROJECT_ROOT
archive: $ARCHIVE_PATH
channels:
slack:
enabled: true/false
telegram:
enabled: true/false
remote_workspaces: []
Phase 4: CLAUDE.md Configuration
- Does not exist → generate from
$PLUGIN_DIR/templates/CLAUDE.md.template
- Exists but has no Orchestrator mention → append the orchestrator section
- Already contains Orchestrator content → skip
Phase 5: Workspace Discovery
Auto-detect subdirectories and present as a checklist:
ls $PROJECT_ROOT/
The following subdirectories were found.
Select the ones to register as workspaces (separate numbers with commas, or enter all):
[1] project-a/ (CLAUDE.md present)
[2] project-b/ (CLAUDE.md present)
[3] project-c/ (no CLAUDE.md — a default will be generated)
[4] data-scripts/ (no CLAUDE.md — a default will be generated)
Number (e.g. 1,2,3 or all):
Workspaces without a CLAUDE.md will be informed that a default one will be created.
Phase 6: Channel Configuration
Run the corresponding channel skill in sequence based on the selected channels:
- Slack →
/claude-code-tunnels:connect-slack
- Telegram →
/claude-code-tunnels:connect-telegram
Dependency installation (show list to user and confirm):
Packages to install:
Base: claude-agent-sdk aiohttp pyyaml
Slack: slack-bolt slack-sdk
Command: $PIP_CMD install claude-agent-sdk aiohttp pyyaml slack-bolt slack-sdk
[1] Install now
[2] Skip (install manually)
Number:
Phase 7: Test & Complete
cd $PROJECT_ROOT && ./start-orchestrator.sh --fg &
sleep 3
If the test fails → explain the situation to the user with the error message. Do not retry automatically.
Final summary:
Setup Complete!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Project Root: /home/user/my-projects
Archive: /home/user/my-projects/ARCHIVE
Python: /usr/bin/python3 (3.11.5)
Channels: slack ✓, telegram ✗
Workspaces: project-a, project-b, project-c
Files created:
orchestrator/ <- Python package
orchestrator.yaml <- configuration file
start-orchestrator.sh <- startup script
.claude/rules/ <- delegation rules
CLAUDE.md <- PO description
Next steps:
./start-orchestrator.sh <- start in background
./start-orchestrator.sh --fg <- foreground (debug)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Credential File Format
All credential files share the same format:
key : value
Spaces are required on both sides of the colon. Even if bot_token contains a colon, only the first : is used as the split point.
File Structure (after installation)
PROJECT_ROOT/
├── orchestrator/ <- PO, executor, router, channels
│ ├── __init__.py
│ ├── main.py
│ ├── server.py
│ ├── po.py
│ ├── executor.py
│ ├── router.py
│ ├── channel/ <- Slack, Telegram adapters
│ └── remote/ <- listener, deploy helpers
├── orchestrator.yaml <- configuration file
├── start-orchestrator.sh <- startup script
├── CLAUDE.md <- project description for the PO
├── .claude/rules/ <- delegation, task-log, notification rules
├── ARCHIVE/ <- credentials (excluded from git)
├── .tasks/ <- task history logs
├── project-a/ <- workspace
│ └── CLAUDE.md
└── project-b/ <- workspace
└── CLAUDE.md