Files
meatbag/handoffs/2026-06-30-desktop-agent-handoff.md
2026-06-30 17:31:59 -06:00

5.1 KiB

Meatbag Desktop Agent Handoff

Date: 2026-06-30 Project: Meatbag Ecosystem: WhetForge Repository: http://localhost:3000/bill/meatbag Branch: main

Current State

Meatbag is a Kotlin/Compose Multiplatform MVP scaffold for a "Human Latency Optimization Tool." The intended flow is:

  1. CLI agent or script sends an SDUI request to the backend.
  2. Ktor backend evaluates active devices and user attention rules.
  3. Backend pushes a JSON UI payload over WebSocket to the best device.
  4. Human taps a response.
  5. Client posts the response back to the backend.
  6. Backend completes the pending agent callback.

The repository has three modules:

  • common: shared kotlinx.serialization models for SDUI primitives, attention tiers, device context, callbacks, and responses.
  • backend: stateful Ktor backend with in-memory device registry and routing engine.
  • client: Compose Multiplatform stateless renderer and desktop simulator, plus Android/Wear attention hook scaffolding.

Important Commit

Initial pushed commit:

8b4cb8e Initialize Meatbag SDUI platform

This handoff should be committed after that initial push.

Gitea Notes

The actual Gitea is containerized in Colima/Docker:

  • URL: http://localhost:3000
  • Repo: http://localhost:3000/bill/meatbag
  • Container name: gitea
  • SSH exposed by container: host port 2222 to container port 22

If localhost:3000 is down, check:

colima status
colima start
docker ps

Do not use the old top-level /Users/blindmouse/gitea_setup.sh as the source of truth. That was an older non-container setup path.

What Works Conceptually

  • common/src/commonMain/kotlin/meatbag/common/UiPrimitive.kt

    • Strict sealed serializable SDUI model hierarchy:
      • ApprovalRequest
      • ActionList
      • TextInput
      • Message
    • Attention schema:
      • SILENT_HAPTIC
      • BACKGROUND_NOTIFICATION
      • OVERRIDE_SCREEN
    • Payload/context types:
      • WebSocketPayload
      • AttentionPolicy
      • DeviceContext
      • CallbackRequest
      • ApprovalResponse
  • backend/src/main/kotlin/meatbag/backend/RoutingEngine.kt

    • In-memory pending request map.
    • Mock UserRuleSet.
    • Watch-first routing for silent haptics.
    • Override-screen fan-out to multiple active devices.
    • Enriched payload context per target device.
  • backend/src/main/kotlin/meatbag/backend/Application.kt

    • GET /api/status
    • POST /api/request
    • POST /api/respond
    • WS /ws/connect?deviceType=WEAR_OS_WATCH|PHONE|DESKTOP
  • client/src/commonMain/kotlin/meatbag/client/ComponentRegistry.kt

    • Stateless UDF renderer.
    • No reflection.
    • Typed ComponentIntent out, converted to ApprovalResponse at the client boundary.
  • client/src/desktopMain/kotlin/meatbag/client/Main.kt

    • Desktop simulator for local payload testing and WebSocket connection testing.

Not Ready Yet

The repo is not yet a ready-to-install Android/Wear app for an S23 Ultra or watch.

Missing pieces:

  • Android app packaging:

    • AndroidManifest.xml
    • MainActivity
    • Compose app bootstrap for MeatbagClient
    • internet permission
    • cleartext HTTP allowance for local backend testing
  • Wear app packaging:

    • Wear entry point
    • manifest
    • real haptic implementation using Android vibrator APIs
    • watch-specific UI constraints
  • Build verification:

    • Previous environment did not have a Java runtime available, so Gradle tests/builds were not run successfully.

Make the Android phone client installable first, then add Wear OS.

Suggested sequence:

  1. Install/confirm JDK 17 on the machine doing the build.

  2. Run:

    ./gradlew :common:jvmTest :backend:test :client:compileKotlinDesktop
    
  3. Fix any compile issues from the recent scaffold.

  4. Add Android app entry:

    • client/src/androidMain/AndroidManifest.xml
    • client/src/androidMain/kotlin/meatbag/client/MainActivity.kt
    • Compose root that uses MeatbagClient
    • host/IP configuration for the backend
  5. Verify an S23 can connect to:

    ws://<computer-lan-ip>:8080/ws/connect?deviceType=PHONE
    
  6. Add Wear OS entry after phone works:

    ws://<computer-lan-ip>:8080/ws/connect?deviceType=WEAR_OS_WATCH
    
  7. Wire WearAttentionFeedback to real haptic APIs.

Local Backend Smoke Test Shape

Once backend runs on the computer:

./gradlew :backend:run

Connect a client WebSocket:

ws://localhost:8080/ws/connect?deviceType=WEAR_OS_WATCH&deviceId=watch_1

Send an approval request:

curl -X POST 'http://localhost:8080/api/request?urgent=true' \
  -H 'Content-Type: application/json' \
  -d '{
    "type": "ApprovalRequest",
    "id": "req_1",
    "prompt": "Allow agent to continue?",
    "target": "desktop-agent"
  }'

Respond:

curl -X POST 'http://localhost:8080/api/respond' \
  -H 'Content-Type: application/json' \
  -d '{
    "requestId": "req_1",
    "approved": true
  }'

Caution

There is a mistakenly downloaded standalone Gitea binary at:

/Users/blindmouse/bin/gitea

And old non-container setup files under:

/Users/blindmouse/gitea

Those are not the active Gitea. The active Gitea is the Docker container named gitea.