Add desktop agent handoff
This commit is contained in:
202
handoffs/2026-06-30-desktop-agent-handoff.md
Normal file
202
handoffs/2026-06-30-desktop-agent-handoff.md
Normal file
@@ -0,0 +1,202 @@
|
||||
# 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:
|
||||
|
||||
```text
|
||||
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:
|
||||
|
||||
```sh
|
||||
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.
|
||||
|
||||
## Recommended Next Task
|
||||
|
||||
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:
|
||||
|
||||
```sh
|
||||
./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:
|
||||
|
||||
```text
|
||||
ws://<computer-lan-ip>:8080/ws/connect?deviceType=PHONE
|
||||
```
|
||||
|
||||
6. Add Wear OS entry after phone works:
|
||||
|
||||
```text
|
||||
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:
|
||||
|
||||
```sh
|
||||
./gradlew :backend:run
|
||||
```
|
||||
|
||||
Connect a client WebSocket:
|
||||
|
||||
```text
|
||||
ws://localhost:8080/ws/connect?deviceType=WEAR_OS_WATCH&deviceId=watch_1
|
||||
```
|
||||
|
||||
Send an approval request:
|
||||
|
||||
```sh
|
||||
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:
|
||||
|
||||
```sh
|
||||
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:
|
||||
|
||||
```text
|
||||
/Users/blindmouse/bin/gitea
|
||||
```
|
||||
|
||||
And old non-container setup files under:
|
||||
|
||||
```text
|
||||
/Users/blindmouse/gitea
|
||||
```
|
||||
|
||||
Those are not the active Gitea. The active Gitea is the Docker container named `gitea`.
|
||||
Reference in New Issue
Block a user