feat: add multi-runtime support (coord run, prdy --codex) and next-task capsule
- coord/prdy subcommands now accept --claude/--codex runtime flags - New `mosaic coord run` generates continuation context and launches selected runtime, replacing manual copy/paste workflow - Next-task capsule (.mosaic/orchestrator/next-task.json) provides machine-readable execution context for deterministic session launches - Codex strict orchestrator profile added to runtime/codex/RUNTIME.md - Orchestrator protocol updated with between-session run flow - New smoke-test.sh for orchestration behavior verification Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,7 @@ MOSAIC_HOME="${MOSAIC_HOME:-$HOME/.config/mosaic}"
|
||||
ORCH_SUBDIR=".mosaic/orchestrator"
|
||||
MISSION_FILE="mission.json"
|
||||
SESSION_LOCK_FILE="session.lock"
|
||||
NEXT_TASK_FILE="next-task.json"
|
||||
MANIFEST_FILE="docs/MISSION-MANIFEST.md"
|
||||
TASKS_MD="docs/TASKS.md"
|
||||
SCRATCHPAD_DIR="docs/scratchpads"
|
||||
@@ -42,6 +43,30 @@ _require_jq() {
|
||||
fi
|
||||
}
|
||||
|
||||
coord_runtime() {
|
||||
local runtime="${MOSAIC_COORD_RUNTIME:-claude}"
|
||||
case "$runtime" in
|
||||
claude|codex) echo "$runtime" ;;
|
||||
*) echo "claude" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
coord_launch_command() {
|
||||
local runtime
|
||||
runtime="$(coord_runtime)"
|
||||
echo "mosaic $runtime"
|
||||
}
|
||||
|
||||
coord_run_command() {
|
||||
local runtime
|
||||
runtime="$(coord_runtime)"
|
||||
if [[ "$runtime" == "claude" ]]; then
|
||||
echo "mosaic coord run"
|
||||
else
|
||||
echo "mosaic coord run --$runtime"
|
||||
fi
|
||||
}
|
||||
|
||||
# ─── Project / state file access ────────────────────────────────────────────
|
||||
|
||||
# Return the orchestrator directory for a project
|
||||
@@ -56,6 +81,11 @@ mission_path() {
|
||||
echo "$(orch_dir "$project")/$MISSION_FILE"
|
||||
}
|
||||
|
||||
next_task_capsule_path() {
|
||||
local project="${1:-.}"
|
||||
echo "$(orch_dir "$project")/$NEXT_TASK_FILE"
|
||||
}
|
||||
|
||||
# Exit with error if mission.json is missing or inactive
|
||||
require_mission() {
|
||||
local project="${1:-.}"
|
||||
@@ -358,6 +388,113 @@ milestone_name() {
|
||||
jq -r --arg id "$mid" '.milestones[] | select(.id == $id) | .name // empty' "$mp"
|
||||
}
|
||||
|
||||
# ─── Next-task capsule helpers ───────────────────────────────────────────────
|
||||
|
||||
write_next_task_capsule() {
|
||||
local project="${1:-.}"
|
||||
local runtime="${2:-claude}"
|
||||
local mission_id="${3:-}"
|
||||
local mission_name="${4:-}"
|
||||
local project_path="${5:-}"
|
||||
local quality_gates="${6:-}"
|
||||
local current_ms_id="${7:-}"
|
||||
local current_ms_name="${8:-}"
|
||||
local next_task="${9:-}"
|
||||
local tasks_done="${10:-0}"
|
||||
local tasks_total="${11:-0}"
|
||||
local pct="${12:-0}"
|
||||
local current_branch="${13:-}"
|
||||
|
||||
_require_jq || return 1
|
||||
mkdir -p "$(orch_dir "$project")"
|
||||
|
||||
local payload
|
||||
payload="$(jq -n \
|
||||
--arg generated_at "$(iso_now)" \
|
||||
--arg runtime "$runtime" \
|
||||
--arg mission_id "$mission_id" \
|
||||
--arg mission_name "$mission_name" \
|
||||
--arg project_path "$project_path" \
|
||||
--arg quality_gates "$quality_gates" \
|
||||
--arg current_ms_id "$current_ms_id" \
|
||||
--arg current_ms_name "$current_ms_name" \
|
||||
--arg next_task "$next_task" \
|
||||
--arg current_branch "$current_branch" \
|
||||
--arg tasks_done "$tasks_done" \
|
||||
--arg tasks_total "$tasks_total" \
|
||||
--arg pct "$pct" \
|
||||
'{
|
||||
generated_at: $generated_at,
|
||||
runtime: $runtime,
|
||||
mission_id: $mission_id,
|
||||
mission_name: $mission_name,
|
||||
project_path: $project_path,
|
||||
quality_gates: $quality_gates,
|
||||
current_milestone: {
|
||||
id: $current_ms_id,
|
||||
name: $current_ms_name
|
||||
},
|
||||
next_task: $next_task,
|
||||
progress: {
|
||||
tasks_done: ($tasks_done | tonumber),
|
||||
tasks_total: ($tasks_total | tonumber),
|
||||
pct: ($pct | tonumber)
|
||||
},
|
||||
current_branch: $current_branch
|
||||
}')"
|
||||
|
||||
write_json "$(next_task_capsule_path "$project")" "$payload"
|
||||
}
|
||||
|
||||
build_codex_strict_kickoff() {
|
||||
local project="${1:-.}"
|
||||
local continuation_prompt="${2:-}"
|
||||
|
||||
_require_jq || return 1
|
||||
|
||||
local capsule_path
|
||||
capsule_path="$(next_task_capsule_path "$project")"
|
||||
local capsule='{}'
|
||||
if [[ -f "$capsule_path" ]]; then
|
||||
capsule="$(cat "$capsule_path")"
|
||||
fi
|
||||
|
||||
local mission_id next_task project_path quality_gates
|
||||
mission_id="$(echo "$capsule" | jq -r '.mission_id // "unknown"')"
|
||||
next_task="$(echo "$capsule" | jq -r '.next_task // "none"')"
|
||||
project_path="$(echo "$capsule" | jq -r '.project_path // "."')"
|
||||
quality_gates="$(echo "$capsule" | jq -r '.quality_gates // "none"')"
|
||||
|
||||
cat <<EOF
|
||||
Now initiating Orchestrator mode...
|
||||
|
||||
STRICT EXECUTION PROFILE FOR CODEX (HARD GATE)
|
||||
- Do NOT ask clarifying questions before your first tool actions unless a Mosaic escalation trigger is hit.
|
||||
- Your first actions must be reading mission state files in order.
|
||||
- Treat the next-task capsule as authoritative execution input.
|
||||
|
||||
REQUIRED FIRST ACTIONS (IN ORDER)
|
||||
1. Read ~/.config/mosaic/guides/ORCHESTRATOR-PROTOCOL.md
|
||||
2. Read docs/MISSION-MANIFEST.md
|
||||
3. Read docs/scratchpads/${mission_id}.md
|
||||
4. Read docs/TASKS.md
|
||||
5. Begin execution on next task: ${next_task}
|
||||
|
||||
WORKING CONTEXT
|
||||
- Project: ${project_path}
|
||||
- Quality gates: ${quality_gates}
|
||||
- Capsule file: .mosaic/orchestrator/next-task.json
|
||||
|
||||
Task capsule (JSON):
|
||||
\`\`\`json
|
||||
${capsule}
|
||||
\`\`\`
|
||||
|
||||
Continuation prompt:
|
||||
${continuation_prompt}
|
||||
EOF
|
||||
}
|
||||
|
||||
# Get next milestone after the given one
|
||||
next_milestone_id() {
|
||||
local project="${1:-.}"
|
||||
|
||||
Reference in New Issue
Block a user