Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actionlint.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Custom labels for the org's self-hosted runner farm (tootie-ci-runner-1..4),
# Custom labels for the org's self-hosted runner farm (nashost-ci-runner-1..4),
# so actionlint (run by the Workflow and dependency policy check) accepts
# runs-on entries like [self-hosted, unraid].
self-hosted-runner:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/synthetics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ concurrency:

jobs:
public-path:
# Self-hosted (tootie runner farm): residential egress is not challenged by
# Self-hosted (nashost runner farm): residential egress is not challenged by
# Cloudflare, unlike GitHub-hosted Azure IPs (see ops/synthetics-cloudflare.md).
runs-on: [self-hosted, unraid]
permissions:
Expand Down
6 changes: 3 additions & 3 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ const config: StorybookConfig = {
allowedHosts: [
"localhost",
"127.0.0.1",
"dookie",
"dookie.manatee-triceratops.ts.net",
"100.88.16.79",
"devhost",
"devhost.example.ts.net",
"198.51.100.1",
],
},
}
Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ and shadcn CLI (registry JSON from `public/r/*.json`).
`docs/component-kotlin-map.md` (Kotlin/Compose parity matrix).
- **SWAG upstream contract:** `aurora.dinglebear.ai` (canonical; `aurora.tootie.tv`
also matches via the wildcard `server_name aurora.*`), `dinglebear.ai`, and
`www.dinglebear.ai` are reverse-proxied by SWAG on `squirts` to the immutable
`aurora` production container on **dookie**, host port `50000→3000`. The
`www.dinglebear.ai` are reverse-proxied by SWAG on `edgehost` to the immutable
`aurora` production container on **devhost**, host port `50000→3000`. The
canonical digest-only Compose overlay and SWAG templates are tracked under
`ops/`; `docs/deployment.md` is the runbook. The `aurora-dev` source bind mount
is isolated on port 3000 and must never receive public traffic. Scheme HTTP,
Expand Down
2 changes: 1 addition & 1 deletion app/gallery/demos/empty-demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export default function EmptyStateDemo() {
as="h2"
icon={<CloudOff size={24} aria-hidden />}
title="Couldn’t reach the gateway"
description="The request to lab.tootie.tv timed out. Check the connection and try again."
description="The request to lab.example.internal timed out. Check the connection and try again."
action={
<Button variant="warn" iconLeft={<RefreshCw size={14} aria-hidden />}>
Retry
Expand Down
4 changes: 2 additions & 2 deletions app/gallery/demos/textarea-demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export default function TextareaDemo() {

// Character-count field, controlled so the counter tracks live edits.
const [summary, setSummary] = React.useState(
"Restart the qdrant container on dookie and re-run the health check."
"Restart the qdrant container on devhost and re-run the health check."
)

return (
Expand Down Expand Up @@ -177,7 +177,7 @@ export default function TextareaDemo() {
error
showCount
maxLength={72}
defaultValue="fix: the qdrant container on dookie kept dropping its collection after a restart because the volume mount drifted"
defaultValue="fix: the qdrant container on devhost kept dropping its collection after a restart because the volume mount drifted"
/>
</Field>
</div>
Expand Down
16 changes: 8 additions & 8 deletions app/gallery/demos/tool-calls-demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,47 +110,47 @@ const TROUBLESHOOT_SESSION: ToolCall[] = [
id: "ops-1",
tool: "shell.exec",
status: "completed",
args: { host: "tootie", command: "docker ps --filter name=sonarr --format '{{.Status}}'" },
args: { host: "nashost", command: "docker ps --filter name=sonarr --format '{{.Status}}'" },
result: "Up 3 hours (unhealthy)",
...span(14000, 13400),
},
{
id: "ops-2",
tool: "arcane.container.inspect",
status: "completed",
args: { host: "tootie", name: "sonarr" },
args: { host: "nashost", name: "sonarr" },
result: "State.Health.FailingStreak = 6 · last probe: connection refused :8989",
...span(13300, 12600),
},
{
id: "ops-3",
tool: "arcane.container.inspect",
status: "completed",
args: { host: "tootie", name: "prowlarr" },
args: { host: "nashost", name: "prowlarr" },
result: "State.Health = healthy · 4 indexers online",
...span(12500, 11900),
},
{
id: "ops-4",
tool: "sonarr.api.get",
status: "error",
args: { endpoint: "/api/v3/health", host: "tootie", port: 8989 },
result: "FetchError: ECONNREFUSED 100.120.242.29:8989 — API not accepting connections",
args: { endpoint: "/api/v3/health", host: "nashost", port: 8989 },
result: "FetchError: ECONNREFUSED 198.51.100.2:8989 — API not accepting connections",
...span(11800, 11500),
},
{
id: "ops-5",
tool: "cortex.logs.search",
status: "completed",
args: { host: "tootie", container: "sonarr", query: "level:error", since: "15m" },
args: { host: "nashost", container: "sonarr", query: "level:error", since: "15m" },
result: "3 matches · 'System.Data.SQLite.SQLiteException: database is locked'",
...span(11400, 10200),
},
{
id: "ops-6",
tool: "arcane.container.restart",
status: "running",
args: { host: "tootie", name: "sonarr", timeout_s: 30 },
args: { host: "nashost", name: "sonarr", timeout_s: 30 },
...since(2600),
},
]
Expand Down Expand Up @@ -220,7 +220,7 @@ export default function ToolCallsDemo() {
<section style={sectionStyle}>
<span style={lbl}>Homelab ops · mixed tools, one failure, live recovery</span>
<p style={captionStyle}>
A gateway agent diagnosing an unhealthy Sonarr container on tootie: a
A gateway agent diagnosing an unhealthy Sonarr container on nashost: a
shell probe, a repeated container inspect (grouped), a failed API fetch
rendered in rose, a log search that finds the root cause, and a restart
still in flight.
Expand Down
14 changes: 7 additions & 7 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ policy with tested build-time script hashes.

| Surface | Hostnames | Runtime | Port/network |
|---|---|---|---|
| Aurora design system | `aurora.tootie.tv` | `aurora` digest-pinned production container on dookie | host `50000` to container `3000`; external `jakenet` |
| Aurora design system | `aurora.tootie.tv` | `aurora` digest-pinned production container on devhost | host `50000` to container `3000`; external `jakenet` |
| Co-hosted fleet tenant | `dinglebear.ai`, `www.dinglebear.ai` | same immutable image; host routing in `proxy.ts` | same upstream |
| Local development | no public hostname | `aurora-dev` profile with source bind mount | host `3000`; isolated `aurora-dev` network |
| Local production smoke | no public hostname | `aurora-prod-build` profile | host `50001`; isolated `aurora-prod-build` network |

The tracked production contract is `ops/compose/production.yaml`; tracked SWAG
templates are under `ops/swag/`. `ops/check-production-topology.sh` validates
that both sides agree on port, network, tenant names, digest use, and isolation.
The host port binds only to `AURORA_BIND_ADDRESS` (dookie's Tailscale address),
The host port binds only to `AURORA_BIND_ADDRESS` (devhost's Tailscale address),
not a wildcard interface, so routable clients cannot bypass the SWAG ingress.

## Publish and promotion
Expand Down Expand Up @@ -51,9 +51,9 @@ the immutable digest pin plus the Trivy gate above.
fails. The `AURORA_ALERT_WEBHOOK_URL` steps were removed: the secret was
never set, so every "alert" was a no-op that made three workflows look
monitored while `publish.yml` stayed broken for a week unnoticed.
3. On dookie, create `jakenet` if it does not exist and install Docker Compose.
3. On devhost, create `jakenet` if it does not exist and install Docker Compose.
Keep the deployment env file outside the checkout.
4. On squirts, render the tracked SWAG templates, review the diff against the
4. On edgehost, render the tracked SWAG templates, review the diff against the
installed vhosts, run `nginx -t`, then atomically install/reload them. Do not
copy an unreviewed generated file over live proxy configuration.

Expand All @@ -66,7 +66,7 @@ Create a private environment file from the tracked example:
cp ops/compose/production.env.example ~/.config/aurora/production.env
chmod 600 ~/.config/aurora/production.env
# Replace AURORA_IMAGE_REF and AURORA_EXPECTED_SHA with the workflow outputs.
# Confirm AURORA_BIND_ADDRESS is dookie's current Tailscale address and set both
# Confirm AURORA_BIND_ADDRESS is devhost's current Tailscale address and set both
# AURORA_PUBLIC_URL and AURORA_TENANT_URL to their production HTTPS origins.
```

Expand All @@ -86,7 +86,7 @@ on both Aurora and the co-hosted dinglebear tenant:
ops/deploy.sh ~/.config/aurora/production.env
```

Only after that succeeds should SWAG public traffic point to dookie port 50000.
Only after that succeeds should SWAG public traffic point to devhost port 50000.
The dev profile remains on port 3000 and is never attached to `jakenet`.

## Rollback
Expand All @@ -109,7 +109,7 @@ intentional delay between merging and manual promotion is not reported as an
outage.

The `ops/install-monitor.sh` systemd watchdog was removed. It was never
installed on dookie — `aurora-monitor.timer` did not exist there — and its
installed on devhost — `aurora-monitor.timer` did not exist there — and its
`AURORA_ALERT_WEBHOOK_URL` was never set, so it could not have paged anyone. CI
was running a unit test for it. Container health is covered by the Compose
`HEALTHCHECK` and the twice-hourly synthetics above.
Expand Down
2 changes: 1 addition & 1 deletion docs/mockups/theme-previews.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<div class="row"><span class="ln">2</span></div>
<div class="row"><span class="ln">3</span><span style="color:#5a7a92">// dispatch one action across surfaces</span></div>
<div class="row"><span class="ln">4</span><span style="color:#38d2ff">pub async fn</span> <span style="color:#7ee0c8">dispatch</span><span style="color:#a8c5d8">(</span><span style="color:#f0f8fd">action</span><span style="color:#a8c5d8">:</span> <span style="color:#ffd479">Action</span><span style="color:#a8c5d8">)</span> <span style="color:#38d2ff">-></span> <span style="color:#ffd479">Result</span><span style="color:#a8c5d8">&lt;</span><span style="color:#ffd479">Json</span><span style="color:#a8c5d8">&gt; {</span></div>
<div class="row"><span class="ln">5</span> <span style="color:#38d2ff">let</span> <span style="color:#f0f8fd">gw</span> <span style="color:#38d2ff">=</span> <span style="color:#ffd479">Gateway</span><span style="color:#a8c5d8">::</span><span style="color:#7ee0c8">connect</span><span style="color:#a8c5d8">(</span><span style="color:#b8e6a0">"lab.tootie.tv"</span><span style="color:#a8c5d8">).</span><span style="color:#7ee0c8">await</span><span style="color:#a8c5d8">?;</span></div>
<div class="row"><span class="ln">5</span> <span style="color:#38d2ff">let</span> <span style="color:#f0f8fd">gw</span> <span style="color:#38d2ff">=</span> <span style="color:#ffd479">Gateway</span><span style="color:#a8c5d8">::</span><span style="color:#7ee0c8">connect</span><span style="color:#a8c5d8">(</span><span style="color:#b8e6a0">"lab.example.internal"</span><span style="color:#a8c5d8">).</span><span style="color:#7ee0c8">await</span><span style="color:#a8c5d8">?;</span></div>
<div class="row"><span class="ln">6</span> <span style="color:#f0f8fd">gw</span><span style="color:#a8c5d8">.</span><span style="color:#c9a6f0">run</span><span style="color:#a8c5d8">(</span><span style="color:#f0f8fd">action</span><span style="color:#a8c5d8">,</span> <span style="color:#ffb38a">3</span><span style="color:#a8c5d8">).</span><span style="color:#7ee0c8">await</span></div>
<div class="row"><span class="ln">7</span><span style="color:#a8c5d8">}</span></div>
</div>
Expand Down
26 changes: 13 additions & 13 deletions docs/sessions/2026-05-23-android-polish-test-implement.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,23 @@ beads: q007 bcjw thfe vyjr mkr1 syc7 w0am ilkm xe0i 01xq nev6 6mwo (12 closed) |

## User Request

After the parallel-dispatch session that landed PRs #6–#15: ask for an auth/server briefing, run a code review on the full diff, address all findings, install the APK via emulator on dookie and walk the chat flow end-to-end via claude-in-mobile / ADB, file all UI polish opportunities as beads, run lavra-research on each, and then lavra-work the resulting backlog.
After the parallel-dispatch session that landed PRs #6–#15: ask for an auth/server briefing, run a code review on the full diff, address all findings, install the APK via emulator on devhost and walk the chat flow end-to-end via claude-in-mobile / ADB, file all UI polish opportunities as beads, run lavra-research on each, and then lavra-work the resulting backlog.

## Session Overview

Long-running execution session. Three distinct phases:

1. **Code review + fixes**: 6 review findings addressed (AuthRepository, ChatViewModel handshake gate, SidebarViewModel timeout, ChatScreen empty-image guard, CodexRepository demux logging, dead `session/update` regression). Build green, APK uploaded.
2. **Live emulator test + bead capture**: Installed APK on dookie's existing emulator, drove the chat flow via ADB. Discovered `getAuthStatus` is not a real Codex protocol method — patched StartupViewModel to trust local AUTH_METHOD. Sent a real prompt round-trip ("Say hello and count from 1 to 3" → "Hello. 1, 2, 3." + tool call). Catalogued 14 polish opportunities as beads, dispatched 4 parallel lavra-research agents to attach evidence to each.
2. **Live emulator test + bead capture**: Installed APK on devhost's existing emulator, drove the chat flow via ADB. Discovered `getAuthStatus` is not a real Codex protocol method — patched StartupViewModel to trust local AUTH_METHOD. Sent a real prompt round-trip ("Say hello and count from 1 to 3" → "Hello. 1, 2, 3." + tool call). Catalogued 14 polish opportunities as beads, dispatched 4 parallel lavra-research agents to attach evidence to each.
3. **Multi-wave lavra-work execution**: Three waves of parallel-then-sequential agent dispatch. Wave 1 (q007, bcjw, thfe) shipped via the user committing `5bea020 Polish Android chat components`. Wave 2 (vyjr, mkr1, syc7, w0am) shipped via three commits. Wave 3 (ilkm, xe0i, 01xq, nev6, 6mwo) all touched `ChatScreen.kt` so a single sequential agent owned the file; shipped via `830e323`. All 12 polish beads closed; APK uploaded after each wave.

## Sequence of Events

1. Asked about auth model + server target; identified `codex app-server --listen ws://127.0.0.1:4500` on dookie (loopback, no auth required)
1. Asked about auth model + server target; identified `codex app-server --listen ws://127.0.0.1:4500` on devhost (loopback, no auth required)
2. Ran code-review skill with 3 finder angles + verifier; 6 findings consolidated
3. Applied fixes; rebased through a large remote update that had independently fixed 2 of the same issues; resolved 4 conflict files keeping both the remote refactor and the timeout-safety additions
4. Built APK 21M, uploaded to `gdrive:Aurora/app-debug.apk`
5. Installed APK on dookie's emulator-5554 via ADB; launched and observed LoginScreen
5. Installed APK on devhost's emulator-5554 via ADB; launched and observed LoginScreen
6. Identified `getAuthStatus` is not in Codex protocol — patched StartupViewModel to trust local `AUTH_METHOD`
7. Bypassed login, observed chat screen, sent real message; round-trip worked; tool call rendered
8. Tested ApprovalPolicyBar dropdown (worked), model selector dropdown (didn't open — bug), attach button, sidebar (opened by accident)
Expand Down Expand Up @@ -122,13 +122,13 @@ Long-running execution session. Three distinct phases:

## Tools and Skills Used

- **Bash**: `bd`, `git`, `gh`, `rtk` wrappers, `./gradlew`, `adb`, `ssh dookie`, `rclone`, `python3` snippets — for nearly every coordination step
- **Bash**: `bd`, `git`, `gh`, `rtk` wrappers, `./gradlew`, `adb`, `ssh devhost`, `rclone`, `python3` snippets — for nearly every coordination step
- **Read/Write/Edit**: file inspection and direct edits when not delegated to subagents
- **Agent (general-purpose subagents)**: dispatched 5 planning agents + 5 execution agents (prior session continuation) + 4 lavra-research agents + 3 wave-1 implementers + 3 wave-2 implementers + 1 wave-3 sequential implementer. ~15 subagent invocations total. Inter-agent WIP races observed during parallel waves — combined build is source of truth.
- **AskUserQuestion**: server-context confirmation, wave scope selection
- **Skill tool**: `code-review`, `gh-pr`, `screenshots`, `save-to-md`, `vibin:save-to-md`, `lavra:lavra-learn`, `lavra:lavra-work`, `lavra:lavra-work-multi`, `superpowers:dispatching-parallel-agents`
- **MCP tools**: `mcp__plugin_lab_lab__scout` (tool discovery), `mcp__plugin_lab_lab__invoke` (axon scrape of OpenAI Codex app-server docs)
- **ADB over SSH to dookie**: `adb install -r`, `adb shell input tap/text/keyevent`, `adb shell screencap -p`, `adb shell uiautomator dump`, `adb shell run-as` for DataStore prefs inspection, `adb logcat` for diagnostics
- **ADB over SSH to devhost**: `adb install -r`, `adb shell input tap/text/keyevent`, `adb shell screencap -p`, `adb shell uiautomator dump`, `adb shell run-as` for DataStore prefs inspection, `adb logcat` for diagnostics
- **rclone**: `rclone copy` to gdrive:Aurora (5+ APK uploads, ~21M each)
- **Issues**: (a) `device` MCP tool name collision between `lab` and `claude-in-mobile` gateways — couldn't route to claude-in-mobile, fell back to direct ADB which worked fine. (b) Raw websocket-client Python rejected with 403 due to Origin header; switched to socket-level handshake without Origin. (c) `bd auto-export` git-add failures (harmless warnings, didn't block push).

Expand All @@ -140,14 +140,14 @@ git diff --stat origin/main...HEAD # establish review scope
./gradlew :app:assembleDebug # BUILD SUCCESSFUL after each wave

# Server inspection
ssh dookie "ss -tlnp | grep ':4500'" # codex app-server on 127.0.0.1:4500
ssh dookie "ps -p 389362 -o cmd" # codex app-server --listen ws://127.0.0.1:4500
ssh devhost "ss -tlnp | grep ':4500'" # codex app-server on 127.0.0.1:4500
ssh devhost "ps -p 389362 -o cmd" # codex app-server --listen ws://127.0.0.1:4500

# Live testing
ssh dookie "adb devices" # emulator-5554 ready
scp APK dookie:/tmp/ && ssh dookie "adb install -r /tmp/aurora-app-debug.apk"
ssh dookie "adb shell am start -n tv.tootie.aurora.app/.MainActivity"
ssh dookie "adb shell input tap X Y; adb shell screencap -p > /tmp/aurora-screen.png"
ssh devhost "adb devices" # emulator-5554 ready
scp APK devhost:/tmp/ && ssh devhost "adb install -r /tmp/aurora-app-debug.apk"
ssh devhost "adb shell am start -n tv.tootie.aurora.app/.MainActivity"
ssh devhost "adb shell input tap X Y; adb shell screencap -p > /tmp/aurora-screen.png"

# Bead workflow
bd create --title=... --description=... --type=... --priority=... # 14 polish beads
Expand Down Expand Up @@ -236,7 +236,7 @@ rclone copy app-debug.apk gdrive:Aurora # final AP
**Recommended immediate next commands:**
```bash
# Install the final APK on the emulator for visual verification
ssh dookie "adb install -r /tmp/aurora-app-debug.apk && adb shell am start -n tv.tootie.aurora.app/.MainActivity"
ssh devhost "adb install -r /tmp/aurora-app-debug.apk && adb shell am start -n tv.tootie.aurora.app/.MainActivity"
# View remaining open beads to plan next session
bd ready --json | jq '.[].title' | head -10
```
Loading
Loading