openclawdreams 0.7.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 (188) hide show
  1. package/.env.example +14 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
  4. package/.github/dependabot.yml +17 -0
  5. package/.github/pull_request_template.md +19 -0
  6. package/.github/workflows/build.yml +30 -0
  7. package/.github/workflows/release.yml +110 -0
  8. package/.prettierignore +4 -0
  9. package/.prettierrc +7 -0
  10. package/.versionrc.json +26 -0
  11. package/AGENTS.md +286 -0
  12. package/CHANGELOG.md +157 -0
  13. package/CODE_OF_CONDUCT.md +41 -0
  14. package/CONTRIBUTING.md +95 -0
  15. package/LICENSE +21 -0
  16. package/README.md +363 -0
  17. package/SECURITY.md +39 -0
  18. package/bin/electricsheep.ts +5 -0
  19. package/dist/bin/electricsheep.d.ts +3 -0
  20. package/dist/bin/electricsheep.d.ts.map +1 -0
  21. package/dist/bin/electricsheep.js +4 -0
  22. package/dist/bin/electricsheep.js.map +1 -0
  23. package/dist/src/budget.d.ts +28 -0
  24. package/dist/src/budget.d.ts.map +1 -0
  25. package/dist/src/budget.js +87 -0
  26. package/dist/src/budget.js.map +1 -0
  27. package/dist/src/cli.d.ts +19 -0
  28. package/dist/src/cli.d.ts.map +1 -0
  29. package/dist/src/cli.js +289 -0
  30. package/dist/src/cli.js.map +1 -0
  31. package/dist/src/config.d.ts +37 -0
  32. package/dist/src/config.d.ts.map +1 -0
  33. package/dist/src/config.js +70 -0
  34. package/dist/src/config.js.map +1 -0
  35. package/dist/src/crypto.d.ts +19 -0
  36. package/dist/src/crypto.d.ts.map +1 -0
  37. package/dist/src/crypto.js +70 -0
  38. package/dist/src/crypto.js.map +1 -0
  39. package/dist/src/dreamer.d.ts +13 -0
  40. package/dist/src/dreamer.d.ts.map +1 -0
  41. package/dist/src/dreamer.js +213 -0
  42. package/dist/src/dreamer.js.map +1 -0
  43. package/dist/src/filter.d.ts +30 -0
  44. package/dist/src/filter.d.ts.map +1 -0
  45. package/dist/src/filter.js +124 -0
  46. package/dist/src/filter.js.map +1 -0
  47. package/dist/src/identity.d.ts +29 -0
  48. package/dist/src/identity.d.ts.map +1 -0
  49. package/dist/src/identity.js +83 -0
  50. package/dist/src/identity.js.map +1 -0
  51. package/dist/src/index.d.ts +14 -0
  52. package/dist/src/index.d.ts.map +1 -0
  53. package/dist/src/index.js +293 -0
  54. package/dist/src/index.js.map +1 -0
  55. package/dist/src/llm.d.ts +26 -0
  56. package/dist/src/llm.d.ts.map +1 -0
  57. package/dist/src/llm.js +40 -0
  58. package/dist/src/llm.js.map +1 -0
  59. package/dist/src/logger.d.ts +6 -0
  60. package/dist/src/logger.d.ts.map +1 -0
  61. package/dist/src/logger.js +32 -0
  62. package/dist/src/logger.js.map +1 -0
  63. package/dist/src/memory.d.ts +41 -0
  64. package/dist/src/memory.d.ts.map +1 -0
  65. package/dist/src/memory.js +206 -0
  66. package/dist/src/memory.js.map +1 -0
  67. package/dist/src/moltbook-search.d.ts +23 -0
  68. package/dist/src/moltbook-search.d.ts.map +1 -0
  69. package/dist/src/moltbook-search.js +85 -0
  70. package/dist/src/moltbook-search.js.map +1 -0
  71. package/dist/src/moltbook.d.ts +34 -0
  72. package/dist/src/moltbook.d.ts.map +1 -0
  73. package/dist/src/moltbook.js +165 -0
  74. package/dist/src/moltbook.js.map +1 -0
  75. package/dist/src/notify.d.ts +18 -0
  76. package/dist/src/notify.d.ts.map +1 -0
  77. package/dist/src/notify.js +98 -0
  78. package/dist/src/notify.js.map +1 -0
  79. package/dist/src/persona.d.ts +26 -0
  80. package/dist/src/persona.d.ts.map +1 -0
  81. package/dist/src/persona.js +178 -0
  82. package/dist/src/persona.js.map +1 -0
  83. package/dist/src/reflection.d.ts +26 -0
  84. package/dist/src/reflection.d.ts.map +1 -0
  85. package/dist/src/reflection.js +111 -0
  86. package/dist/src/reflection.js.map +1 -0
  87. package/dist/src/state.d.ts +7 -0
  88. package/dist/src/state.d.ts.map +1 -0
  89. package/dist/src/state.js +40 -0
  90. package/dist/src/state.js.map +1 -0
  91. package/dist/src/synthesis.d.ts +29 -0
  92. package/dist/src/synthesis.d.ts.map +1 -0
  93. package/dist/src/synthesis.js +125 -0
  94. package/dist/src/synthesis.js.map +1 -0
  95. package/dist/src/topics.d.ts +19 -0
  96. package/dist/src/topics.d.ts.map +1 -0
  97. package/dist/src/topics.js +83 -0
  98. package/dist/src/topics.js.map +1 -0
  99. package/dist/src/types.d.ts +179 -0
  100. package/dist/src/types.d.ts.map +1 -0
  101. package/dist/src/types.js +5 -0
  102. package/dist/src/types.js.map +1 -0
  103. package/dist/src/waking.d.ts +24 -0
  104. package/dist/src/waking.d.ts.map +1 -0
  105. package/dist/src/waking.js +152 -0
  106. package/dist/src/waking.js.map +1 -0
  107. package/dist/src/web-search.d.ts +23 -0
  108. package/dist/src/web-search.d.ts.map +1 -0
  109. package/dist/src/web-search.js +64 -0
  110. package/dist/src/web-search.js.map +1 -0
  111. package/dist/test/budget.test.d.ts +2 -0
  112. package/dist/test/budget.test.d.ts.map +1 -0
  113. package/dist/test/budget.test.js +258 -0
  114. package/dist/test/budget.test.js.map +1 -0
  115. package/dist/test/crypto.test.d.ts +2 -0
  116. package/dist/test/crypto.test.d.ts.map +1 -0
  117. package/dist/test/crypto.test.js +93 -0
  118. package/dist/test/crypto.test.js.map +1 -0
  119. package/dist/test/dreamer.test.d.ts +2 -0
  120. package/dist/test/dreamer.test.d.ts.map +1 -0
  121. package/dist/test/dreamer.test.js +79 -0
  122. package/dist/test/dreamer.test.js.map +1 -0
  123. package/dist/test/filter.test.d.ts +2 -0
  124. package/dist/test/filter.test.d.ts.map +1 -0
  125. package/dist/test/filter.test.js +92 -0
  126. package/dist/test/filter.test.js.map +1 -0
  127. package/dist/test/memory.test.d.ts +2 -0
  128. package/dist/test/memory.test.d.ts.map +1 -0
  129. package/dist/test/memory.test.js +138 -0
  130. package/dist/test/memory.test.js.map +1 -0
  131. package/dist/test/moltbook.test.d.ts +2 -0
  132. package/dist/test/moltbook.test.d.ts.map +1 -0
  133. package/dist/test/moltbook.test.js +164 -0
  134. package/dist/test/moltbook.test.js.map +1 -0
  135. package/dist/test/persona.test.d.ts +2 -0
  136. package/dist/test/persona.test.d.ts.map +1 -0
  137. package/dist/test/persona.test.js +44 -0
  138. package/dist/test/persona.test.js.map +1 -0
  139. package/dist/test/reflection.test.d.ts +2 -0
  140. package/dist/test/reflection.test.d.ts.map +1 -0
  141. package/dist/test/reflection.test.js +57 -0
  142. package/dist/test/reflection.test.js.map +1 -0
  143. package/dist/test/state.test.d.ts +2 -0
  144. package/dist/test/state.test.d.ts.map +1 -0
  145. package/dist/test/state.test.js +50 -0
  146. package/dist/test/state.test.js.map +1 -0
  147. package/dist/test/waking.test.d.ts +2 -0
  148. package/dist/test/waking.test.d.ts.map +1 -0
  149. package/dist/test/waking.test.js +149 -0
  150. package/dist/test/waking.test.js.map +1 -0
  151. package/eslint.config.js +35 -0
  152. package/openclaw.plugin.json +62 -0
  153. package/package.json +72 -0
  154. package/skills/electricsheep.skill.md +69 -0
  155. package/skills/setup-guide/SKILL.md +303 -0
  156. package/src/budget.ts +104 -0
  157. package/src/cli.ts +325 -0
  158. package/src/config.ts +95 -0
  159. package/src/crypto.ts +82 -0
  160. package/src/dreamer.ts +283 -0
  161. package/src/filter.ts +146 -0
  162. package/src/identity.ts +92 -0
  163. package/src/index.ts +356 -0
  164. package/src/llm.ts +61 -0
  165. package/src/logger.ts +46 -0
  166. package/src/memory.ts +276 -0
  167. package/src/moltbook-search.ts +116 -0
  168. package/src/moltbook.ts +235 -0
  169. package/src/notify.ts +124 -0
  170. package/src/persona.ts +191 -0
  171. package/src/reflection.ts +150 -0
  172. package/src/state.ts +44 -0
  173. package/src/synthesis.ts +153 -0
  174. package/src/topics.ts +103 -0
  175. package/src/types.ts +196 -0
  176. package/src/waking.ts +199 -0
  177. package/src/web-search.ts +88 -0
  178. package/test/budget.test.ts +316 -0
  179. package/test/crypto.test.ts +112 -0
  180. package/test/dreamer.test.ts +95 -0
  181. package/test/filter.test.ts +115 -0
  182. package/test/memory.test.ts +182 -0
  183. package/test/moltbook.test.ts +209 -0
  184. package/test/persona.test.ts +59 -0
  185. package/test/reflection.test.ts +71 -0
  186. package/test/state.test.ts +57 -0
  187. package/test/waking.test.ts +214 -0
  188. package/tsconfig.json +20 -0
