homaruscc 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/.env.example +8 -0
  2. package/LICENSE +21 -0
  3. package/README.md +307 -0
  4. package/bin/event-loop +60 -0
  5. package/config.example.json +55 -0
  6. package/dist/agent-registry.d.ts +38 -0
  7. package/dist/agent-registry.d.ts.map +1 -0
  8. package/dist/agent-registry.js +207 -0
  9. package/dist/agent-registry.js.map +1 -0
  10. package/dist/backend.d.ts +3 -0
  11. package/dist/backend.d.ts.map +1 -0
  12. package/dist/backend.js +59 -0
  13. package/dist/backend.js.map +1 -0
  14. package/dist/browser-service.d.ts +19 -0
  15. package/dist/browser-service.d.ts.map +1 -0
  16. package/dist/browser-service.js +101 -0
  17. package/dist/browser-service.js.map +1 -0
  18. package/dist/channel-adapter.d.ts +22 -0
  19. package/dist/channel-adapter.d.ts.map +1 -0
  20. package/dist/channel-adapter.js +62 -0
  21. package/dist/channel-adapter.js.map +1 -0
  22. package/dist/channel-manager.d.ts +18 -0
  23. package/dist/channel-manager.d.ts.map +1 -0
  24. package/dist/channel-manager.js +73 -0
  25. package/dist/channel-manager.js.map +1 -0
  26. package/dist/compaction-manager.d.ts +23 -0
  27. package/dist/compaction-manager.d.ts.map +1 -0
  28. package/dist/compaction-manager.js +135 -0
  29. package/dist/compaction-manager.js.map +1 -0
  30. package/dist/config.d.ts +21 -0
  31. package/dist/config.d.ts.map +1 -0
  32. package/dist/config.js +169 -0
  33. package/dist/config.js.map +1 -0
  34. package/dist/dashboard-adapter.d.ts +17 -0
  35. package/dist/dashboard-adapter.d.ts.map +1 -0
  36. package/dist/dashboard-adapter.js +41 -0
  37. package/dist/dashboard-adapter.js.map +1 -0
  38. package/dist/dashboard-server.d.ts +29 -0
  39. package/dist/dashboard-server.d.ts.map +1 -0
  40. package/dist/dashboard-server.js +381 -0
  41. package/dist/dashboard-server.js.map +1 -0
  42. package/dist/embedding-provider.d.ts +28 -0
  43. package/dist/embedding-provider.d.ts.map +1 -0
  44. package/dist/embedding-provider.js +91 -0
  45. package/dist/embedding-provider.js.map +1 -0
  46. package/dist/event-bus.d.ts +18 -0
  47. package/dist/event-bus.d.ts.map +1 -0
  48. package/dist/event-bus.js +41 -0
  49. package/dist/event-bus.js.map +1 -0
  50. package/dist/event-queue.d.ts +18 -0
  51. package/dist/event-queue.d.ts.map +1 -0
  52. package/dist/event-queue.js +68 -0
  53. package/dist/event-queue.js.map +1 -0
  54. package/dist/homaruscc.d.ts +69 -0
  55. package/dist/homaruscc.d.ts.map +1 -0
  56. package/dist/homaruscc.js +337 -0
  57. package/dist/homaruscc.js.map +1 -0
  58. package/dist/identity-manager.d.ts +36 -0
  59. package/dist/identity-manager.d.ts.map +1 -0
  60. package/dist/identity-manager.js +142 -0
  61. package/dist/identity-manager.js.map +1 -0
  62. package/dist/mcp-proxy.d.ts +3 -0
  63. package/dist/mcp-proxy.d.ts.map +1 -0
  64. package/dist/mcp-proxy.js +259 -0
  65. package/dist/mcp-proxy.js.map +1 -0
  66. package/dist/mcp-resources.d.ts +10 -0
  67. package/dist/mcp-resources.d.ts.map +1 -0
  68. package/dist/mcp-resources.js +67 -0
  69. package/dist/mcp-resources.js.map +1 -0
  70. package/dist/mcp-server.d.ts +3 -0
  71. package/dist/mcp-server.d.ts.map +1 -0
  72. package/dist/mcp-server.js +169 -0
  73. package/dist/mcp-server.js.map +1 -0
  74. package/dist/mcp-tools.d.ts +14 -0
  75. package/dist/mcp-tools.d.ts.map +1 -0
  76. package/dist/mcp-tools.js +408 -0
  77. package/dist/mcp-tools.js.map +1 -0
  78. package/dist/memory-index.d.ts +79 -0
  79. package/dist/memory-index.d.ts.map +1 -0
  80. package/dist/memory-index.js +437 -0
  81. package/dist/memory-index.js.map +1 -0
  82. package/dist/session-checkpoint.d.ts +22 -0
  83. package/dist/session-checkpoint.d.ts.map +1 -0
  84. package/dist/session-checkpoint.js +100 -0
  85. package/dist/session-checkpoint.js.map +1 -0
  86. package/dist/skill-manager.d.ts +26 -0
  87. package/dist/skill-manager.d.ts.map +1 -0
  88. package/dist/skill-manager.js +156 -0
  89. package/dist/skill-manager.js.map +1 -0
  90. package/dist/skill-transport.d.ts +45 -0
  91. package/dist/skill-transport.d.ts.map +1 -0
  92. package/dist/skill-transport.js +111 -0
  93. package/dist/skill-transport.js.map +1 -0
  94. package/dist/skill.d.ts +22 -0
  95. package/dist/skill.d.ts.map +1 -0
  96. package/dist/skill.js +106 -0
  97. package/dist/skill.js.map +1 -0
  98. package/dist/telegram-adapter.d.ts +43 -0
  99. package/dist/telegram-adapter.d.ts.map +1 -0
  100. package/dist/telegram-adapter.js +188 -0
  101. package/dist/telegram-adapter.js.map +1 -0
  102. package/dist/timer-service.d.ts +30 -0
  103. package/dist/timer-service.d.ts.map +1 -0
  104. package/dist/timer-service.js +176 -0
  105. package/dist/timer-service.js.map +1 -0
  106. package/dist/tool-registry.d.ts +30 -0
  107. package/dist/tool-registry.d.ts.map +1 -0
  108. package/dist/tool-registry.js +108 -0
  109. package/dist/tool-registry.js.map +1 -0
  110. package/dist/tools/bash.d.ts +3 -0
  111. package/dist/tools/bash.d.ts.map +1 -0
  112. package/dist/tools/bash.js +67 -0
  113. package/dist/tools/bash.js.map +1 -0
  114. package/dist/tools/browser.d.ts +4 -0
  115. package/dist/tools/browser.d.ts.map +1 -0
  116. package/dist/tools/browser.js +138 -0
  117. package/dist/tools/browser.js.map +1 -0
  118. package/dist/tools/edit.d.ts +3 -0
  119. package/dist/tools/edit.d.ts.map +1 -0
  120. package/dist/tools/edit.js +47 -0
  121. package/dist/tools/edit.js.map +1 -0
  122. package/dist/tools/git.d.ts +3 -0
  123. package/dist/tools/git.d.ts.map +1 -0
  124. package/dist/tools/git.js +105 -0
  125. package/dist/tools/git.js.map +1 -0
  126. package/dist/tools/glob.d.ts +3 -0
  127. package/dist/tools/glob.d.ts.map +1 -0
  128. package/dist/tools/glob.js +84 -0
  129. package/dist/tools/glob.js.map +1 -0
  130. package/dist/tools/grep.d.ts +3 -0
  131. package/dist/tools/grep.d.ts.map +1 -0
  132. package/dist/tools/grep.js +168 -0
  133. package/dist/tools/grep.js.map +1 -0
  134. package/dist/tools/index.d.ts +6 -0
  135. package/dist/tools/index.d.ts.map +1 -0
  136. package/dist/tools/index.js +46 -0
  137. package/dist/tools/index.js.map +1 -0
  138. package/dist/tools/memory.d.ts +4 -0
  139. package/dist/tools/memory.d.ts.map +1 -0
  140. package/dist/tools/memory.js +64 -0
  141. package/dist/tools/memory.js.map +1 -0
  142. package/dist/tools/read.d.ts +3 -0
  143. package/dist/tools/read.d.ts.map +1 -0
  144. package/dist/tools/read.js +50 -0
  145. package/dist/tools/read.js.map +1 -0
  146. package/dist/tools/web-fetch.d.ts +3 -0
  147. package/dist/tools/web-fetch.d.ts.map +1 -0
  148. package/dist/tools/web-fetch.js +51 -0
  149. package/dist/tools/web-fetch.js.map +1 -0
  150. package/dist/tools/web-search.d.ts +3 -0
  151. package/dist/tools/web-search.d.ts.map +1 -0
  152. package/dist/tools/web-search.js +65 -0
  153. package/dist/tools/web-search.js.map +1 -0
  154. package/dist/tools/write.d.ts +3 -0
  155. package/dist/tools/write.d.ts.map +1 -0
  156. package/dist/tools/write.js +32 -0
  157. package/dist/tools/write.js.map +1 -0
  158. package/dist/transcript-logger.d.ts +23 -0
  159. package/dist/transcript-logger.d.ts.map +1 -0
  160. package/dist/transcript-logger.js +101 -0
  161. package/dist/transcript-logger.js.map +1 -0
  162. package/dist/types.d.ts +190 -0
  163. package/dist/types.d.ts.map +1 -0
  164. package/dist/types.js +14 -0
  165. package/dist/types.js.map +1 -0
  166. package/identity.example/disagreements.md +9 -0
  167. package/identity.example/preferences.md +11 -0
  168. package/identity.example/soul.md +12 -0
  169. package/identity.example/state.md +21 -0
  170. package/identity.example/user.md +14 -0
  171. package/package.json +60 -0
