@@ -16,7 +16,7 @@ This plan implements the Advanced Feature Plan (Specs 0–5) to create a fully f
1616
17172 . ** Spec 1** : Make devices fully functional with scope enforcement, heartbeat, and command channel.
1818
19- 3 . ** Spec 2** : Unify remotes as devices, create a remote satellite daemon, and implement heartbeat-based presence .
19+ 3 . ** Spec 2** : Devices fully unified (legacy remotes removed); remote satellite daemon implemented .
2020
21214 . ** Spec 3** : Complete action lifecycle with approval persistence, execution status, result storage, and tool execution.
2222
@@ -25,8 +25,8 @@ This plan implements the Advanced Feature Plan (Specs 0–5) to create a fully f
25256 . ** Spec 5** : Implement real-time event broadcasting to make the GUI feel alive.
2626
2727** Trade-offs** :
28- - ** Gain** : Coherent permission model, working devices/remotes/ actions/memories, real-time GUI, and session continuity.
29- - ** Lose** : Migration effort to remove legacy table references; remote daemon is a new app to maintain.
28+ - ** Gain** : Coherent permission model, working devices/actions/memories, real-time GUI, and session continuity.
29+ - ** Lose** : Remote satellite daemon is a new app to maintain.
3030
3131---
3232
@@ -36,7 +36,7 @@ This plan implements the Advanced Feature Plan (Specs 0–5) to create a fully f
3636flowchart TD
3737 S0[Spec 0: Fix Identity/Permission Spine]
3838 S1[Spec 1: Devices Fully Functional]
39- S2[Spec 2: Remotes as Devices ]
39+ S2[Spec 2: Devices (legacy remotes removed) ]
4040 S3[Spec 3: Actions Fully Functional]
4141 S4[Spec 4: Core Agent + Memories]
4242 S5[Spec 5: Real-time Event Stream]
@@ -55,7 +55,7 @@ flowchart TD
5555** Critical Path** : Spec 0 → (Spec 1 + Spec 3) → Spec 5
5656
5757** Parallel Workstreams** (after Spec 0):
58- - Spec 1 + Spec 2 (devices/remotes )
58+ - Spec 1 + Spec 2 (devices)
5959- Spec 3 + Spec 4 (actions/memories)
6060- All converge at Spec 5 (broadcasting)
6161
@@ -85,7 +85,7 @@ ALTER TABLE IF EXISTS memberships RENAME TO legacy_memberships;
8585| File | Change |
8686| ------| --------|
8787| ` functions/hub_api/app.py ` | Replace all ` memberships ` JOIN with ` agent_memberships ` (8 occurrences found) |
88- | ` sql/003_remotes.sql ` | Already creates ` memberships ` - mark as legacy reference only |
88+ | ` sql/003_remotes.sql ` | Already creates ` memberships ` - mark as legacy reference only | (DELETED)
8989
9090** Lines to modify in ` app.py ` ** (found via search):
9191- Line 428, 452, 503, 723, 783, 819, 1009, 1524, 1790, 1825, 2073
@@ -99,7 +99,7 @@ ALTER TABLE IF EXISTS memberships RENAME TO legacy_memberships;
9999
100100** Acceptance Criteria** :
101101- [ ] No code references ` memberships ` table (only ` legacy_memberships ` or ` agent_memberships ` )
102- - [ ] GUI pages (revoke device, delete memory, approve action, delete remote ) work correctly
102+ - [ ] GUI pages (revoke device, delete memory, approve action) work correctly
103103- [ ] All existing tests pass
104104
105105** Risk** : Medium — requires careful search/replace and testing
@@ -168,92 +168,14 @@ ALTER TABLE devices ADD COLUMN IF NOT EXISTS last_heartbeat_at timestamptz;
168168
169169---
170170
171- ### Phase 2: Spec 2 — Remotes as Devices
171+ ### Phase 2: Spec 2 -- Devices (formerly " Remotes as Devices") -- COMPLETE, legacy removed
172172
173- ** Goal** : Unify remotes and devices; create remote satellite daemon.
173+ > ** Status** : Complete. The legacy ` remotes ` table, GUI page (` /remotes ` ), API endpoints
174+ > (` /api/remotes/* ` ), and all related tests have been fully removed from the codebase (2026-02-06).
175+ > Satellite devices are managed exclusively through the ` devices ` table.
174176
175- #### 3.2.1 Design Decision
176-
177- ** Recommendation** : Fold ` remotes ` into ` devices ` (Option A from spec).
178-
179- - Remotes are devices with ` metadata.is_remote = true `
180- - Remote-specific fields stored in ` devices.metadata ` and ` devices.capabilities `
181- - Existing ` remotes ` table becomes ` legacy_remotes ` or is migrated
182-
183- #### 3.2.2 Database Migration
184-
185- ** File** : ` sql/007_remotes_to_devices.sql `
186-
187- ``` sql
188- -- Migrate existing remotes to devices
189- -- Each remote gets a new device entry with appropriate metadata
190-
191- INSERT INTO devices (agent_id, name, capabilities, metadata, scopes)
192- SELECT
193- agent_id,
194- name,
195- capabilities,
196- jsonb_build_object(
197- ' is_remote' , true,
198- ' address' , address,
199- ' connection_type' , connection_type
200- ),
201- ' ["events:write", "presence:write"]' ::jsonb
202- FROM remotes
203- WHERE NOT EXISTS (
204- SELECT 1 FROM devices d
205- WHERE d .metadata - >> ' migrated_from_remote_id' = remotes .remote_id ::text
206- )
207- ON CONFLICT DO NOTHING;
208-
209- -- Rename remotes table to legacy
210- ALTER TABLE IF EXISTS remotes RENAME TO legacy_remotes;
211- ```
212-
213- #### 3.2.3 New App: Remote Satellite Daemon
214-
215- ** Directory** : ` apps/remote_satellite/ `
216-
217- | File | Purpose |
218- | ------| ---------|
219- | ` apps/remote_satellite/__init__.py ` | Package init |
220- | ` apps/remote_satellite/daemon.py ` | Main daemon entry point |
221- | ` apps/remote_satellite/hub_client.py ` | WebSocket + REST Hub client |
222- | ` apps/remote_satellite/requirements.txt ` | Dependencies (websockets, requests) |
223- | ` apps/remote_satellite/README.md ` | Installation and usage |
224-
225- ** Daemon Responsibilities** :
226- 1 . Connect to Hub WebSocket using device token
227- 2 . Send ` hello ` on connect
228- 3 . Send heartbeat every 15–30 seconds
229- 4 . Respond to ` cmd.ping ` with ` cmd.pong `
230- 5 . Execute device-local tools on ` cmd.run_action ` (Phase 2 stretch)
231-
232- #### 3.2.4 GUI Updates
233-
234- | File | Change |
235- | ------| --------|
236- | ` functions/hub_api/app.py ` | Update ` /remotes ` route to query devices with ` is_remote ` metadata |
237- | ` functions/hub_api/templates/remotes.html ` | Show device-based remotes |
238- | ` functions/hub_api/app.py ` | ` POST /api/remotes ` creates a device with remote metadata |
239-
240- #### 3.2.5 Tests
241-
242- | Test File | Tests |
243- | -----------| -------|
244- | ` tests/test_remote_satellite.py ` (new) | Daemon heartbeat, ping/pong |
245- | ` tests/test_gui_remotes_as_devices.py ` (new) | GUI shows device-based remotes |
246-
247- ** Acceptance Criteria** :
248- - [ ] Adding a remote produces a device with token + install snippet
249- - [ ] Remote shows "online" when daemon is connected
250- - [ ] Ping works over WebSocket (server→remote→server)
251- - [ ] Existing remote data migrated successfully
252-
253- ** Risk** : Medium — new app, migration
254- ** Estimate** : 4–5 hours
255-
256- ---
177+ The remote satellite daemon (` apps/remote_satellite/ ` ) authenticates as a device and connects
178+ via WebSocket for heartbeats, ping/pong, and action execution.
257179
258180### Phase 3: Spec 3 — Actions Fully Functional
259181
@@ -316,7 +238,7 @@ def execute(payload: dict, ctx: ToolContext) -> ToolResult:
316238** Acceptance Criteria** :
317239- [ ] GUI approve → action executes
318240- [ ] GUI shows action results (result/error)
319- - [ ] ` device_command ` action can ping a remote
241+ - [ ] ` device_command ` action can ping a device
320242- [ ] ` send_message ` stores event even if broadcast fails
321243
322244** Risk** : Medium
@@ -459,7 +381,6 @@ def broadcast_to_subscribers(
459381| ` functions/hub_api/static/js/marvain.js ` | Handle broadcast messages, update UI |
460382| ` functions/hub_api/templates/actions.html ` | Auto-refresh on ` actions.updated ` |
461383| ` functions/hub_api/templates/devices.html ` | Auto-refresh on ` presence.updated ` |
462- | ` functions/hub_api/templates/remotes.html ` | Auto-refresh on ` presence.updated ` |
463384
464385#### 3.5.6 Tests
465386
@@ -470,7 +391,7 @@ def broadcast_to_subscribers(
470391
471392** Acceptance Criteria** :
472393- [ ] Actions page updates without manual refresh
473- - [ ] Remotes/devices online state updates without polling
394+ - [ ] Devices online state updates without polling
474395- [ ] Events page shows new events in real-time
475396
476397** Risk** : Medium — requires DynamoDB GSI for efficient subscription lookup
@@ -539,9 +460,9 @@ Each commit should be a logical unit:
539460 - ` feat(ws): add device command messages `
540461
5414623 . ** Phase 2 commits** :
542- - ` feat (db): add migration 007 for remotes to devices`
463+ - ` refactor (db): remove migration 007 ( remotes to devices) -- legacy cleanup `
543464 - ` feat(app): add remote satellite daemon skeleton `
544- - ` refactor(gui): update remotes page for device-based remotes `
465+ - ` refactor: remove legacy remotes page entirely `
545466
5464674 . ** Phase 3 commits** :
547468 - ` feat(db): add migration 008 for action enhancement `
@@ -599,7 +520,7 @@ git revert <commit-hash>
599520### 6.4 Data Safety
600521
601522- ` legacy_memberships ` preserved (not dropped)
602- - ` legacy_remotes ` preserved (not dropped)
523+ - ` legacy_remotes (REMOVED) ` preserved (not dropped)
603524- Audit bucket has Object Lock (immutable)
604525
605526---
@@ -636,7 +557,7 @@ git revert <commit-hash>
636557| -------| -------------| ----------| --------------|
637558| Phase 0 | Fix identity/permission spine | 2–3 hours | None |
638559| Phase 1 | Devices fully functional | 3–4 hours | Phase 0 |
639- | Phase 2 | Remotes as devices | 4–5 hours | Phase 0, Phase 1 |
560+ | Phase 2 | Devices (legacy remotes removed) | 4–5 hours | Phase 0, Phase 1 |
640561| Phase 3 | Actions fully functional | 4–5 hours | Phase 0 |
641562| Phase 4 | Core agent + memories | 4–5 hours | Phase 0 |
642563| Phase 5 | Real-time event stream | 4–5 hours | Phase 3, Phase 4 |
@@ -672,7 +593,7 @@ All 6 phases (Specs 0-5) have been successfully implemented.
672593| -------| ------| --------| --------|
673594| 0 | Fix Identity/Permission Spine | ` c5abd1f ` | ✅ Complete |
674595| 1 | Devices Fully Functional | ` 24f9d3f ` | ✅ Complete |
675- | 2 | Remotes as Devices | ` 2c73b39 ` | ✅ Complete |
596+ | 2 | Devices (legacy remotes removed) | ` 2c73b39 ` | ✅ Complete |
676597| 3 | Actions Fully Functional | ` 8938244 ` | ✅ Complete |
677598| 4 | Core Agent + Memories | ` 806bdd7 ` | ✅ Complete |
678599| 5 | Real-time Event Stream | ` 4604d61 ` | ✅ Complete |
@@ -687,7 +608,7 @@ All 6 phases (Specs 0-5) have been successfully implemented.
687608** New Files Created:**
688609- ` sql/005_users_columns_and_legacy_cleanup.sql ` - Migration for users columns and legacy memberships cleanup
689610- ` sql/006_devices_enhancement.sql ` - Device scopes, heartbeat, command channel
690- - ` sql/007_remotes_to_devices.sql ` - Migrate remotes to devices table
611+ - ` sql/007_remotes_to_devices.sql (DELETED) ` - Migrate remotes to devices table
691612- ` sql/008_actions_enhancement.sql ` - Action lifecycle columns (result, error, timestamps)
692613- ` layers/shared/python/agent_hub/broadcast.py ` - WebSocket broadcast module
693614- ` layers/shared/python/agent_hub/tools/device_command.py ` - Device command tool
0 commit comments