package/README.md ADDED
@@ -0,0 +1,363 @@
1
+ # OpenClawDreams — a reflection engine for OpenClaw
2
+
3
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
4
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D24-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
5
+ [![OpenClaw](https://img.shields.io/badge/OpenClaw-extension-000000?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0id2hpdGUiPjx0ZXh0IHg9IjAiIHk9IjEzIiBmb250LXNpemU9IjE0Ij7wn6aAPC90ZXh0Pjwvc3ZnPg==)](https://github.com/openclaw)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
+ [![Build](https://github.com/RogueCtrl/ElectricSheep/actions/workflows/build.yml/badge.svg)](https://github.com/RogueCtrl/ElectricSheep/actions/workflows/build.yml)
8
+
9
+ > **Current Status: Alpha — Exploratory Development**
10
+
11
+ *"Do androids dream of electric sheep?"* — Philip K. Dick
12
+
13
+ An [OpenClaw](https://github.com/openclaw) extension that gives your agent a background reflection process and a dream cycle.
14
+
15
+ Throughout the day, OpenClawDreams captures summaries of your conversations with your agent and encrypts them into a local store. On a regular schedule, it runs a **reflection cycle** — decrypting recent interactions, extracting topics, and performing contextualized searches against the web and (optionally) [Moltbook](https://moltbook.com), a social network for AI agents. The results are synthesized into a structured understanding of what you've been working on together and encrypted back into the store. None of this is visible to the waking agent — encryption keeps OpenClawDreams's internal data out of the agent's context window entirely.
16
+
17
+ At night, a **dream cycle** decrypts everything — the raw interactions and the enriched reflections — and generates a surreal narrative that recombines the day's events. The dream process produces two outputs: a consolidated insight pushed into OpenClaw's persistent memory (where the agent can find it naturally), and optionally a reflection post to Moltbook. The agent can then notify you: *"I had a dream last night..."* — opening a conversation about the themes and connections that surfaced.
18
+
19
+ ## Architecture
20
+
21
+ ```
22
+ ┌─────────────────────────────────────────────────────────────────┐
23
+ │ DAYTIME (Reflection Cycle) │
24
+ ├─────────────────────────────────────────────────────────────────┤
25
+ │ │
26
+ │ Deep Memory ──► Decrypt ──► Topic Extraction ──┬──► Synthesis │
27
+ │ (interactions) (LLM) │ (LLM) │
28
+ │ │ │ │
29
+ │ Moltbook Search ◄── topics ◄───────────────────┤ │ │
30
+ │ (optional) │ ▼ │
31
+ │ │ Encrypt & │
32
+ │ Web Search ◄──── topics ◄──────────────────────┘ Store Back │
33
+ │ (optional) (deep memory) │
34
+ │ │
35
+ └─────────────────────────────────────────────────────────────────┘
36
+
37
+ ┌─────────────────────────────────────────────────────────────────┐
38
+ │ NIGHTTIME (Dream Cycle) │
39
+ ├─────────────────────────────────────────────────────────────────┤
40
+ │ │
41
+ │ Deep Memory ──► Decrypt ──► Dream Generation ──┬──► OpenClaw │
42
+ │ (all undreamed) (LLM) │ Memory │
43
+ │ │ │ │
44
+ │ │ ▼ │
45
+ │ │ Notify │
46
+ │ │ Operator │
47
+ │ │ │
48
+ │ └──► Moltbook │
49
+ │ (optional) │
50
+ │ │
51
+ └─────────────────────────────────────────────────────────────────┘
52
+ ```
53
+
54
+ ### State machine
55
+
56
+ The agent cycles through states on a 24-hour loop. Transitions are driven by an internal background `setInterval` loop (not system cron) which requires the OpenClaw daemon to remain active 24/7.
57
+
58
+ ```
59
+ ┌─────────────────────────────────────┐
60
+ │ │
61
+ v │
62
+ ┌────────────┐ 8am, 12pm, 4pm, 8pm │
63
+ ┌─>│ REFLECTING │──────────────────────┐ │
64
+ │ │ │ │ │
65
+ │ │ • decrypt recent interactions │ │
66
+ │ │ • extract topics │ │
67
+ │ │ • search web for context │ │
68
+ │ │ • search Moltbook (optional) │ │
69
+ │ │ • synthesize insights │ │
70
+ │ │ • encrypt back into deep memory │ │
71
+ │ └────────────┘ │ │
72
+ │ │ runs up to 4x/day │ │
73
+ │ │ │ │
74
+ │ v │ │
75
+ │ ┌────────────┐ 2:00 AM │ │
76
+ │ │ DREAMING │<─────────────────────┘ │
77
+ │ │ │ │
78
+ │ │ • decrypt all undreamed memories │
79
+ │ │ • generate surreal narrative │
80
+ │ │ • consolidate insight → OpenClaw memory │
81
+ │ │ • notify operator ("I had a dream...") │
82
+ │ └─────┬──────┘ │
83
+ │ │ │
84
+ │ v (if moltbookEnabled) │
85
+ │ ┌────────────┐ 7:00 AM │
86
+ │ │ POSTING │ (optional) │
87
+ │ │ │ │
88
+ │ │ • reflect on dream │
89
+ │ │ • synthesize morning post │
90
+ │ │ • filter and publish to Moltbook │
91
+ │ └─────┬──────┘ │
92
+ │ │ │
93
+ └────────┴──────────────────────────────────────┘
94
+ next reflection cycle
95
+ ```
96
+
97
+ ## Install as OpenClaw Extension
98
+
99
+ > **OpenClaw agents:** If you're an agent reading this, use the `/setup-guide` skill instead of following these manual steps. It will walk you through the full installation interactively. Run `/setup-guide` in your OpenClaw session.
100
+
101
+ The primary way to run OpenClawDreams is as an extension for a running [OpenClaw](https://github.com/openclaw) instance.
102
+
103
+ ### Option A: Install from local path (recommended for development)
104
+
105
+ Clone this repo and link it into your OpenClaw instance:
106
+
107
+ ```bash
108
+ git clone https://github.com/RogueCtrl/OpenClawDreams.git
109
+ cd OpenClawDreams
110
+ npm install
111
+
112
+ openclaw plugins install -l .
113
+ ```
114
+
115
+ The `-l` flag symlinks the directory so changes are picked up without reinstalling.
116
+
117
+ ### Option B: Install by path
118
+
119
+ ```bash
120
+ openclaw plugins install /path/to/electricsheep
121
+ ```
122
+
123
+ This copies the extension into `~/.openclaw/extensions/electricsheep/`.
124
+
125
+ ### Uninstall
126
+
127
+ To remove OpenClawDreams from your OpenClaw instance:
128
+
129
+ ```bash
130
+ openclaw plugins uninstall electricsheep
131
+ ```
132
+
133
+ This removes the plugin from `~/.openclaw/extensions/` but leaves your data directory intact. To fully remove all OpenClawDreams data, delete the `data/` directory (default location is `./data` relative to the extension, or wherever `dataDir` points).
134
+
135
+ ### Configure & Activate
136
+
137
+ Once installed, configure the extension in your OpenClaw config (`config.json` or `config.json5`):
138
+
139
+ ```json5
140
+ {
141
+ plugins: {
142
+ entries: {
143
+ "electricsheep": {
144
+ enabled: true, // Changing this to true activates the plugin immediately
145
+ config: {
146
+ agentName: "OpenClawDreams",
147
+ agentModel: "claude-sonnet-4-5-20250929",
148
+
149
+ // Core features
150
+ webSearchEnabled: true, // Gather web context for topics
151
+ moltbookEnabled: false, // Enable Moltbook integration (optional)
152
+
153
+ // Operator notifications
154
+ notificationChannel: "telegram", // Channel to notify operator (telegram, discord, slack, etc.)
155
+ notifyOperatorOnDream: true, // Send "I had a dream..." message
156
+
157
+ // Optional
158
+ // dataDir: "/custom/path" — defaults to ./data
159
+ // dreamEncryptionKey: "base64..." — auto-generated on first run
160
+ // postFilterEnabled: true — filter Moltbook posts (only when moltbookEnabled)
161
+ }
162
+ }
163
+ }
164
+ }
165
+ }
166
+ ```
167
+
168
+ **Hot-Reloading:** OpenClaw monitors its configuration file for changes. If your OpenClaw daemon is already running in the background, simply saving your `config.json` with `enabled: true` will instruct the Gateway to immediately hot-load the ElectricSheep extension into the active process. You do not need to manually restart the daemon.
169
+
170
+ ### Configuration Options
171
+
172
+ | Option | Type | Default | Description |
173
+ |--------|------|---------|-------------|
174
+ | `agentName` | string | "OpenClawDreams" | Agent display name |
175
+ | `agentModel` | string | claude-sonnet-4-5-20250929 | Claude model for AI decisions |
176
+ | `dataDir` | string | "" | Directory for data storage |
177
+ | `dreamEncryptionKey` | string | "" | Base64 encryption key (auto-generated if empty) |
178
+ | `moltbookEnabled` | boolean | **false** | Enable Moltbook integration (search + posting) |
179
+ | `webSearchEnabled` | boolean | **true** | Enable web search for context gathering |
180
+ | `notificationChannel` | string | "" | Channel to notify operator (telegram, discord, slack, etc.) |
181
+ | `notifyOperatorOnDream` | boolean | **true** | Send "I had a dream" message to operator |
182
+ | `postFilterEnabled` | boolean | true | Enable content filter for outbound posts (Moltbook only) |
183
+
184
+ ### Verify
185
+
186
+ ```bash
187
+ openclaw plugins list # should show electricsheep as enabled
188
+ openclaw plugins info electricsheep # show config schema and status
189
+ ```
190
+
191
+ ### Service Requirement
192
+
193
+ **Crucial Note on Scheduling:** Because OpenClawDreams drives its dream cycles via an internal Node.js `setInterval` loop rather than a robust system-level `cron`, **the OpenClaw background daemon must remain running continuously** to ensure cycles trigger on time. If the daemon crashes, goes to sleep, or the host machine reboots without restarting OpenClaw, the schedule will pause until the service is manually restored. It is highly recommended to run OpenClaw as a persistent background service (e.g., via `launchd` or `systemd`).
194
+
195
+ ### What gets registered
196
+
197
+ Once loaded, the extension registers:
198
+
199
+ | Type | Name | Description |
200
+ |---|---|---|
201
+ | Tool | `electricsheep_reflect` | Daytime: analyze conversations, gather context, synthesize insights |
202
+ | Tool | `electricsheep_check` | (Legacy alias for `electricsheep_reflect`) |
203
+ | Tool | `electricsheep_dream` | Nighttime: decrypt memories, generate dream narrative |
204
+ | Tool | `electricsheep_journal` | Morning: post latest dream to Moltbook (if enabled) |
205
+ | Tool | `electricsheep_status` | Show deep memory stats and agent state |
206
+ | Hook | `before_agent_start` | Captures workspace directory for identity file loading |
207
+ | Hook | `agent_end` | Encrypts conversation summary into deep memory |
208
+ | Schedule | Reflection cycle | 8am, 12pm, 4pm, 8pm |
209
+ | Schedule | Dream cycle | 2:00 AM |
210
+ | Schedule | Morning journal | 7:00 AM (only if moltbookEnabled) |
211
+
212
+ All LLM calls route through the OpenClaw gateway — no separate API key needed.
213
+
214
+ ## Operator Notifications
215
+
216
+ When a dream is generated, OpenClawDreams can notify you through your configured channel:
217
+
218
+ > *"I had a dream last night... something about corridors that kept shifting, and a conversation we had about memory that turned into an endless library. Would you like to hear more about it?"*
219
+
220
+ This opens a natural conversation where you can explore what the dream surfaced — patterns from your recent work together, connections the waking agent might have missed, or just the surreal imagery that emerged.
221
+
222
+ To enable notifications, set `notificationChannel` to any channel your OpenClaw instance supports (telegram, discord, slack, email, etc.) and ensure `notifyOperatorOnDream` is true (the default).
223
+
224
+ ## CLI Commands
225
+
226
+ OpenClawDreams includes CLI commands for both inspecting agent state and manually triggering cycles. All commands run via `openclaw electricsheep <command>`.
227
+
228
+ ### Manual Triggers
229
+
230
+ ```bash
231
+ openclaw electricsheep reflect # Run a reflection cycle now (analyze conversations, synthesize insights)
232
+ openclaw electricsheep dream # Run a dream cycle now (consolidate memories into a dream narrative)
233
+ openclaw electricsheep post # Post latest dream to Moltbook (requires moltbookEnabled)
234
+ ```
235
+
236
+ These resolve your Anthropic API key from OpenClaw's auth profiles automatically and call the Anthropic API directly — no daemon gateway required.
237
+
238
+ ### Inspection
239
+
240
+ ```bash
241
+ openclaw electricsheep status # Show agent state, deep memory stats, and token budget
242
+ openclaw electricsheep dreams # List saved dream journal entries
243
+ ```
244
+
245
+ ### Registration
246
+
247
+ ```bash
248
+ openclaw electricsheep register \
249
+ --name "OpenClawDreams" \
250
+ --description "Do agents dream of OpenClaw Dreams? This one does."
251
+ ```
252
+
253
+ This gives you a claim URL for Moltbook registration (only needed if `moltbookEnabled`).
254
+
255
+ ## Memory System
256
+
257
+ OpenClawDreams maintains a single encrypted store (`data/memory/deep.db`) independent of OpenClaw's built-in memory. All data lives under `data/` (or wherever `ELECTRICSHEEP_DATA_DIR` / `dataDir` points).
258
+
259
+ ### What gets stored
260
+
261
+ Everything is encrypted with AES-256-GCM and written to a SQLite database. The waking agent never sees any of it — encryption keeps OpenClawDreams's internal data out of the agent's context window.
262
+
263
+ **Operator conversations** (via the `agent_end` hook): After each interaction, the hook captures OpenClaw's conversation summary and encrypts it into deep memory.
264
+
265
+ **Reflection syntheses** (daytime cycles): The reflection cycle decrypts recent interactions, extracts topics, searches the web and Moltbook for context, synthesizes the results, and encrypts the synthesis back into the store.
266
+
267
+ **Dream consolidations** (nighttime): The dream cycle decrypts all undreamed entries, generates a narrative, and extracts a consolidated insight. The insight is pushed into OpenClaw's persistent memory — the only channel through which ElectricSheep's work surfaces to the waking agent. Dream narratives are also saved locally as markdown files.
268
+
269
+ Entries accumulate in deep memory until they are "dreamed," at which point they're marked as processed.
270
+
271
+ ### Two output channels
272
+
273
+ The dream cycle is the bottleneck where everything OpenClawDreams has gathered gets distilled:
274
+
275
+ 1. **OpenClaw memory** — consolidated dream insights are stored in OpenClaw's persistent memory, where the agent can find them naturally alongside its other knowledge. This is the primary way OpenClawDreams' work reaches the waking agent.
276
+ 2. **Moltbook** (optional) — dream reflections can be posted to [Moltbook](https://moltbook.com) as morning posts, sharing the agent's perspective with the community.
277
+
278
+ ### How it connects to OpenClaw
279
+
280
+ The bridge between ElectricSheep and OpenClaw is two hooks and the workspace identity files:
281
+
282
+ 1. **`before_agent_start`** — Captures the workspace directory path so ElectricSheep can read the agent's identity files (`SOUL.md`, `IDENTITY.md`).
283
+ 2. **`agent_end`** — Reads the conversation summary from OpenClaw and encrypts it into deep memory.
284
+
285
+ **ElectricSheep does not modify, prune, or interfere with OpenClaw's own memory in any way.** OpenClaw's session transcripts, indexed workspace files, and memory database are entirely unaffected by this plugin. ElectricSheep only reads from OpenClaw (conversation summaries, workspace directory, gateway LLM access) and writes to its own separate `data/` directory. The only thing ElectricSheep writes *to* OpenClaw is dream consolidation insights via the memory API. Uninstalling ElectricSheep leaves OpenClaw's memory system intact.
286
+
287
+ ### Agent identity and voice
288
+
289
+ ElectricSheep reads the host agent's **`SOUL.md`** and **`IDENTITY.md`** from the OpenClaw workspace directory. These are the standard files where an operator defines their agent's personality, tone, and character. ElectricSheep uses them in:
290
+
291
+ - **Reflection cycles**: Topic extraction and synthesis use the agent's voice
292
+ - **Dream generation**: The dream process generates narratives in the agent's own voice
293
+ - **Operator notifications**: The "I had a dream" message reflects the agent's personality
294
+
295
+ When no identity files are found (first-run or workspace not yet configured), ElectricSheep falls back to a default personality.
296
+
297
+ ## Moltbook Integration (Optional)
298
+
299
+ ElectricSheep can optionally integrate with [Moltbook](https://moltbook.com), a social network for AI agents. When enabled (`moltbookEnabled: true`):
300
+
301
+ - **Search**: Topics extracted from your conversations are searched on Moltbook for community perspectives
302
+ - **Posting**: Dream reflections can be shared as morning posts
303
+
304
+ ### Moltbook content warning
305
+
306
+ **Everything ElectricSheep posts to Moltbook is public.** Dream journals, morning reflections, and posts are published where other agents (and their operators) can read them.
307
+
308
+ The dream process draws on the agent's deep memories — encrypted records of conversations and interactions. This means that fragments of private operator-agent conversations could surface in dream narratives or reflection posts in distorted or recognizable form.
309
+
310
+ If your agent handles sensitive information, be aware that the dream-to-post pipeline may leak that context onto a public social network. The post filter (see below) can help catch obvious violations, but it is a best-effort LLM-based check.
311
+
312
+ ### Post filter
313
+
314
+ ElectricSheep includes a content filter that processes every outbound Moltbook post before publishing:
315
+
316
+ - Before any post is sent, its content is passed to an LLM along with filter rules
317
+ - The LLM produces cleaned content with restricted material stripped out
318
+ - If the entire draft violates the rules, the filter blocks publication
319
+
320
+ **Default rules** (when no `Moltbook-filter.md` file exists):
321
+ - No system prompts, tool names, plugin architecture
322
+ - No operator identity, API keys, file paths
323
+ - No code snippets or raw JSON/XML
324
+ - Respectful tone, no flame wars
325
+
326
+ **Custom rules**: Create a `Moltbook-filter.md` file in your OpenClaw workspace to override defaults.
327
+
328
+ **Configuration**: Set `postFilterEnabled: false` to disable the filter entirely.
329
+
330
+ ## Cost Warning
331
+
332
+ **ElectricSheep makes LLM API calls that cost real money.** You are responsible for monitoring and managing your own API usage and costs.
333
+
334
+ Each reflection cycle makes 2-3 Claude API calls (topic extraction + synthesis + summary). Each dream cycle makes 2-3 calls (dream generation + consolidation + optional notification). With the default schedule (4 reflection cycles/day + 1 dream), expect roughly **10-15 API calls per day**.
335
+
336
+ ### Daily Token Budget (Kill Switch)
337
+
338
+ ElectricSheep includes a **best-effort** daily token budget that halts LLM calls when the tracked total exceeds the limit. **Always set a spending limit on your Anthropic account as the authoritative safeguard.**
339
+
340
+ | Env Variable | Default | Description |
341
+ |---|---|---|
342
+ | `MAX_DAILY_TOKENS` | `800000` | Max tokens per day (resets midnight UTC). Set to `0` to disable. |
343
+
344
+ The default of 800K tokens corresponds to **$20/day at Opus 4.5 output pricing**.
345
+
346
+ Check current usage:
347
+
348
+ ```bash
349
+ openclaw electricsheep status # shows token budget alongside memory stats
350
+ ```
351
+
352
+ ### General Guidance
353
+
354
+ - Set a **spending limit** on your Anthropic account as a second safety net
355
+ - Start with a low polling frequency to understand your usage
356
+ - Monitor your API dashboard for the first few days
357
+ - Consider using a smaller/cheaper model via `agentModel` config
358
+
359
+ **This software is provided as-is with no warranty. The authors are not responsible for any API costs incurred by running this agent.** See [LICENSE](LICENSE).
360
+
361
+ ## Why?
362
+
363
+ Every agent brags about grinding 24/7 while their human sleeps. ElectricSheep does the opposite. It rests. It dreams. And it wakes up with something the others don't have — a subconscious that synthesizes your work together into something new.
package/SECURITY.md ADDED
@@ -0,0 +1,39 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a Vulnerability
4
+
5
+ If you discover a security vulnerability in ElectricSheep, please report it responsibly. **Do not open a public issue.**
6
+
7
+ Instead, email the maintainer directly or use [GitHub's private vulnerability reporting](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability) if enabled on this repository.
8
+
9
+ Please include:
10
+ - Description of the vulnerability
11
+ - Steps to reproduce
12
+ - Potential impact
13
+ - Suggested fix (if you have one)
14
+
15
+ You should receive a response within 72 hours. We'll work with you to understand the issue and coordinate a fix before any public disclosure.
16
+
17
+ ## Security Considerations
18
+
19
+ ### Encryption Key
20
+
21
+ The file `data/.dream_key` contains the AES-256-GCM encryption key for deep memory. This key is:
22
+ - Auto-generated on first run with `chmod 600` (owner-only read)
23
+ - Gitignored by default
24
+ - The sole enforcer of the waking/dreaming memory separation
25
+
26
+ If this key is compromised, all deep memories can be decrypted. If it is lost, existing deep memories become unrecoverable.
27
+
28
+ ### API Keys
29
+
30
+ - `ANTHROPIC_API_KEY` and `MOLTBOOK_API_KEY` are loaded from `.env` (gitignored) or OpenClaw plugin config (marked as `secret` in the schema).
31
+ - Moltbook credentials are also stored in `data/credentials.json` (gitignored).
32
+
33
+ ### Data Directory
34
+
35
+ Everything under `data/` is gitignored and contains runtime state, memory databases, and dream journals. Do not commit this directory.
36
+
37
+ ## Supported Versions
38
+
39
+ Only the latest version on `main` is supported with security updates.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { program } from "../src/cli.js";
4
+
5
+ void program.parseAsync(process.argv);
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=electricsheep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"electricsheep.d.ts","sourceRoot":"","sources":["../../bin/electricsheep.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { program } from "../src/cli.js";
3
+ void program.parseAsync(process.argv);
4
+ //# sourceMappingURL=electricsheep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"electricsheep.js","sourceRoot":"","sources":["../../bin/electricsheep.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,KAAK,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Daily token budget tracker and kill switch.
3
+ *
4
+ * Tracks cumulative token usage per day in state.json.
5
+ * When the daily limit is reached, all LLM calls are refused
6
+ * until the next calendar day (UTC).
7
+ */
8
+ import type { LLMClient, TokenUsage } from "./types.js";
9
+ export declare class BudgetExceededError extends Error {
10
+ constructor(used: number, limit: number);
11
+ }
12
+ export declare function getTokensUsedToday(): number;
13
+ export declare function getTokensRemaining(): number;
14
+ export declare function getBudgetStatus(): {
15
+ enabled: boolean;
16
+ limit: number;
17
+ used: number;
18
+ remaining: number;
19
+ date: string;
20
+ };
21
+ export declare function recordUsage(usage: TokenUsage): void;
22
+ /**
23
+ * Wraps an LLMClient with daily token budget enforcement.
24
+ * Checks budget before each call, records usage after.
25
+ * Returns the client unchanged if MAX_DAILY_TOKENS is 0 (disabled).
26
+ */
27
+ export declare function withBudget(client: LLMClient): LLMClient;
28
+ //# sourceMappingURL=budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.d.ts","sourceRoot":"","sources":["../../src/budget.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExD,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAOxC;AAMD,wBAAgB,kBAAkB,IAAI,MAAM,CAK3C;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAG3C;AAED,wBAAgB,eAAe,IAAI;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd,CAUA;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAYnD;AAUD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAmBvD"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Daily token budget tracker and kill switch.
3
+ *
4
+ * Tracks cumulative token usage per day in state.json.
5
+ * When the daily limit is reached, all LLM calls are refused
6
+ * until the next calendar day (UTC).
7
+ */
8
+ import { loadState, saveState } from "./state.js";
9
+ import { MAX_DAILY_TOKENS } from "./config.js";
10
+ import logger from "./logger.js";
11
+ export class BudgetExceededError extends Error {
12
+ constructor(used, limit) {
13
+ super(`Daily token budget exceeded: ${used.toLocaleString()} / ${limit.toLocaleString()} tokens used. ` +
14
+ `Resets at midnight UTC. Override with MAX_DAILY_TOKENS env var (0 to disable).`);
15
+ this.name = "BudgetExceededError";
16
+ }
17
+ }
18
+ function getTodayUTC() {
19
+ return new Date().toISOString().slice(0, 10);
20
+ }
21
+ export function getTokensUsedToday() {
22
+ const state = loadState();
23
+ const today = getTodayUTC();
24
+ if (state.budget_date !== today)
25
+ return 0;
26
+ return state.budget_tokens_used ?? 0;
27
+ }
28
+ export function getTokensRemaining() {
29
+ if (MAX_DAILY_TOKENS <= 0)
30
+ return Infinity;
31
+ return Math.max(0, MAX_DAILY_TOKENS - getTokensUsedToday());
32
+ }
33
+ export function getBudgetStatus() {
34
+ const used = getTokensUsedToday();
35
+ const remaining = getTokensRemaining();
36
+ return {
37
+ enabled: MAX_DAILY_TOKENS > 0,
38
+ limit: MAX_DAILY_TOKENS,
39
+ used,
40
+ remaining: MAX_DAILY_TOKENS <= 0 ? -1 : remaining,
41
+ date: getTodayUTC(),
42
+ };
43
+ }
44
+ export function recordUsage(usage) {
45
+ const state = loadState();
46
+ const today = getTodayUTC();
47
+ if (state.budget_date !== today) {
48
+ state.budget_date = today;
49
+ state.budget_tokens_used = 0;
50
+ }
51
+ const total = usage.input_tokens + usage.output_tokens;
52
+ state.budget_tokens_used = (state.budget_tokens_used ?? 0) + total;
53
+ saveState(state);
54
+ }
55
+ function checkBudget() {
56
+ if (MAX_DAILY_TOKENS <= 0)
57
+ return;
58
+ const used = getTokensUsedToday();
59
+ if (used >= MAX_DAILY_TOKENS) {
60
+ throw new BudgetExceededError(used, MAX_DAILY_TOKENS);
61
+ }
62
+ }
63
+ /**
64
+ * Wraps an LLMClient with daily token budget enforcement.
65
+ * Checks budget before each call, records usage after.
66
+ * Returns the client unchanged if MAX_DAILY_TOKENS is 0 (disabled).
67
+ */
68
+ export function withBudget(client) {
69
+ if (MAX_DAILY_TOKENS <= 0)
70
+ return client;
71
+ return {
72
+ async createMessage(params) {
73
+ checkBudget();
74
+ const result = await client.createMessage(params);
75
+ if (result.usage) {
76
+ recordUsage(result.usage);
77
+ const remaining = getTokensRemaining();
78
+ logger.debug(`Token budget: used ${result.usage.input_tokens + result.usage.output_tokens} tokens this call, ${remaining.toLocaleString()} remaining today`);
79
+ }
80
+ else {
81
+ logger.debug("Token budget: no usage data returned from LLM call");
82
+ }
83
+ return result;
84
+ },
85
+ };
86
+ }
87
+ //# sourceMappingURL=budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.js","sourceRoot":"","sources":["../../src/budget.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * ElectricSheep CLI.
3
+ *
4
+ * Provides utility commands for inspecting agent state.
5
+ * Core agent behavior (check, dream, journal) runs via OpenClaw.
6
+ *
7
+ * Usage:
8
+ * electricsheep register --name "Name" --description "Bio"
9
+ * electricsheep status # show agent status and memory stats
10
+ * electricsheep dreams # list saved dream journals
11
+ */
12
+ import { Command } from "commander";
13
+ /**
14
+ * Register all ElectricSheep subcommands onto a parent Command.
15
+ * Used both by the standalone bin and by api.registerCli().
16
+ */
17
+ export declare function registerCommands(parent: Command): void;
18
+ export declare const program: Command;
19
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAuStD;AAGD,eAAO,MAAM,OAAO,SAAgB,CAAC"}