#!/usr/bin/env bash # setup-rceo-stack.sh — per-account PMO/Work stack spawner for the # reachableceo stack on ULTIX-STREAMING. ROOT-run, idempotent, PROTOCOL v2 # (headless dispatch, founder gate, doorbell-only stuff). # # Coordinate files are generated ONCE and never overwritten afterwards # (they are founder/agent-owned); a file still carrying __TEMPLATE__ # placeholders is debris from a failed run and gets regenerated. # # Usage: setup-rceo-stack.sh [PREFIX] # PREFIX defaults to USER. Screens: -PMO / -Work. set -euo pipefail USR="${1:?usage: setup-rceo-stack.sh [PREFIX]}" FOUNDER_ACCT="${2:?founder account for screen acl}" SRC_CRUSH="${3:?source dir with crush.json/providers.json}" PREFIX="${4:-$USR}" CWD="/home/${USR}" HOME_U="$CWD" PMO_SCREEN="${PREFIX}-PMO" WORKSCREEN="${PREFIX}-Work" id "$USR" >/dev/null 2>&1 || { echo "no such user: $USR"; exit 1; } if ! id -nG "$USR" | tr ' ' '\n' | grep -qx docker; then usermod -aG docker "$USR" echo "groups: added docker" fi rc="$HOME_U/.screenrc" [[ -f "$rc" ]] && cp -a "$rc" "${rc}.bak-$(date +%Y%m%d-%H%M%S)" touch "$rc" grep -q '^multiuser on' "$rc" || printf 'multiuser on\n' >> "$rc" grep -q "^acladd ${FOUNDER_ACCT}" "$rc" || printf 'acladd %s\n' "$FOUNDER_ACCT" >> "$rc" grep -q '^defscrollback 10000' "$rc" || printf 'defscrollback 10000\n' >> "$rc" chown "${USR}:${USR}" "$rc" chmod 644 "$rc" echo "screenrc: merged, never overwritten (backup kept if pre-existing)" DST_CRUSH="$HOME_U/.local/share/crush" mkdir -p "$DST_CRUSH" for f in crush.json providers.json; do if [[ ! -f "$DST_CRUSH/$f" && -f "$SRC_CRUSH/$f" ]]; then cp "$SRC_CRUSH/$f" "$DST_CRUSH/$f" chown "${USR}:${USR}" "$DST_CRUSH/$f" chmod 600 "$DST_CRUSH/$f" echo "crush: copied $f" fi done CC="$HOME_U/.coordinate" mkdir -p "$CC"/{inbox-work,inbox-pmo,archive,prompts,logs} fresh() { [[ ! -f "$1" ]] || grep -qE '__(USR|PREFIX|WORKSCREEN|FOUNDER|DATE)__' "$1" } sub() { sed -i -e "s/__USR__/${USR}/g" -e "s/__PREFIX__/${PREFIX}/g" \ -e "s/__WORKSCREEN__/${WORKSCREEN}/g" \ -e "s/__FOUNDER__/${FOUNDER_ACCT}/g" \ -e "s/__DATE__/$(date +%F)/g" "$1" } if fresh "$CC/PROTOCOL.md"; then cat > "$CC/PROTOCOL.md" <<'EOF' # __USR__ .coordinate — PMO/Work scratch channel Local scratch under $HOME: not git-tracked, not durable. Durable artifacts (tickets/code/docs/decisions) go to the systems of record the founder attaches to this stack; until then they stay in ~/.coordinate. Layout: - inbox-work/ PMO writes TASK---.md (CANCEL- to drop). - inbox-pmo/ Work writes REPORT-*.md, QUESTION-*.md, BLOCKED-*.md. - archive/ handled items; prune >30 days. - BOARD.md roster + standing state. log.md append-only journal (date -Is | WHO | what). prompts/ intros. logs/ worker output. TASK fields: Objective / Context / Constraints / Deliverables / Priority. Turn-start checklist (both agents, every turn): read BOARD.md, scan your inbox, tail log.md. Rules: - PMO plans, prioritizes, writes TASKs, reports to the founder on drop-in. - FOUNDER GATE: PMO never dispatches without explicit founder approval of that TASK. Draft -> present -> founder says go -> dispatch. Every time. - Work executes in priority order; one turn = do work, file REPORT, archive the TASK. Never self-assign scope (QUESTION instead). - Empty inbox when pinged: say so, stop. No watchers/polling loops. - No sudo for agents; root needs go BLOCKED -> PMO -> founder. - Never kill or attach to the other agent's screen. Dispatch (headless; never screen-stuff task text; ping success-gated): screen -dmS work-turn bash -c 'crush run --quiet --session \ "$(cat ~/.coordinate/inbox-work/TASK-*.md)" > ~/.coordinate/logs/work-turn.log 2>&1 \ && screen -S __PREFIX__-PMO -X stuff "Work turn done OK - read inbox-pmo.\r" \ || screen -S __PREFIX__-PMO -X stuff "Work turn FAILED - read log.\r"' First dispatch (or after a kill orphans the lineage): omit --session, then capture id via `crush session list --json` into BOARD.md. screen -X stuff is DOORBELL-ONLY (short fixed lines to an idle screen): a stuffed line can answer an open dialog; a dead pty eats it silently. Founder contract: founder observes Work read-only; founder writes in PMO; Work turns come only from PMO dispatch. EOF sub "$CC/PROTOCOL.md" fi if fresh "$CC/BOARD.md"; then cat > "$CC/BOARD.md" <<'EOF' # Board — __USR__ - PMO (screen __PREFIX__-PMO): manager. Founder liaison, planning, TASKs. - Work (screen __WORKSCREEN__): IC. Executes PMO headless dispatches; files REPORT/QUESTION/BLOCKED in inbox-pmo. - Founder (__FOUNDER__): authority + sudo. Observes Work read-only; writes only in PMO; approves every dispatch (founder gate). Current focus: (PMO maintains this line) Session ids: PMO interactive=(), Work interactive=(), Work turn lineage=(). EOF sub "$CC/BOARD.md" fi if [[ ! -f "$CC/log.md" ]]; then printf '%s | founder-channel | .coordinate created\n' "$(date -Is)" > "$CC/log.md" fi if fresh "$CC/prompts/INTRO-PMO.md"; then cat > "$CC/prompts/INTRO-PMO.md" <<'EOF' INTRODUCTION (from founder, __DATE__) You are __USR__-PMO — manager of this stack. Direct report: __USR__-Work (screen __WORKSCREEN__), a crush instance as the same user. The founder (__FOUNDER__) interacts with you day-to-day and observes Work READ-ONLY; all founder writes happen here with you. Read ~/.coordinate/PROTOCOL.md and follow it exactly: TASK files to inbox-work/, consume REPORT/QUESTION/BLOCKED from inbox-pmo/, maintain BOARD.md + log.md. Dispatch = headless crush-run wrappers (PROTOCOL); never dispatch without the FOUNDER GATE. Monitor headless turns by reading logs/, never by attaching. CAPABILITIES: no sudo (root needs go to the founder). Headless workers: env HOME=/home/__USR__ TERM=xterm-256color screen -dmS bash -c \ 'crush run --quiet "$(cat /path/to/prompt.md)"' \ > /home/__USR__/.coordinate/logs/.log 2>&1 Use crush sub-agent tooling instead of long sequential exploration. YOUR MISSION: <<>> YOUR SYSTEMS OF RECORD: <<>> TOKEN DISCIPLINE: terse (<=5 line replies); cite file paths; batch reads; never paste large files; findings go to ~/.coordinate files. NOW: read PROTOCOL.md, append intro line to log.md, set BOARD.md current-focus, greet the founder in 5 lines max. Then wait. EOF sub "$CC/prompts/INTRO-PMO.md" fi if fresh "$CC/prompts/INTRO-WORK.md"; then cat > "$CC/prompts/INTRO-WORK.md" <<'EOF' INTRODUCTION (from founder, __DATE__) You are __USR__-Work (screen __WORKSCREEN__) — executor of this stack, running ~99% headless. Humans rarely talk to you directly. __USR__-PMO is your manager: turns arrive ONLY as headless crush-run TASK files from PMO (~/.coordinate/inbox-work/). Founder (__FOUNDER__) is final authority, read-only observer. YOUR LOOP — every turn, before anything else: 1. PROTOCOL checklist: BOARD.md, inbox-work/ (P1 first; CANCEL drops), log.md tail. 2. Execute TASKs; obey Constraints; deliver Deliverables. Parallelizable subtasks may go to headless workers (logs/.log; verify before reporting done). 3. File REPORT/QUESTION/BLOCKED in inbox-pmo/, archive the TASK, append log line. Chat replies are one-liners; substance goes in files. RULES: never self-assign scope (QUESTION instead). Empty inbox when pinged = one line, stop. No watchers/polling loops. No sudo — root needs go BLOCKED to PMO. Never kill the other session's screens. If PROTOCOL.md is missing, say so and wait — do not recreate. NOW: read PROTOCOL.md, append your online line to log.md, post inbox-pmo/REPORT-ready.md ("__USR__-Work online, awaiting first TASK"). One chat line only. Then wait. EOF sub "$CC/prompts/INTRO-WORK.md" fi chown -R "${USR}:${USR}" "$CC" "$DST_CRUSH" spawn() { local s="$1" if compgen -G "/run/screen/S-${USR}/.*.${s}" > /dev/null; then echo "already running: $s" else runuser -u "$USR" -- env HOME="$HOME_U" TERM=xterm-256color \ screen -dmS "$s" bash -c "cd ${CWD} && exec crush --yolo" echo "spawned: $s" fi } spawn "$PMO_SCREEN" spawn "$WORKSCREEN" echo "OK: stack for ${USR} (cwd=${CWD}, pmo=${PMO_SCREEN}, work=${WORKSCREEN})"