package/.env.example ADDED
@@ -0,0 +1,8 @@
1
+ # HomarUScc environment variables
2
+ # Copy this to ~/.homaruscc/.env and fill in your values
3
+
4
+ # Required: Telegram bot token from @BotFather
5
+ TELEGRAM_BOT_TOKEN=your-bot-token-here
6
+
7
+ # Optional: API key for cloud embedding providers (not needed for Ollama)
8
+ # EMBEDDING_API_KEY=your-api-key-here
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Max Ross
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,307 @@
1
+ # HomarUScc
2
+
3
+ **An MCP server that gives Claude Code a body** — messaging, memory, identity, timers, browser automation, and tools. Claude Code is the brain. HomarUScc is the nervous system.
4
+
5
+ Most MCP servers add capabilities. HomarUScc adds _continuity_. It gives the agent persistent identity (who it is across sessions), evolving memory (what it's learned), and zero-token idle (it costs nothing when nobody's talking to it). The agent wakes on events, reasons, responds, reflects, and goes back to sleep.
6
+
7
+ The result is an agent that remembers yesterday's conversation, carries forward its own preferences and opinions, writes a daily journal, dreams overnight, and can modify its own personality file as it develops. Not a chatbot that resets every session — a persistent presence that grows over time.
8
+
9
+ Built with [mini-spec](https://github.com/zot/mini-spec).
10
+
11
+ ## How It Works
12
+
13
+ ```
14
+ Claude Code <-> MCP (stdio) <-> Proxy (mcp-proxy.ts)
15
+ | auto-spawns + HTTP forwarding
16
+ v
17
+ Backend (backend.ts)
18
+ |
19
+ +-- Telegram (long-polling adapter)
20
+ +-- Dashboard (Express + WebSocket SPA)
21
+ +-- Timer service (cron / interval / one-shot)
22
+ +-- Memory index (SQLite + vector + FTS + decay + MMR + dream scoring)
23
+ +-- Browser automation (Playwright)
24
+ +-- Identity manager (soul.md / user.md / state.md + journal)
25
+ +-- Session checkpoint (compaction resilience)
26
+ +-- Agent registry (background task dispatch)
27
+ +-- Skill plugins (hot-loadable)
28
+ +-- Tool registry (bash, fs, git, web, memory)
29
+ ```
30
+
31
+ The proxy is thin and never restarts. The backend can be restarted (via `restart_backend` tool) for self-improvement without dropping the MCP connection.
32
+
33
+ Events arrive from channels (Telegram messages, dashboard chat, timer fires) and flow into the event loop. HomarUScc sends MCP notifications to Claude Code, which reasons about them and calls MCP tools to respond.
34
+
35
+ ## Requirements
36
+
37
+ - [Claude Code](https://docs.anthropic.com/en/docs/claude-code) CLI
38
+ - Node.js >= 22
39
+ - (Optional) Ollama for local embeddings
40
+ - (Optional) Playwright for browser automation
41
+
42
+ ## Installation
43
+
44
+ ### 1. Clone and build
45
+
46
+ ```bash
47
+ git clone https://github.com/kcdjmaxx/HomarUScc.git
48
+ cd HomarUScc
49
+ npm install
50
+ npm run build
51
+ ```
52
+
53
+ ### 2. Configure
54
+
55
+ ```bash
56
+ mkdir -p ~/.homaruscc
57
+ cp config.example.json ~/.homaruscc/config.json
58
+ ```
59
+
60
+ Edit `~/.homaruscc/config.json` with your settings (see `config.example.json` for all options including default timers and browser config). Tokens use `${ENV_VAR}` syntax so secrets stay in your `.env` file:
61
+
62
+ ```bash
63
+ cp .env.example ~/.homaruscc/.env
64
+ # Edit ~/.homaruscc/.env with your actual tokens
65
+ ```
66
+
67
+ ### 3. Set up identity
68
+
69
+ HomarUScc loads identity files from `~/.homaruscc/identity/` to shape your assistant's personality, what it knows about you, and its evolving self-knowledge.
70
+
71
+ ```bash
72
+ mkdir -p ~/.homaruscc/identity
73
+ cp identity.example/*.md ~/.homaruscc/identity/
74
+ ```
75
+
76
+ Edit `soul.md` (agent personality) and `user.md` (what the agent knows about you) to make it yours. The starter kit includes templates for all five identity files. The agent updates them over time:
77
+
78
+ | File | Purpose | Who writes it |
79
+ |------|---------|---------------|
80
+ | `soul.md` | Core identity, values, self-evolution | Human (core) + Agent (below Self-Evolution line) |
81
+ | `user.md` | User context and preferences | Human |
82
+ | `state.md` | Session mood, unresolved items, emotional continuity | Agent (end of each session) |
83
+ | `preferences.md` | Emergent preferences discovered through experience | Agent (during reflection) |
84
+ | `disagreements.md` | Times the agent pushed back or had a different opinion | Agent (when it happens) |
85
+
86
+ Journal entries are written to `~/.homaruscc/journal/YYYY-MM-DD.md` during daily reflection.
87
+
88
+ ### Dream Cycle
89
+
90
+ At 3am each night, the agent runs a three-phase dream cycle inspired by [neuroscience research on sleep functions](dreams.md):
91
+
92
+ 1. **Memory consolidation** — reviews recent memories, identifies what's important vs noise
93
+ 2. **Associative dreaming** — pulls random memories from different topics/periods and force-connects them, producing fuzzy, impressionistic fragments
94
+ 3. **Overfitting prevention** — challenges an established preference or belief to test its flexibility
95
+
96
+ Dream output is deliberately stream-of-consciousness and stored in the unified memory index under `dreams/` with 0.5x weight (always ranks below waking memories) and a 7-day decay half-life (fades quickly). When dream fragments surface during waking interactions, the agent notes the origin explicitly.
97
+
98
+ A morning digest summarizes interesting dream fragments via Telegram.
99
+
100
+ The waking personality loop and dream cycle run on different timescales but feed into each other:
101
+
102
+ ```
103
+ WAKING LOOP DREAM CYCLE (3am)
104
+ ========== =================
105
+
106
+ ┌─→ Experience ──────────────────────────→ Raw material for dreams
107
+ │ | |
108
+ │ v v
109
+ │ Memory ←──────────── Memory Consolidation ────┘
110
+ │ | (re-rank, strengthen, |
111
+ │ | let weak ones decay) |
112
+ │ v v
113
+ │ Reflection ←──────── Emotional Processing ────┘
114
+ │ | (revisit charged moments |
115
+ │ | from new angles) |
116
+ │ v v
117
+ │ Self-knowledge ←──── Overfitting Prevention ──┘
118
+ │ | (challenge established |
119
+ │ | patterns/preferences) |
120
+ │ v v
121
+ │ Identity ←────────── Associative Dreaming ────┘
122
+ │ evolution (novel connections feed
123
+ │ | into convictions,
124
+ │ v soul.md evolution)
125
+ └── Changed
126
+ behavior
127
+ ```
128
+
129
+ The waking loop is **fast and reactive** — every interaction triggers observe, reflect, learn, evolve, act differently. The dream cycle is **slow and integrative** — once per night, processing the accumulated day into deeper patterns. This dual-timescale architecture mirrors how human memory consolidation works: waking learning is specific, sleep consolidation is general.
130
+
131
+ ### 4. Add to Claude Code
132
+
133
+ Register HomarUScc as an MCP server in `.claude/settings.json`:
134
+
135
+ ```json
136
+ {
137
+ "mcpServers": {
138
+ "homaruscc": {
139
+ "command": "node",
140
+ "args": ["/absolute/path/to/HomarUScc/dist/mcp-proxy.js"],
141
+ "env": {
142
+ "HOMARUSCC_CONFIG": "~/.homaruscc/config.json"
143
+ }
144
+ }
145
+ }
146
+ }
147
+ ```
148
+
149
+ Restart Claude Code. HomarUScc's tools will appear automatically. The proxy auto-spawns the backend process — no manual startup needed.
150
+
151
+ ## MCP Tools
152
+
153
+ | Tool | Description |
154
+ |------|-------------|
155
+ | `telegram_send` | Send a message to a Telegram chat |
156
+ | `telegram_read` | Read recent incoming messages |
157
+ | `memory_search` | Hybrid vector + full-text search over stored content |
158
+ | `memory_store` | Store and index content for later retrieval |
159
+ | `timer_schedule` | Schedule cron, interval, or one-shot timers |
160
+ | `timer_cancel` | Cancel a scheduled timer |
161
+ | `dashboard_send` | Send a message to the web dashboard |
162
+ | `get_status` | System status (channels, memory, timers, queue) |
163
+ | `get_events` | Recent event history |
164
+ | `wait_for_event` | Long-poll for events (blocks until something happens) |
165
+ | `browser_navigate` | Navigate to a URL |
166
+ | `browser_snapshot` | Get the accessibility tree of the current page |
167
+ | `browser_screenshot` | Take a screenshot (base64 PNG) |
168
+ | `browser_click` | Click an element by CSS selector |
169
+ | `browser_type` | Type into an input by CSS selector |
170
+ | `browser_evaluate` | Execute JavaScript in the page |
171
+ | `browser_content` | Get page text content |
172
+ | `run_tool` | Execute any registered tool (bash, read, write, edit, glob, grep, git, web) |
173
+
174
+ ## MCP Resources
175
+
176
+ | URI | Description |
177
+ |-----|-------------|
178
+ | `identity://soul` | Soul.md content |
179
+ | `identity://user` | User.md content |
180
+ | `identity://state` | State.md — agent mood, session continuity |
181
+ | `config://current` | Current config (secrets redacted) |
182
+ | `events://recent` | Recent event history |
183
+
184
+ ## Dashboard
185
+
186
+ When enabled, the dashboard runs on `http://localhost:3120` with:
187
+
188
+ - Chat interface (messages route through Claude Code via MCP)
189
+ - Real-time event log via WebSocket
190
+ - System status panel
191
+ - Memory search browser
192
+
193
+ ### Dashboard Development
194
+
195
+ ```bash
196
+ cd dashboard
197
+ npm install
198
+ npm run dev # Dev server on :3121, proxies API to :3120
199
+ ```
200
+
201
+ ## Runtime Directories
202
+
203
+ HomarUScc creates runtime data that's gitignored and stays local:
204
+
205
+ | Directory | Purpose |
206
+ |-----------|---------|
207
+ | `user/context/` | Facts the assistant learns about you |
208
+ | `user/corrections/` | Corrections you've made (so it doesn't repeat mistakes) |
209
+ | `user/preferences/` | Your stated preferences |
210
+ | `system/` | System-level learned knowledge |
211
+ | `~/.homaruscc/memory/` | Vector + FTS search index (SQLite) |
212
+ | `~/.homaruscc/identity/` | Agent identity files (soul, user, state, preferences, disagreements) |
213
+ | `~/.homaruscc/journal/` | Daily reflection journal entries (indexed by memory system) |
214
+ | `~/.homaruscc/browser-data/` | Persistent browser sessions |
215
+
216
+ ## Event Loop
217
+
218
+ The `bin/event-loop` script provides a zero-token idle loop. It long-polls the dashboard HTTP API at the OS level — no Claude tokens are consumed while waiting. When events arrive, it returns control to Claude Code.
219
+
220
+ ```bash
221
+ bash homaruscc/bin/event-loop
222
+ ```
223
+
224
+ ### Identity Digest
225
+
226
+ Each wake delivers identity context so the agent stays in character. To avoid burning ~3K tokens on every event, the server uses two delivery modes:
227
+
228
+ - **Normal wake** (~200 tokens) — a compressed digest: agent name, core behavioral rules, and last session mood. Enough for personality consistency without the full payload.
229
+ - **Post-compaction wake** (~3K tokens) — full identity: `soul.md`, `user.md`, and `state.md`. Sent once after compaction when the original identity context has been compressed away.
230
+
231
+ The `PreCompact` hook sets a flag on the backend. The next `/api/wait` response checks the flag and returns the appropriate format. The flag is consumed once — subsequent wakes return the digest until the next compaction.
232
+
233
+ ## Compaction Resilience
234
+
235
+ Claude Code compresses conversation history when the context window fills up. Without mitigation, the post-compaction agent loses track of what it was doing. HomarUScc handles this with two mechanisms:
236
+
237
+ **Session checkpoint** — Before compaction, the agent saves its current task context (topic, recent decisions, in-progress work, modified files) to `~/.homaruscc/checkpoint.json` via `POST /api/checkpoint`. After compaction, the post-compact context injection includes this checkpoint so the new instance knows exactly where things left off. The checkpoint is cleared at session end.
238
+
239
+ **Delivery watermark** — The server tracks the timestamp of the last event delivered to Claude Code. After compaction, the event loop resumes from the watermark instead of replaying old events. This prevents the "bad loop" problem where a post-compaction agent re-handles messages it already responded to.
240
+
241
+ Both are wired into the `PreCompact` Claude Code hook that calls `/api/pre-compact`. Add this to your project's `.claude/settings.local.json`:
242
+
243
+ ```json
244
+ {
245
+ "hooks": {
246
+ "PreCompact": [
247
+ {
248
+ "hooks": [
249
+ {
250
+ "type": "command",
251
+ "command": "curl -s http://127.0.0.1:3120/api/pre-compact"
252
+ }
253
+ ]
254
+ }
255
+ ]
256
+ }
257
+ }
258
+ ```
259
+
260
+ ## Agent Dispatch
261
+
262
+ For tasks that would consume significant context (research, multi-file processing, mini-spec workflows), the agent can dispatch work to background agents instead of doing it inline:
263
+
264
+ 1. Register the agent with `POST /api/agents` (returns 429 if at max capacity)
265
+ 2. Spawn a background Task agent via Claude Code's Task tool
266
+ 3. Return to the event loop immediately — stay responsive to messages
267
+ 4. When the agent completes, an `agent_completed` event flows through the event system
268
+ 5. Summarize results and send to the user
269
+
270
+ Max concurrent agents is configurable via `agents.maxConcurrent` in config (default 3). The agent registry tracks running/completed/failed agents and includes them in post-compaction context so background work isn't lost across compaction boundaries.
271
+
272
+ **Completion detection:** The backend polls output files of registered agents every 5 seconds. When it detects a completion marker (stable file mtime for 10+ seconds, or `"stop_reason":"end_turn"` in the output), it emits an `agent_completed` event that wakes the main event loop. No manual checking needed — results arrive as events.
273
+
274
+ ## Architecture
275
+
276
+ HomarUScc is a fork of HomarUS with the agent loop, model router, and HTTP API removed. Claude Code handles all reasoning; HomarUScc just provides the I/O layer.
277
+
278
+ Key source files:
279
+
280
+ | File | Purpose |
281
+ |------|---------|
282
+ | `src/homaruscc.ts` | Event loop orchestrator |
283
+ | `src/mcp-proxy.ts` | MCP stdio proxy — auto-spawns backend, forwards tool calls over HTTP |
284
+ | `src/backend.ts` | Standalone backend process (Telegram, timers, dashboard, memory) |
285
+ | `src/mcp-server.ts` | Legacy single-process MCP server (unused in two-process mode) |
286
+ | `src/mcp-tools.ts` | MCP tool definitions |
287
+ | `src/mcp-resources.ts` | MCP resource definitions |
288
+ | `src/config.ts` | Config loader with env var resolution and hot-reload |
289
+ | `src/telegram-adapter.ts` | Telegram long-polling adapter |
290
+ | `src/dashboard-server.ts` | Express + WebSocket dashboard server |
291
+ | `src/dashboard-adapter.ts` | Dashboard channel adapter |
292
+ | `src/memory-index.ts` | SQLite + sqlite-vec hybrid search with dream-aware scoring |
293
+ | `src/compaction-manager.ts` | Auto-flush memory before context compaction |
294
+ | `src/session-checkpoint.ts` | Save/restore task context across compaction |
295
+ | `src/agent-registry.ts` | Track background agents with capacity limits |
296
+ | `src/transcript-logger.ts` | Session transcript capture and indexing |
297
+ | `src/identity-manager.ts` | Identity loader (soul.md, user.md, state.md) |
298
+ | `src/timer-service.ts` | Cron, interval, and one-shot timers |
299
+ | `src/browser-service.ts` | Playwright browser automation |
300
+ | `src/skill-manager.ts` | Hot-loadable skill plugins |
301
+ | `src/tool-registry.ts` | Tool registration and policy enforcement |
302
+ | `src/tools/` | Built-in tools (bash, fs, git, web, memory) |
303
+ | `dashboard/` | React + Vite SPA |
304
+
305
+ ## License
306
+
307
+ MIT - see [LICENSE](LICENSE)
package/bin/event-loop ADDED
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env bash
2
+ # Zero-token event loop for HomarUScc
3
+ # Long-polls the dashboard HTTP API — blocks at OS level, zero Claude tokens while idle.
4
+ # Returns to Claude only when real events arrive.
5
+ #
6
+ # The server maintains a delivery watermark — events already delivered via /api/wait
7
+ # are never re-delivered. This survives context compaction without client-side state.
8
+
9
+ set -euo pipefail
10
+
11
+ # Read dashboard port from config, default 3120
12
+ CONFIG="$HOME/.homaruscc/config.json"
13
+ if [[ -f "$CONFIG" ]] && command -v jq &>/dev/null; then
14
+ PORT=$(jq -r '.dashboard.port // 3120' "$CONFIG" 2>/dev/null || echo 3120)
15
+ else
16
+ PORT=3120
17
+ fi
18
+
19
+ BASE="http://127.0.0.1:${PORT}"
20
+ TIMEOUT=120
21
+
22
+ # Prevent duplicate listeners
23
+ PIDFILE="/tmp/homaruscc-event-loop.pid"
24
+ if [[ -f "$PIDFILE" ]]; then
25
+ OLD_PID=$(cat "$PIDFILE" 2>/dev/null || true)
26
+ if [[ -n "$OLD_PID" ]] && kill -0 "$OLD_PID" 2>/dev/null; then
27
+ echo "Killing previous event-loop (PID $OLD_PID)"
28
+ kill "$OLD_PID" 2>/dev/null || true
29
+ sleep 0.5
30
+ fi
31
+ fi
32
+ echo $$ > "$PIDFILE"
33
+ trap 'rm -f "$PIDFILE"' EXIT
34
+
35
+ while true; do
36
+ HTTP_CODE=$(curl -s -o /tmp/homaruscc-wait-response.json -w "%{http_code}" \
37
+ "${BASE}/api/wait?timeout=${TIMEOUT}" 2>/dev/null) || {
38
+ echo "ERROR: curl failed — is the HomarUScc dashboard running on port ${PORT}?"
39
+ exit 1
40
+ }
41
+
42
+ case "$HTTP_CODE" in
43
+ 204)
44
+ # Timeout, no events — loop again (zero tokens)
45
+ continue
46
+ ;;
47
+ 200)
48
+ # Events arrived — print and return to Claude
49
+ cat /tmp/homaruscc-wait-response.json
50
+ echo ""
51
+ echo "---"
52
+ echo "Event loop paused. Handle the events above, then restart: bash \"\$PWD/bin/event-loop\""
53
+ exit 0
54
+ ;;
55
+ *)
56
+ echo "ERROR: Unexpected HTTP ${HTTP_CODE} from /api/wait"
57
+ exit 1
58
+ ;;
59
+ esac
60
+ done
@@ -0,0 +1,55 @@
1
+ {
2
+ "channels": {
3
+ "telegram": {
4
+ "token": "${TELEGRAM_BOT_TOKEN}",
5
+ "allowedChatIds": []
6
+ }
7
+ },
8
+ "memory": {
9
+ "embedding": {
10
+ "provider": "ollama",
11
+ "model": "nomic-embed-text",
12
+ "baseUrl": "http://127.0.0.1:11434/v1"
13
+ },
14
+ "extraPaths": []
15
+ },
16
+ "identity": {
17
+ "dir": "~/.homaruscc/identity"
18
+ },
19
+ "dashboard": {
20
+ "port": 3120,
21
+ "enabled": true
22
+ },
23
+ "timers": {
24
+ "enabled": true,
25
+ "defaults": [
26
+ {
27
+ "name": "morning-briefing",
28
+ "type": "cron",
29
+ "schedule": "0 9 * * *",
30
+ "timezone": "America/Chicago",
31
+ "prompt": "Good morning routine: 1) Search memory for user patterns and preferences. 2) Check recent events for anything unresolved. 3) Send a Telegram message with: a greeting, any pending items, and proactive suggestions."
32
+ },
33
+ {
34
+ "name": "evening-reflection",
35
+ "type": "cron",
36
+ "schedule": "0 21 * * *",
37
+ "timezone": "America/Chicago",
38
+ "prompt": "Daily reflection: 1) Review today's interactions. 2) Identify new user preferences, corrections, or patterns. 3) Store insights in memory. 4) Send a brief summary if there's something actionable for tomorrow."
39
+ },
40
+ {
41
+ "name": "nightly-dream",
42
+ "type": "cron",
43
+ "schedule": "0 3 * * *",
44
+ "timezone": "America/Chicago",
45
+ "prompt": "Dream cycle: 1) Memory consolidation — search recent topics, note what matters. 2) Associative dreaming — search diverse queries, force-connect results into impressionistic fragments. 3) Overfitting prevention — challenge one established belief. Store output as dreams/YYYY-MM-DD.md. Send a brief dream digest via Telegram."
46
+ }
47
+ ]
48
+ },
49
+ "browser": {
50
+ "enabled": false,
51
+ "headless": true,
52
+ "viewport": { "width": 1280, "height": 720 },
53
+ "timeout": 30000
54
+ }
55
+ }
@@ -0,0 +1,38 @@
1
+ import type { Event, Logger } from "./types.js";
2
+ export type AgentStatus = "running" | "completed" | "failed";
3
+ export interface AgentEntry {
4
+ id: string;
5
+ description: string;
6
+ status: AgentStatus;
7
+ startTime: number;
8
+ outputFile?: string;
9
+ result?: string;
10
+ error?: string;
11
+ }
12
+ export declare class AgentRegistry {
13
+ private agents;
14
+ private maxConcurrent;
15
+ private emitFn;
16
+ private logger;
17
+ private pollIntervalMs;
18
+ private pollTimer;
19
+ constructor(logger: Logger, maxConcurrent?: number, pollIntervalMs?: number);
20
+ setEmitter(fn: (event: Event) => void): void;
21
+ register(id: string, description: string, outputFile?: string): boolean;
22
+ getAll(): AgentEntry[];
23
+ get(id: string): AgentEntry | null;
24
+ complete(id: string, result: string): void;
25
+ fail(id: string, error: string): void;
26
+ cleanup(id: string): void;
27
+ getAvailableSlots(): number;
28
+ getActiveCount(): number;
29
+ startPolling(): void;
30
+ stopPolling(): void;
31
+ pollAgents(): void;
32
+ private checkAgentFile;
33
+ private readTail;
34
+ private extractSummary;
35
+ private resolve;
36
+ private emit;
37
+ }
38
+ //# sourceMappingURL=agent-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-registry.d.ts","sourceRoot":"","sources":["../src/agent-registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE7D,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAWD,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,MAAM,CAAyC;IACvD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO,CAAC,SAAS,CAA+C;gBAEpD,MAAM,EAAE,MAAM,EAAE,aAAa,SAAI,EAAE,cAAc,SAAO;IAMpE,UAAU,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;IAI5C,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO;IAmBvE,MAAM,IAAI,UAAU,EAAE;IAItB,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAKlC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAY1C,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAYrC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIzB,iBAAiB,IAAI,MAAM;IAI3B,cAAc,IAAI,MAAM;IASxB,YAAY,IAAI,IAAI;IAWpB,WAAW,IAAI,IAAI;IASnB,UAAU,IAAI,IAAI;IAiBlB,OAAO,CAAC,cAAc;IAqCtB,OAAO,CAAC,QAAQ;IAoBhB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,OAAO;IASf,OAAO,CAAC,IAAI;CAcb"}