From mst
Activates Gran Maestro orchestration mode: creates .gran-maestro/ project dir, syncs Chrome extension, copies configs/agents, reads user-profile.json, detects git base branch.
npx claudepluginhub myrtlepn/gran-maestro --plugin mstThis skill uses the workspace's default tool permissions.
Gran Maestro 모드를 활성화합니다. Maestro 오케스트레이션 스킬이 활성화됩니다.
Manages Gran Maestro settings in .gran-maestro/config.json: queries full config or keys, updates values like workflow feedback rounds, discussion limits, server port, concurrency; handles presets, runs resolve script, reads ~/.claude/user-profile.json.
Executes approved Maestro implementation plans using shared session-state contract, coordinating tools like Agent, Bash, task management for complex workflows.
Orchestrates complex tasks by decomposing into DAGs and dispatching focused sub-agents with minimal context. Invoke /orchestra run for multi-step, multi-repo coding workflows.
Share bugs, ideas, or general feedback.
Gran Maestro 모드를 활성화합니다. Maestro 오케스트레이션 스킬이 활성화됩니다.
/autopilot, /ralph, /ultrawork, /team, /pipeline, /ultrapilot, /swarm, /ecomode
(구 오토파일럿/루프 계열 슬래시 스킬 차단 목적. /ralph는 과거 이름으로 유지하며, 현재 mst-loop 재진입은 /mst:resume + scripts/mst-loop.sh로 대체되었습니다.)/mst:request, /mst:list, /mst:inspect, /mst:approve, /mst:accept, /mst:feedback, /mst:cancel, /mst:dashboard, /mst:priority, /mst:history, /mst:settings/mst:codex, /mst:gemini (모드 무관)/analyze, /deepsearch, /code-review, /security-review (모드 무관)/note, /plan, /trace, /doctor (모드 무관)경로 규칙 (MANDATORY): 이 스킬의 모든
.gran-maestro/경로는 절대경로로 사용합니다. 스킬 실행 시작 시PROJECT_ROOT를 취득하고, 이후 모든 경로에{PROJECT_ROOT}/접두사를 붙입니다.PROJECT_ROOT=$(pwd)
{PLUGIN_ROOT}는 이 스킬의 "Base directory"에서skills/{스킬명}/을 제거한 절대경로입니다. 상대경로(.claude/...)는 절대 사용하지 않습니다.
~/.claude/user-profile.json (AskUserQuestion 컨텍스트, 비차단)~/.claude/user-profile.json을 Read한다.
user_profile_context = null로 처리하고 기존 동작을 유지한다 (graceful fallback).role (string)experience_level (string)domain_knowledge (string[])communication_style (string)user_profile_context = null로 처리한다 (워크플로우 차단 금지).AskUserQuestion과 사용자 설명 텍스트 작성 시:
communication_style을 최우선 반영한다.experience_level/domain_knowledge에 맞춰 용어 수준과 설명 깊이를 조절한다.{PROJECT_ROOT}/.gran-maestro/ 디렉토리 생성, .gitignore에 .gran-maestro/ 등록 (미존재 시)
플러그인 루트 경로 확인 (스킬 베이스 디렉토리 2단계 상위) 2.5. Extension 안정 경로 동기화 (비차단):
python3 {PLUGIN_ROOT}/scripts/mst.py extension ensure-copy 실행 (Step 2에서 확인한 PLUGIN_ROOT 사용)updated → 안내 출력: "Extension이 업데이트되었습니다. chrome://extensions 페이지에서 확장 프로그램 새로고침 아이콘을 클릭하세요"created → 안내 출력: "Extension 안정 경로 복사 완료 (~/.gran-maestro/chrome-extension/)"unchanged / skipped → 추가 출력 없음 (silent){PLUGIN_ROOT}/extension/ 미존재 등 에러 종료 포함config.json / agents.json 없으면 templates/defaults/에서 복사
3.5. base_branch 설정 마법사:
현재 git 브랜치 감지:
CURRENT_BRANCH=$(git -C "{PROJECT_ROOT}" branch --show-current 2>/dev/null)
# git 저장소가 아니거나 빈 문자열이면 "main" 폴백
[ -z "$CURRENT_BRANCH" ] && CURRENT_BRANCH="main"
기존 base_branch 값 읽기:
SAVED_BRANCH=$(python3 -c "
import json
try:
d = json.load(open('{PROJECT_ROOT}/.gran-maestro/config.json'))
v = d.get('worktree', {}).get('base_branch', '')
print(v)
except: print('')
" 2>/dev/null || echo "")
skip 조건: SAVED_BRANCH가 비어있지 않고 SAVED_BRANCH != "main" 이면:
→ "✓ base_branch: {SAVED_BRANCH} (기존 설정 유지)" 출력 후 Step 3.55로 진행.
ℹ️
"main"은 templates/defaults/config.json의 기본값이므로 "미설정"과 동일하게 취급한다. Step 3에서 config.json이 처음 복사된 경우에도 SAVED_BRANCH는"main"이 되어 질문 조건에 진입한다.
질문 조건 (SAVED_BRANCH 비어있거나 SAVED_BRANCH == "main" 인 경우):
CURRENT_BRANCH 옵션 (권장): label = "{CURRENT_BRANCH} (현재 브랜치, 권장)", value = {CURRENT_BRANCH}"main" — CURRENT_BRANCH != "main"인 경우에만 포함"master" — CURRENT_BRANCH != "master"인 경우에만 포함
(Other 텍스트 입력 항상 허용)"워크트리를 어느 브랜치에서 분기할까요? (감지된 현재 브랜치: {CURRENT_BRANCH})"BASE_BRANCH_VALUE로 저장:
{CURRENT_BRANCH}, "main", "master" 중 택일)config.json에 반영 (임시파일 + rename 패턴으로 원자적 쓰기):
python3 - << EOF
import json, os, tempfile
path = "{PROJECT_ROOT}/.gran-maestro/config.json"
try:
d = json.load(open(path))
except:
d = {}
d.setdefault("worktree", {})["base_branch"] = "{BASE_BRANCH_VALUE}"
tmp = path + ".tmp"
with open(tmp, "w") as f:
json.dump(d, f, indent=2, ensure_ascii=False)
os.replace(tmp, path)
EOF
완료 메시지: "✓ base_branch: {BASE_BRANCH_VALUE}"
3.55. protected_branches 설정 마법사:
기본값은 ["main", "master", "release/*"]이다.
현재 worktree.protected_branches 값 읽기 및 표시:
CURRENT_PROTECTED_BRANCHES_JSON=$(python3 - << EOF
import json
default = ["main", "master", "release/*"]
try:
d = json.load(open('{PROJECT_ROOT}/.gran-maestro/config.json'))
v = d.get("worktree", {}).get("protected_branches", default)
if not (isinstance(v, list) and all(isinstance(item, str) for item in v)):
v = default
except Exception:
v = default
print(json.dumps(v, ensure_ascii=False))
EOF
)
echo "현재 protected_branches: ${CURRENT_PROTECTED_BRANCHES_JSON}"
사용자에게 현재 값을 그대로 유지하거나 편집할지 묻는다.
PROTECTED_BRANCHES_JSON=${CURRENT_PROTECTED_BRANCHES_JSON}로 두고 config.json을 변경하지 않고 다음 단계로 진행한다.main,master,release/*) 또는 JSON 배열 문자열(["main", "master", "release/*"]) 둘 다 허용한다.PROTECTED_BRANCHES_JSON은 파싱 결과를 json.dumps(value, ensure_ascii=False)로 직렬화한 JSON 배열 문자열이다.편집 입력 파싱 규칙:
import json
default = ["main", "master", "release/*"]
def parse_protected_branches(raw):
raw = raw.strip()
if not raw:
return None
if raw.startswith("["):
parsed = json.loads(raw)
else:
parsed = [item.strip() for item in raw.split(",")]
if not isinstance(parsed, list):
raise ValueError("protected_branches must be a list")
parsed = [item.strip() for item in parsed if isinstance(item, str) and item.strip()]
if not parsed:
raise ValueError("protected_branches must include at least one branch pattern")
return parsed
protected_branches_value = default로 기본값 복구 후 저장한다.편집 또는 3회 실패 기본값 복구 시 config.json에 반영 (임시파일 + rename 패턴으로 원자적 쓰기):
python3 - << EOF
import json, os
path = "{PROJECT_ROOT}/.gran-maestro/config.json"
protected_branches_value = {PROTECTED_BRANCHES_JSON}
try:
d = json.load(open(path))
except Exception:
d = {}
d.setdefault("worktree", {})["protected_branches"] = protected_branches_value
tmp = path + ".tmp"
with open(tmp, "w") as f:
json.dump(d, f, indent=2, ensure_ascii=False)
os.replace(tmp, path)
EOF
완료 메시지: "✓ protected_branches: {PROTECTED_BRANCHES_JSON}"
3.6. MANDATORY (config 변경 후처리): Step 3/3.5/3.55에서 config.json이 생성/수정된 직후 아래 명령을 실행한다.
python3 {PLUGIN_ROOT}/scripts/mst.py config resolve || echo "[warning] config.resolved.json 갱신 실패. 수동으로 'python3 scripts/mst.py config resolve'를 실행하세요." >&2
{PROJECT_ROOT}/.gran-maestro/mode.json 작성 (always overwrite):
⏱️ 타임스탬프 취득 (MANDATORY):
TS=$(python3 {PLUGIN_ROOT}/scripts/mst.py timestamp now)위 명령 실패 시 폴백:python3 -c "from datetime import datetime, timezone; print(datetime.now(timezone.utc).isoformat())"출력값을activated_at필드에 기입한다. 날짜만 기입 금지.
{
"active": true,
"activated_at": "{TS — mst.py timestamp now 출력값}",
"auto_deactivate": true,
}
requests/, worktrees/ 디렉토리 생성
워크플로우 Hook 및 스크립트 설치 (MANDATORY):
6a. Hook 파일 복사: {PLUGIN_ROOT}/hooks/ → {PROJECT_ROOT}/.claude/hooks/
{PLUGIN_ROOT}/hooks/ (플러그인 소유 원본)mst-stop-hook.sh (Stop hook — mst-loop 스타일 re-feed로 워크플로우 연속 실행 보장)mst-session-init.sh (SessionStart hook — 세션 초기화 + 버전 게이트)mst-pre-tool-use.sh (PreToolUse hook — worktree 경계 진입 가드){PROJECT_ROOT}/.claude/hooks/ 디렉토리가 없으면 생성chmod +x)# 레거시 4파일 구조 → 3파일 구조 마이그레이션
rm -f "{PROJECT_ROOT}/.claude/hooks/mst-continuation-guard.sh"
rm -f "{PROJECT_ROOT}/.claude/hooks/mst-skill-push.sh"
rm -f "{PROJECT_ROOT}/.claude/hooks/mst-skill-pop.sh"
mkdir -p "{PROJECT_ROOT}/.claude/hooks"
for f in mst-stop-hook.sh mst-session-init.sh mst-pre-tool-use.sh; do
cp "{PLUGIN_ROOT}/hooks/$f" "{PROJECT_ROOT}/.claude/hooks/$f"
chmod +x "{PROJECT_ROOT}/.claude/hooks/$f"
done
# 플러그인 버전을 hook 버전 마커에 기록 (버전 게이트가 비교에 사용)
python3 -c "import json; print(json.load(open('{PLUGIN_ROOT}/.claude-plugin/plugin.json'))['version'])" \
> "{PROJECT_ROOT}/.claude/hooks/.mst-hook-version"
6b. Hook 등록: {PROJECT_ROOT}/.claude/settings.local.json에 hook 이벤트 바인딩 등록
{
"hooks": {
"SessionStart": [
{ "matcher": "", "hooks": [{ "type": "command", "command": "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.claude/hooks/mst-session-init.sh" }] }
],
"Stop": [
{ "matcher": "", "hooks": [{ "type": "command", "command": "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.claude/hooks/mst-stop-hook.sh" }] }
],
"PreToolUse": [
{ "matcher": "Skill", "hooks": [{ "type": "command", "command": "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.claude/hooks/mst-pre-tool-use.sh" }] }
]
}
}
settings.local.json의 다른 필드(env, permissions 등)를 보존한 상태로 병합command가 이미 등록되어 있으면 건너뜀 (중복 방지)PostToolUse 이벤트와 mst-continuation-guard.sh 참조를 제거settings.local.json 파일이 없으면 새로 생성python3로 수행:
python3 - << 'HOOKEOF'
import json, os
settings_path = "{PROJECT_ROOT}/.claude/settings.local.json"
try:
with open(settings_path, "r", encoding="utf-8") as f:
settings = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
settings = {}
if not isinstance(settings, dict):
settings = {}
hooks = settings.setdefault("hooks", {})
prefix = '$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.claude/hooks'
# 레거시 hook 참조 정리 (4파일 → 3파일 마이그레이션)
legacy_events = ["PostToolUse"]
for event in legacy_events:
hooks.pop(event, None)
# 레거시 hook 참조 정리 (mst-continuation-guard.sh → mst-stop-hook.sh / mst-pre-tool-use.sh)
for event, entries in list(hooks.items()):
if isinstance(entries, list):
hooks[event] = [
e for e in entries
if not (isinstance(e, dict) and any(
isinstance(h, dict) and "mst-continuation-guard.sh" in h.get("command", "")
for h in (e.get("hooks") or [])
))
]
# 새 hook 등록
hook_map = {
"SessionStart": {"matcher": "", "file": "mst-session-init.sh"},
"Stop": {"matcher": "", "file": "mst-stop-hook.sh"},
"PreToolUse": {"matcher": "Skill", "file": "mst-pre-tool-use.sh"},
}
for event, cfg in hook_map.items():
cmd = f"{prefix}/{cfg['file']}"
entries = hooks.setdefault(event, [])
already = any(
isinstance(e, dict) and any(
isinstance(h, dict) and h.get("command", "").endswith(cfg["file"])
for h in (e.get("hooks") or [])
)
for e in entries
)
if not already:
entries.append({
"matcher": cfg["matcher"],
"hooks": [{"type": "command", "command": cmd}]
})
tmp = settings_path + ".tmp"
with open(tmp, "w", encoding="utf-8") as f:
json.dump(settings, f, indent=2, ensure_ascii=False)
f.write("\n")
os.replace(tmp, settings_path)
HOOKEOF
"✓ 워크플로우 Hook 3개 설치 완료 (레거시 hook 정리됨)"6c. 버전 알림 스크립트 설치:
check-version.sh를 ~/.claude/scripts/에 복사; settings.json의 hooks.UserPromptSubmit에 아래 hook 추가(미존재 시):
{ "type": "command", "command": "~/.claude/scripts/check-version.sh" }
동일 command가 이미 등록되어 있으면 건너뜁니다.
hooks.UserPromptSubmit 배열은 기존 항목을 보존한 상태로 병합해야 합니다.
설정 파일 파싱은 python3 또는 jq로 수행할 수 있으며, 동일 command가 이미 존재하면 추가하지 마세요.사용자에게 모드 전환 알림 출력
Gran Maestro 모드 활성화
역할 전환: Claude Code → PM (지휘자)
- 코드 작성: 금지 (Codex/Gemini에 위임)
- 분석/스펙/리뷰: 활성
Maestro 오케스트레이션 스킬이 활성화되었습니다.
/mst:request 로 새 요청을 시작하세요.
maestro-status.sh (macOS/Linux) 또는 maestro-status.py (Windows) 함께 설치:
~/.claude/scripts/maestro-status.sh # "on (requests: 2)" 또는 "off"
~/.claude/scripts/maestro-status.sh --json # JSON 전체 출력
~/.claude/scripts/maestro-status.sh -q # exit code만 (스크립팅용)
~/.claude/scripts/maestro-status.sh --field active
mode.json의 active: true 확인; 추가 작업 불필요