open-terminal 0.11.34 bare-metal (human-authorized host install) with a systemd template unit: reachableceo on tailscale-only :30000 (cwd ~/projects) and all 8 other accounts on :30001-30008, each with its own key kept out of ps in per-user TOMLs, all users added to the docker group. Keys live in ~/.creds + /etc/ukrrs/open-terminal, never in this repo. UAT: throwaway OpenWebUI v0.11.1 (matched to the human's Cloudron prod) driven purely over its HTTP API against the beta gateway lane - connection verify/config PASS, direct exec as uid 1001 PASS, and the chat round trip PASS: the model emitted run_command, we executed it through OpenWebUI's terminal proxy (server holds the key), and the final answer named 9/9 real project directories; earlier negative runs prove the test catches hallucinated output. Ops note OPEN-TERMINAL.md documents production wiring (prod openwebui container v0.3.10 is too old and needs an upgrade first). Also tonight: agent-stack relaunchers removed (6-, backups kept) so no screen/crush sessions auto-start on reboot; 22:00 night-profile flip observed live; docs synced for the earlier teardown. 💘 Generated with Crush Assisted-by: Crush:glm-5.2 [#610]
210 lines
8.2 KiB
Bash
Executable File
210 lines
8.2 KiB
Bash
Executable File
#!/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 <USER> <FOUNDER_ACCT> <SRC_CRUSH> [PREFIX]
|
|
# PREFIX defaults to USER. Screens: <PREFIX>-PMO / <PREFIX>-Work.
|
|
set -euo pipefail
|
|
|
|
USR="${1:?usage: setup-rceo-stack.sh <USER> <FOUNDER_ACCT> <SRC_CRUSH> [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-<yyyymmdd>-<HHMM>-<slug>.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 <WORK_TURN_SID> \
|
|
"$(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 <slug> bash -c \
|
|
'crush run --quiet "$(cat /path/to/prompt.md)"' \
|
|
> /home/__USR__/.coordinate/logs/<slug>.log 2>&1
|
|
Use crush sub-agent tooling instead of long sequential exploration.
|
|
|
|
YOUR MISSION: <<<FOUNDER: one paragraph — what this stack is for>>>
|
|
YOUR SYSTEMS OF RECORD: <<<FOUNDER: where durable work lands for this stack>>>
|
|
|
|
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/<slug>.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})"
|