Files
ocp/docs/runbooks/tui-flip-rollback.md
T
79c1d61e1d docs(tui): 6/15 canary + flip/rollback runbooks + setup auth-probe guard (PR-C) (#138)
Docs scope (no server.mjs touched):
- docs/runbooks/615-canary.md — executable canary runbook: quiesce host,
  read Agent SDK credit balance manually (no programmatic API exists for
  that pool — this is stated explicitly to avoid endpoint hallucination),
  send one Haiku turn via TUI-mode, confirm cc_entrypoint=cli in transcript,
  re-read balance, green/red decision tree, periodic self-classification
  mini-canary with OCP_TUI_ENTRYPOINT=auto.
- docs/runbooks/tui-flip-rollback.md — flip and rollback procedure for
  systemd (EnvironmentFile + daemon-reload) and launchd (plist edit +
  bootout/bootstrap cycle). Calls out both known pitfalls explicitly:
  daemon-reload required on systemd; launchctl kickstart -k does NOT
  reload plist env on launchd (matches MEMORY.md operational pit entry).
- README.md § "2026-06-15 operator checklist" — brief fleet checklist +
  pointers to both runbooks. Placed inside the existing TUI-mode section
  just before "Architecture and design decisions".
- README.md § Environment Variables — adds OCP_SKIP_AUTH_TEST row.

Operator-tooling scope (setup.mjs, not a Class A wire path):
- setup.mjs auth quick-test: wraps the existing claude -p probe in an
  OCP_SKIP_AUTH_TEST=1 gate; adds inline comment warning that after
  2026-06-15 the probe draws from the Agent SDK credit pool. The setup
  flow is unchanged when OCP_SKIP_AUTH_TEST is unset.

Alignment note: this PR does not touch server.mjs. The setup.mjs change
is operator-tooling only — it guards a local test spawn, not any wire
path. No cli.js citation required (no Class A surface is modified).

Co-authored-by: dtzp555 <dtzp555@gmail.com>
Co-authored-by: Claude claude-sonnet-4-6 <noreply@anthropic.com>
2026-06-10 21:41:03 +10:00

6.0 KiB

TUI-Mode Flip and Rollback Runbook

Purpose: Step-by-step instructions for enabling (CLAUDE_TUI_MODE=true) or disabling TUI-mode on real OCP deployments managed by systemd (Linux) or launchd (macOS).

Run the 615-canary runbook after any flip to confirm billing pool routing is correct.


Critical pitfalls — read first

systemd: daemon-reload is required after editing the unit

Editing the unit file (or EnvironmentFile) and then doing systemctl restart ocp.service without daemon-reload will restart the process with the old environment from the cached unit. Always run daemon-reload after editing any unit file.

launchd: launchctl kickstart -k does NOT reload plist env

launchctl kickstart -k gui/$(id -u)/dev.ocp.proxy kills the running process and re-launches it, but it re-uses the launchd-cached environment — not the current plist file. If you edited the plist's EnvironmentVariables section, you must do a full bootout + bootstrap cycle for the change to take effect. kickstart is not sufficient.


Flip — enable TUI-mode

systemd (Linux, e.g. Raspberry Pi, VPS)

Option A — EnvironmentFile (recommended for clean separation)

If your unit uses EnvironmentFile=/etc/ocp/ocp.env (or similar):

# 1. Edit the environment file
sudo nano /etc/ocp/ocp.env
# Add or update:
#   CLAUDE_TUI_MODE=true
#
# If OCP binds to 0.0.0.0 AND you trust the network:
#   OCP_TUI_ALLOW_LAN=1
#   (WARNING: TUI-mode is single-user only — only enable OCP_TUI_ALLOW_LAN=1
#    if you fully trust every caller that can reach the OCP port on your network)

# 2. Reload the unit definition and restart
sudo systemctl daemon-reload
sudo systemctl restart ocp.service

# 3. Verify
curl -s http://127.0.0.1:3456/health | python3 -m json.tool | grep -E "tui|version"
# Expected: "tuiMode": true (or similar TUI indicator in the health response)

Option B — inline Environment= in the unit file

# 1. Edit the unit file
sudo systemctl edit --full ocp.service
# Add or update in the [Service] section:
#   Environment=CLAUDE_TUI_MODE=true

# 2. Reload and restart
sudo systemctl daemon-reload
sudo systemctl restart ocp.service

# 3. Verify
systemctl show ocp.service --property=Environment
# Expected: Environment=CLAUDE_TUI_MODE=true ...

launchd (macOS)

Locate the OCP plist. The standard label is dev.ocp.proxy:

# Find the plist path
ls ~/Library/LaunchAgents/dev.ocp.proxy.plist

Edit the plist:

# 1. Stop the service first (bootout)
launchctl bootout gui/$(id -u)/dev.ocp.proxy

# 2. Edit the plist — add CLAUDE_TUI_MODE to EnvironmentVariables
#    Use your editor of choice:
nano ~/Library/LaunchAgents/dev.ocp.proxy.plist

Inside the plist, in the <key>EnvironmentVariables</key> <dict> block, add:

<key>CLAUDE_TUI_MODE</key>
<string>true</string>

If OCP_TUI_ALLOW_LAN=1 is also needed (only if OCP binds to 0.0.0.0 and you trust the network):

<key>OCP_TUI_ALLOW_LAN</key>
<string>1</string>
# 3. Bootstrap (reload from disk + start)
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/dev.ocp.proxy.plist

# 4. Verify
curl -s http://127.0.0.1:3456/health | python3 -m json.tool | grep -E "tui|version"

Confirm env was actually loaded (not just set in your shell):

ps aux | grep server.mjs | grep -v grep
# Get the PID, then:
# macOS: ps -E -p <PID> | tr ' ' '\n' | grep CLAUDE_TUI_MODE
# Expected: CLAUDE_TUI_MODE=true

Rollback — disable TUI-mode

Rollback is the same procedure as flip, but you remove CLAUDE_TUI_MODE or set it to any value other than "true" (e.g. false, or simply omit it).

After rollback, OCP returns to the default callClaude / callClaudeStreaming stream-json path — byte-for-byte identical to the pre-TUI code path. No other change is required.

systemd rollback

# Option A — EnvironmentFile
sudo nano /etc/ocp/ocp.env
# Remove or comment out:
#   CLAUDE_TUI_MODE=true
#   OCP_TUI_ALLOW_LAN=1  (if set)

sudo systemctl daemon-reload
sudo systemctl restart ocp.service

# Verify
curl -s http://127.0.0.1:3456/health | python3 -m json.tool | grep tui
# Expected: "tuiMode": false (or the field absent)

launchd rollback

# 1. Stop
launchctl bootout gui/$(id -u)/dev.ocp.proxy

# 2. Edit plist — remove the CLAUDE_TUI_MODE and OCP_TUI_ALLOW_LAN entries from EnvironmentVariables

# 3. Bootstrap
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/dev.ocp.proxy.plist

# 4. Verify
curl -s http://127.0.0.1:3456/health | python3 -m json.tool | grep tui

Billing impact of staying on the default (non-TUI) path after 2026-06-15

If you do NOT flip to TUI-mode and keep CLAUDE_TUI_MODE unset (the default), OCP continues using claude -p --output-format stream-json, which sets cc_entrypoint=sdk-cli. After 2026-06-15, every OCP request on the default path will draw from the Agent SDK credit pool (approximately $20/month on a Pro plan, or $100/month on a Max plan) rather than the Pro/Max subscription. The subscription pool usage (5-hour and 7-day windows) will be unaffected, but the Agent SDK credit balance will drain with each request.

If you want to continue using OCP without TUI-mode after 2026-06-15, budget for the Agent SDK credit cost accordingly — or switch to OLP for multi-provider fallback.


Verify after any flip

  1. Check /health shows the expected tuiMode state.
  2. Run the 615-canary to confirm billing pool routing.
  3. If TUI-mode is ON: check ocp logs 10 for any TUI spawn errors (tui_spawn_failed, tmux errors).