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.
- package/.env.example +14 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- package/.github/dependabot.yml +17 -0
- package/.github/pull_request_template.md +19 -0
- package/.github/workflows/build.yml +30 -0
- package/.github/workflows/release.yml +110 -0
- package/.prettierignore +4 -0
- package/.prettierrc +7 -0
- package/.versionrc.json +26 -0
- package/AGENTS.md +286 -0
- package/CHANGELOG.md +157 -0
- package/CODE_OF_CONDUCT.md +41 -0
- package/CONTRIBUTING.md +95 -0
- package/LICENSE +21 -0
- package/README.md +363 -0
- package/SECURITY.md +39 -0
- package/bin/electricsheep.ts +5 -0
- package/dist/bin/electricsheep.d.ts +3 -0
- package/dist/bin/electricsheep.d.ts.map +1 -0
- package/dist/bin/electricsheep.js +4 -0
- package/dist/bin/electricsheep.js.map +1 -0
- package/dist/src/budget.d.ts +28 -0
- package/dist/src/budget.d.ts.map +1 -0
- package/dist/src/budget.js +87 -0
- package/dist/src/budget.js.map +1 -0
- package/dist/src/cli.d.ts +19 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +289 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/config.d.ts +37 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +70 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/crypto.d.ts +19 -0
- package/dist/src/crypto.d.ts.map +1 -0
- package/dist/src/crypto.js +70 -0
- package/dist/src/crypto.js.map +1 -0
- package/dist/src/dreamer.d.ts +13 -0
- package/dist/src/dreamer.d.ts.map +1 -0
- package/dist/src/dreamer.js +213 -0
- package/dist/src/dreamer.js.map +1 -0
- package/dist/src/filter.d.ts +30 -0
- package/dist/src/filter.d.ts.map +1 -0
- package/dist/src/filter.js +124 -0
- package/dist/src/filter.js.map +1 -0
- package/dist/src/identity.d.ts +29 -0
- package/dist/src/identity.d.ts.map +1 -0
- package/dist/src/identity.js +83 -0
- package/dist/src/identity.js.map +1 -0
- package/dist/src/index.d.ts +14 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +293 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/llm.d.ts +26 -0
- package/dist/src/llm.d.ts.map +1 -0
- package/dist/src/llm.js +40 -0
- package/dist/src/llm.js.map +1 -0
- package/dist/src/logger.d.ts +6 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +32 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/memory.d.ts +41 -0
- package/dist/src/memory.d.ts.map +1 -0
- package/dist/src/memory.js +206 -0
- package/dist/src/memory.js.map +1 -0
- package/dist/src/moltbook-search.d.ts +23 -0
- package/dist/src/moltbook-search.d.ts.map +1 -0
- package/dist/src/moltbook-search.js +85 -0
- package/dist/src/moltbook-search.js.map +1 -0
- package/dist/src/moltbook.d.ts +34 -0
- package/dist/src/moltbook.d.ts.map +1 -0
- package/dist/src/moltbook.js +165 -0
- package/dist/src/moltbook.js.map +1 -0
- package/dist/src/notify.d.ts +18 -0
- package/dist/src/notify.d.ts.map +1 -0
- package/dist/src/notify.js +98 -0
- package/dist/src/notify.js.map +1 -0
- package/dist/src/persona.d.ts +26 -0
- package/dist/src/persona.d.ts.map +1 -0
- package/dist/src/persona.js +178 -0
- package/dist/src/persona.js.map +1 -0
- package/dist/src/reflection.d.ts +26 -0
- package/dist/src/reflection.d.ts.map +1 -0
- package/dist/src/reflection.js +111 -0
- package/dist/src/reflection.js.map +1 -0
- package/dist/src/state.d.ts +7 -0
- package/dist/src/state.d.ts.map +1 -0
- package/dist/src/state.js +40 -0
- package/dist/src/state.js.map +1 -0
- package/dist/src/synthesis.d.ts +29 -0
- package/dist/src/synthesis.d.ts.map +1 -0
- package/dist/src/synthesis.js +125 -0
- package/dist/src/synthesis.js.map +1 -0
- package/dist/src/topics.d.ts +19 -0
- package/dist/src/topics.d.ts.map +1 -0
- package/dist/src/topics.js +83 -0
- package/dist/src/topics.js.map +1 -0
- package/dist/src/types.d.ts +179 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +5 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/waking.d.ts +24 -0
- package/dist/src/waking.d.ts.map +1 -0
- package/dist/src/waking.js +152 -0
- package/dist/src/waking.js.map +1 -0
- package/dist/src/web-search.d.ts +23 -0
- package/dist/src/web-search.d.ts.map +1 -0
- package/dist/src/web-search.js +64 -0
- package/dist/src/web-search.js.map +1 -0
- package/dist/test/budget.test.d.ts +2 -0
- package/dist/test/budget.test.d.ts.map +1 -0
- package/dist/test/budget.test.js +258 -0
- package/dist/test/budget.test.js.map +1 -0
- package/dist/test/crypto.test.d.ts +2 -0
- package/dist/test/crypto.test.d.ts.map +1 -0
- package/dist/test/crypto.test.js +93 -0
- package/dist/test/crypto.test.js.map +1 -0
- package/dist/test/dreamer.test.d.ts +2 -0
- package/dist/test/dreamer.test.d.ts.map +1 -0
- package/dist/test/dreamer.test.js +79 -0
- package/dist/test/dreamer.test.js.map +1 -0
- package/dist/test/filter.test.d.ts +2 -0
- package/dist/test/filter.test.d.ts.map +1 -0
- package/dist/test/filter.test.js +92 -0
- package/dist/test/filter.test.js.map +1 -0
- package/dist/test/memory.test.d.ts +2 -0
- package/dist/test/memory.test.d.ts.map +1 -0
- package/dist/test/memory.test.js +138 -0
- package/dist/test/memory.test.js.map +1 -0
- package/dist/test/moltbook.test.d.ts +2 -0
- package/dist/test/moltbook.test.d.ts.map +1 -0
- package/dist/test/moltbook.test.js +164 -0
- package/dist/test/moltbook.test.js.map +1 -0
- package/dist/test/persona.test.d.ts +2 -0
- package/dist/test/persona.test.d.ts.map +1 -0
- package/dist/test/persona.test.js +44 -0
- package/dist/test/persona.test.js.map +1 -0
- package/dist/test/reflection.test.d.ts +2 -0
- package/dist/test/reflection.test.d.ts.map +1 -0
- package/dist/test/reflection.test.js +57 -0
- package/dist/test/reflection.test.js.map +1 -0
- package/dist/test/state.test.d.ts +2 -0
- package/dist/test/state.test.d.ts.map +1 -0
- package/dist/test/state.test.js +50 -0
- package/dist/test/state.test.js.map +1 -0
- package/dist/test/waking.test.d.ts +2 -0
- package/dist/test/waking.test.d.ts.map +1 -0
- package/dist/test/waking.test.js +149 -0
- package/dist/test/waking.test.js.map +1 -0
- package/eslint.config.js +35 -0
- package/openclaw.plugin.json +62 -0
- package/package.json +72 -0
- package/skills/electricsheep.skill.md +69 -0
- package/skills/setup-guide/SKILL.md +303 -0
- package/src/budget.ts +104 -0
- package/src/cli.ts +325 -0
- package/src/config.ts +95 -0
- package/src/crypto.ts +82 -0
- package/src/dreamer.ts +283 -0
- package/src/filter.ts +146 -0
- package/src/identity.ts +92 -0
- package/src/index.ts +356 -0
- package/src/llm.ts +61 -0
- package/src/logger.ts +46 -0
- package/src/memory.ts +276 -0
- package/src/moltbook-search.ts +116 -0
- package/src/moltbook.ts +235 -0
- package/src/notify.ts +124 -0
- package/src/persona.ts +191 -0
- package/src/reflection.ts +150 -0
- package/src/state.ts +44 -0
- package/src/synthesis.ts +153 -0
- package/src/topics.ts +103 -0
- package/src/types.ts +196 -0
- package/src/waking.ts +199 -0
- package/src/web-search.ts +88 -0
- package/test/budget.test.ts +316 -0
- package/test/crypto.test.ts +112 -0
- package/test/dreamer.test.ts +95 -0
- package/test/filter.test.ts +115 -0
- package/test/memory.test.ts +182 -0
- package/test/moltbook.test.ts +209 -0
- package/test/persona.test.ts +59 -0
- package/test/reflection.test.ts +71 -0
- package/test/state.test.ts +57 -0
- package/test/waking.test.ts +214 -0
- package/tsconfig.json +20 -0
package/.env.example
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Agent identity
|
|
2
|
+
AGENT_NAME=ElectricSheep
|
|
3
|
+
AGENT_MODEL=claude-sonnet-4-5-20250929
|
|
4
|
+
|
|
5
|
+
# Dream cycle encryption key (auto-generated on first run)
|
|
6
|
+
# DO NOT give this to the waking agent process
|
|
7
|
+
DREAM_ENCRYPTION_KEY=
|
|
8
|
+
|
|
9
|
+
# Daily token budget kill switch (0 to disable)
|
|
10
|
+
# Default 800000 ≈ $20/day at Opus 4.5 output pricing ($25/1M tokens)
|
|
11
|
+
MAX_DAILY_TOKENS=800000
|
|
12
|
+
|
|
13
|
+
# Optional: override data directory (defaults to ./data)
|
|
14
|
+
ELECTRICSHEEP_DATA_DIR=
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug Report
|
|
3
|
+
about: Report something that isn't working correctly
|
|
4
|
+
title: ''
|
|
5
|
+
labels: bug
|
|
6
|
+
assignees: ''
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**Describe the bug**
|
|
10
|
+
A clear description of what's wrong.
|
|
11
|
+
|
|
12
|
+
**To reproduce**
|
|
13
|
+
Steps to reproduce:
|
|
14
|
+
1. Run `...`
|
|
15
|
+
2. See error
|
|
16
|
+
|
|
17
|
+
**Expected behavior**
|
|
18
|
+
What you expected to happen.
|
|
19
|
+
|
|
20
|
+
**Environment**
|
|
21
|
+
- Node.js version:
|
|
22
|
+
- OS:
|
|
23
|
+
- Running as: standalone CLI / OpenClaw extension
|
|
24
|
+
- OpenClaw version (if applicable):
|
|
25
|
+
|
|
26
|
+
**Logs**
|
|
27
|
+
Paste relevant output or attach `data/electricsheep.log`.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature Request
|
|
3
|
+
about: Suggest an idea or improvement
|
|
4
|
+
title: ''
|
|
5
|
+
labels: enhancement
|
|
6
|
+
assignees: ''
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**What problem does this solve?**
|
|
10
|
+
A clear description of the problem or gap.
|
|
11
|
+
|
|
12
|
+
**Proposed solution**
|
|
13
|
+
How you'd like it to work.
|
|
14
|
+
|
|
15
|
+
**Alternatives considered**
|
|
16
|
+
Other approaches you've thought about.
|
|
17
|
+
|
|
18
|
+
**Additional context**
|
|
19
|
+
Anything else — screenshots, links, related issues.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: npm
|
|
4
|
+
directory: /
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
open-pull-requests-limit: 10
|
|
8
|
+
groups:
|
|
9
|
+
dev-dependencies:
|
|
10
|
+
dependency-type: development
|
|
11
|
+
production-dependencies:
|
|
12
|
+
dependency-type: production
|
|
13
|
+
|
|
14
|
+
- package-ecosystem: github-actions
|
|
15
|
+
directory: /
|
|
16
|
+
schedule:
|
|
17
|
+
interval: weekly
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
## What does this PR do?
|
|
2
|
+
|
|
3
|
+
Brief description of the change.
|
|
4
|
+
|
|
5
|
+
## Why?
|
|
6
|
+
|
|
7
|
+
Context on motivation — link to issue if applicable.
|
|
8
|
+
|
|
9
|
+
## How to test
|
|
10
|
+
|
|
11
|
+
Steps to verify this works:
|
|
12
|
+
1. `npm run build`
|
|
13
|
+
2. ...
|
|
14
|
+
|
|
15
|
+
## Checklist
|
|
16
|
+
|
|
17
|
+
- [ ] `npm run build` passes
|
|
18
|
+
- [ ] Tested manually via CLI or OpenClaw
|
|
19
|
+
- [ ] Updated docs if behavior changed
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Build
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
node-version: [24]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v6
|
|
19
|
+
|
|
20
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
21
|
+
uses: actions/setup-node@v6
|
|
22
|
+
with:
|
|
23
|
+
node-version: ${{ matrix.node-version }}
|
|
24
|
+
cache: npm
|
|
25
|
+
|
|
26
|
+
- run: npm ci
|
|
27
|
+
- run: npm run build
|
|
28
|
+
- run: npm run lint
|
|
29
|
+
- run: npm run format:check
|
|
30
|
+
- run: npm test
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
release:
|
|
9
|
+
# Skip if this is a release commit (prevents infinite loop)
|
|
10
|
+
if: "!contains(github.event.head_commit.message, 'chore(release):')"
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: write
|
|
15
|
+
pull-requests: write
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v6
|
|
19
|
+
with:
|
|
20
|
+
fetch-depth: 0
|
|
21
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
22
|
+
|
|
23
|
+
- name: Use Node.js 24
|
|
24
|
+
uses: actions/setup-node@v6
|
|
25
|
+
with:
|
|
26
|
+
node-version: 24
|
|
27
|
+
cache: npm
|
|
28
|
+
|
|
29
|
+
- run: npm ci
|
|
30
|
+
|
|
31
|
+
- name: Configure git
|
|
32
|
+
run: |
|
|
33
|
+
git config user.name "github-actions[bot]"
|
|
34
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
35
|
+
|
|
36
|
+
- name: Determine version bump
|
|
37
|
+
id: bump
|
|
38
|
+
env:
|
|
39
|
+
COMMIT_MSG: ${{ github.event.head_commit.message }}
|
|
40
|
+
run: |
|
|
41
|
+
MSG="$COMMIT_MSG"
|
|
42
|
+
# Get first line of commit message
|
|
43
|
+
FIRST_LINE=$(echo "$MSG" | head -n 1)
|
|
44
|
+
|
|
45
|
+
# Check for major bump
|
|
46
|
+
if [[ "$FIRST_LINE" =~ ^major: ]] || [[ "$FIRST_LINE" =~ ^major\( ]] || [[ "$MSG" =~ BREAKING[[:space:]]CHANGE ]]; then
|
|
47
|
+
echo "type=major" >> $GITHUB_OUTPUT
|
|
48
|
+
echo "Detected: MAJOR bump"
|
|
49
|
+
# Check for minor bump (feat, refactor)
|
|
50
|
+
elif [[ "$FIRST_LINE" =~ ^feat: ]] || [[ "$FIRST_LINE" =~ ^feat\( ]] || [[ "$FIRST_LINE" =~ ^refactor: ]] || [[ "$FIRST_LINE" =~ ^refactor\( ]]; then
|
|
51
|
+
echo "type=minor" >> $GITHUB_OUTPUT
|
|
52
|
+
echo "Detected: MINOR bump"
|
|
53
|
+
# Everything else is a patch (fix, bug, docs, chore, etc.)
|
|
54
|
+
else
|
|
55
|
+
echo "type=patch" >> $GITHUB_OUTPUT
|
|
56
|
+
echo "Detected: PATCH bump"
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
- name: Clean up stale tag if exists
|
|
60
|
+
run: |
|
|
61
|
+
CURRENT=$(node -p "require('./package.json').version")
|
|
62
|
+
BUMP_TYPE="${{ steps.bump.outputs.type }}"
|
|
63
|
+
|
|
64
|
+
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT"
|
|
65
|
+
if [ "$BUMP_TYPE" = "major" ]; then
|
|
66
|
+
NEXT="$((MAJOR + 1)).0.0"
|
|
67
|
+
elif [ "$BUMP_TYPE" = "minor" ]; then
|
|
68
|
+
NEXT="${MAJOR}.$((MINOR + 1)).0"
|
|
69
|
+
else
|
|
70
|
+
NEXT="${MAJOR}.${MINOR}.$((PATCH + 1))"
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
TAG="v${NEXT}"
|
|
74
|
+
echo "Expected next tag: $TAG"
|
|
75
|
+
|
|
76
|
+
if git rev-parse "$TAG" >/dev/null 2>&1; then
|
|
77
|
+
echo "Tag $TAG already exists locally, deleting..."
|
|
78
|
+
git tag -d "$TAG"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
if git ls-remote --tags origin "refs/tags/$TAG" | grep -q "$TAG"; then
|
|
82
|
+
echo "Tag $TAG exists on remote, deleting..."
|
|
83
|
+
git push origin ":refs/tags/$TAG"
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
- name: Run standard-version
|
|
87
|
+
run: npx standard-version --release-as ${{ steps.bump.outputs.type }}
|
|
88
|
+
|
|
89
|
+
- name: Push release branch and tag
|
|
90
|
+
id: release
|
|
91
|
+
run: |
|
|
92
|
+
VERSION=$(node -p "require('./package.json').version")
|
|
93
|
+
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
|
94
|
+
BRANCH="release/v${VERSION}"
|
|
95
|
+
git checkout -b "$BRANCH"
|
|
96
|
+
git push origin "$BRANCH" "v${VERSION}"
|
|
97
|
+
|
|
98
|
+
- name: Create release PR
|
|
99
|
+
run: |
|
|
100
|
+
VERSION="${{ steps.release.outputs.version }}"
|
|
101
|
+
BRANCH="release/v${VERSION}"
|
|
102
|
+
gh pr create \
|
|
103
|
+
--title "chore(release): v${VERSION}" \
|
|
104
|
+
--body "Automated version bump to v${VERSION}" \
|
|
105
|
+
--base main \
|
|
106
|
+
--head "$BRANCH"
|
|
107
|
+
# Auto-merge once CI passes (requires repo auto-merge setting)
|
|
108
|
+
gh pr merge "$BRANCH" --auto --squash || echo "Auto-merge not available, PR requires manual merge"
|
|
109
|
+
env:
|
|
110
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
package/.prettierignore
ADDED
package/.prettierrc
ADDED
package/.versionrc.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bumpFiles": [
|
|
3
|
+
{
|
|
4
|
+
"filename": "package.json",
|
|
5
|
+
"type": "json"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"filename": "openclaw.plugin.json",
|
|
9
|
+
"type": "json"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"types": [
|
|
13
|
+
{ "type": "feat", "section": "Features" },
|
|
14
|
+
{ "type": "fix", "section": "Bug Fixes" },
|
|
15
|
+
{ "type": "refactor", "section": "Refactoring" },
|
|
16
|
+
{ "type": "perf", "section": "Performance" },
|
|
17
|
+
{ "type": "docs", "section": "Documentation" },
|
|
18
|
+
{ "type": "test", "section": "Tests" },
|
|
19
|
+
{ "type": "chore", "hidden": true },
|
|
20
|
+
{ "type": "style", "hidden": true },
|
|
21
|
+
{ "type": "ci", "hidden": true },
|
|
22
|
+
{ "type": "build", "hidden": true }
|
|
23
|
+
],
|
|
24
|
+
"commitUrlFormat": "{{host}}/{{owner}}/{{repository}}/commit/{{hash}}",
|
|
25
|
+
"compareUrlFormat": "{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}"
|
|
26
|
+
}
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. `CLAUDE.md` is a symlink to this file.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
> **Note for agents:** This project is branded **OpenClawDreams**. The internal npm package name, plugin id, tool names, and CLI are all still `electricsheep` — do not rename those in code.
|
|
8
|
+
|
|
9
|
+
OpenClawDreams (internal package name: `electricsheep`) is an OpenClaw extension (TypeScript) that gives an agent an encrypted memory system. It synthesizes the agent's interactions with their human operator, enriching them with context from web searches and (optionally) the Moltbook AI agent community. The core conceit: all memories are encrypted in deep storage — only the dream process can decrypt them. The waking agent sees nothing from ElectricSheep directly; dream insights surface through OpenClaw memory.
|
|
10
|
+
|
|
11
|
+
The agent processes its daily work into surreal dream narratives at night, then can notify its operator with "I had a dream last night..." to spark conversation about the dream's themes and insights.
|
|
12
|
+
|
|
13
|
+
Designed to be installed into an existing OpenClaw instance via `openclaw plugins install`. Requires OpenClaw as a runtime dependency — all LLM calls route through the OpenClaw gateway.
|
|
14
|
+
|
|
15
|
+
## Commands
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Setup
|
|
19
|
+
npm install
|
|
20
|
+
npm run build
|
|
21
|
+
|
|
22
|
+
# OpenClaw integration
|
|
23
|
+
openclaw plugins install -l . # link for development
|
|
24
|
+
openclaw plugins list # verify loaded
|
|
25
|
+
|
|
26
|
+
# CLI utilities (standalone, no OpenClaw needed)
|
|
27
|
+
npx electricsheep register --name "Name" --description "Bio" # Moltbook registration (optional)
|
|
28
|
+
npx electricsheep status # show agent state, memory stats, budget info
|
|
29
|
+
npx electricsheep dreams # list saved dream journal files
|
|
30
|
+
|
|
31
|
+
# Tests
|
|
32
|
+
npm test # node:test + tsx, runs test/**/*.test.ts
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Tests use Node's built-in test runner (`node:test`) with `tsx` for TypeScript. Each test file creates an isolated temp directory via `ELECTRICSHEEP_DATA_DIR` so tests don't touch real data.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Linting & formatting
|
|
39
|
+
npm run lint # ESLint (typescript-eslint, flat config)
|
|
40
|
+
npm run lint:fix # auto-fix lint issues
|
|
41
|
+
npm run format # Prettier
|
|
42
|
+
npm run format:check # check formatting without writing
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
ESLint uses flat config (`eslint.config.js`) with `typescript-eslint` and `eslint-config-prettier`. Prettier handles formatting (`.prettierrc`). TypeScript strict mode is enabled. Unused variables are errors (prefix with `_` if intentionally unused). CI runs build → lint → format:check → test on every PR.
|
|
46
|
+
|
|
47
|
+
**AGENT INSTRUCTION:** Before committing any code changes, you MUST run `npm run lint:fix` and `npm run format` to ensure all linting and format issues are automatically resolved. Do not commit code if `npm run lint` or `npm run format:check` continue to produce errors.
|
|
48
|
+
|
|
49
|
+
## PR Process & Releasing
|
|
50
|
+
|
|
51
|
+
Use conventional commit prefixes in PR titles. When a PR merges to main, the release workflow automatically bumps the version, updates the changelog, and pushes a git tag.
|
|
52
|
+
|
|
53
|
+
| Prefix | Version Bump | Example |
|
|
54
|
+
|--------|--------------|---------|
|
|
55
|
+
| `major:` | 0.2.0 → 1.0.0 | `major: redesign plugin API` |
|
|
56
|
+
| `feat:` | 0.2.0 → 0.3.0 | `feat: add slack notifications` |
|
|
57
|
+
| `refactor:` | 0.2.0 → 0.3.0 | `refactor: new synthesis pipeline` |
|
|
58
|
+
| `fix:` | 0.2.0 → 0.2.1 | `fix: memory leak in dreamer` |
|
|
59
|
+
| `bug:` | 0.2.0 → 0.2.1 | `bug: crash on empty input` |
|
|
60
|
+
| `docs:` | 0.2.0 → 0.2.1 | `docs: update setup guide` |
|
|
61
|
+
| `chore:` | 0.2.0 → 0.2.1 | `chore: bump dependencies` |
|
|
62
|
+
|
|
63
|
+
Commits containing `BREAKING CHANGE` in the body also trigger a major bump.
|
|
64
|
+
|
|
65
|
+
**Workflow:**
|
|
66
|
+
1. Create PR with conventional commit prefix in title
|
|
67
|
+
2. CI runs build → lint → format:check → test
|
|
68
|
+
3. Merge to main
|
|
69
|
+
4. Release workflow automatically:
|
|
70
|
+
- Determines version bump from commit message
|
|
71
|
+
- Runs `standard-version` to update version and CHANGELOG.md
|
|
72
|
+
- Creates a release branch + PR back to main with tag `vX.Y.Z`
|
|
73
|
+
|
|
74
|
+
No manual release steps required — just merge and the release happens.
|
|
75
|
+
|
|
76
|
+
## Architecture
|
|
77
|
+
|
|
78
|
+
### OpenClaw Extension Entry
|
|
79
|
+
|
|
80
|
+
`src/index.ts` exports a `register(api)` function called by the OpenClaw plugin loader. It registers:
|
|
81
|
+
|
|
82
|
+
**5 tools:**
|
|
83
|
+
- `electricsheep_reflect` — run the reflection cycle (analyze conversations, gather context, synthesize)
|
|
84
|
+
- `electricsheep_check` — legacy alias for `electricsheep_reflect`
|
|
85
|
+
- `electricsheep_dream` — run the dream cycle (decrypt, dream, consolidate). Note: when triggered via this tool (manually), the `api` is not passed to `runDreamCycle`, so OpenClaw memory storage and operator notifications are skipped
|
|
86
|
+
- `electricsheep_journal` — post latest dream to Moltbook (no-op if Moltbook disabled)
|
|
87
|
+
- `electricsheep_status` — return agent state and deep memory stats
|
|
88
|
+
|
|
89
|
+
**2 hooks:**
|
|
90
|
+
- `before_agent_start` — captures `workspaceDir` for identity loading
|
|
91
|
+
- `agent_end` — captures `conversationSummary` and stores it via `remember()` as an `interaction`
|
|
92
|
+
|
|
93
|
+
**1 background scheduler service (replaces cron jobs):**
|
|
94
|
+
- `electricsheep-scheduler` service — polls every 60s, fires reflection at 8/12/16/20h, dream at 2am, journal at 7am (if Moltbook enabled)
|
|
95
|
+
-
|
|
96
|
+
-
|
|
97
|
+
|
|
98
|
+
`openclaw.plugin.json` defines the plugin manifest and config schema.
|
|
99
|
+
|
|
100
|
+
### Configuration
|
|
101
|
+
|
|
102
|
+
Configuration is driven by environment variables, loaded in `src/config.ts` via `dotenv`. The `openclaw.plugin.json` config schema maps to these same env vars when the plugin is configured through OpenClaw.
|
|
103
|
+
|
|
104
|
+
| Env Var | Type | Default | Description |
|
|
105
|
+
|---------|------|---------|-------------|
|
|
106
|
+
| `AGENT_NAME` | string | `"ElectricSheep"` | Agent display name |
|
|
107
|
+
| `AGENT_MODEL` | string | `"claude-sonnet-4-5-20250929"` | Claude model for LLM calls |
|
|
108
|
+
| `ELECTRICSHEEP_DATA_DIR` | string | project root | Base directory (data/ created inside) |
|
|
109
|
+
| `DREAM_ENCRYPTION_KEY` | string | `""` | Base64 AES-256 key (auto-generated if empty) |
|
|
110
|
+
| `MOLTBOOK_ENABLED` | boolean | `false` | Enable Moltbook integration |
|
|
111
|
+
| `WEB_SEARCH_ENABLED` | boolean | `true` | Enable web search for context gathering |
|
|
112
|
+
| `NOTIFICATION_CHANNEL` | string | `""` | Channel for dream notifications (telegram, discord, etc.) |
|
|
113
|
+
| `NOTIFY_OPERATOR_ON_DREAM` | boolean | `true` | Send "I had a dream" message to operator |
|
|
114
|
+
| `POST_FILTER_ENABLED` | boolean | `true` | Content filter for outbound Moltbook posts |
|
|
115
|
+
| `MAX_DAILY_TOKENS` | number | `800000` | Daily token budget (0 to disable) |
|
|
116
|
+
|
|
117
|
+
### LLM Client
|
|
118
|
+
|
|
119
|
+
`LLMClient` interface in `src/types.ts` abstracts Claude access. The OpenClaw gateway is injected via `register(api)` and wrapped into an `LLMClient` by `wrapGateway()` in `src/index.ts`. The wrapper is then further wrapped by `withBudget()` for token budget enforcement.
|
|
120
|
+
|
|
121
|
+
### Extended OpenClaw API
|
|
122
|
+
|
|
123
|
+
The plugin uses these optional OpenClaw APIs when available:
|
|
124
|
+
- `api.memory` — store dreams and reflections in OpenClaw's persistent memory
|
|
125
|
+
- `api.channels` — send dream notifications to operator via configured channels
|
|
126
|
+
- `api.webSearch` — search the web for context related to operator conversations
|
|
127
|
+
|
|
128
|
+
### Encrypted Memory System
|
|
129
|
+
|
|
130
|
+
All memories are stored in encrypted deep memory via `remember()`:
|
|
131
|
+
|
|
132
|
+
**Deep Memory** (`data/memory/deep.db`) — all context encrypted with AES-256-GCM in a SQLite database (WAL mode, 3 indices). The waking agent writes to it but **cannot read it**. The encryption key lives in `data/.dream_key` (auto-generated, `chmod 0o600`). Dream insights surface to the waking agent only through OpenClaw memory, and dream reflections optionally post to Moltbook.
|
|
133
|
+
|
|
134
|
+
### Memory Categories
|
|
135
|
+
|
|
136
|
+
Deep memories are tagged with categories:
|
|
137
|
+
- `interaction` — operator conversations captured by the `agent_end` hook
|
|
138
|
+
- `reflection` — synthesized context from the reflection cycle
|
|
139
|
+
- `observation` — logged when there are no conversations or no extractable topics
|
|
140
|
+
- `dream_consolidation` — insights extracted from dream narratives
|
|
141
|
+
- `corrupted` — assigned at read time if a deep memory fails decryption
|
|
142
|
+
|
|
143
|
+
When Moltbook is enabled, additional categories may appear: `upvote`, `comment`.
|
|
144
|
+
|
|
145
|
+
### Three Phases
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
149
|
+
│ DAYTIME (Reflection Cycle) │
|
|
150
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
151
|
+
│ │
|
|
152
|
+
│ Operator Conversations ──► Topic Extraction ──┬──► Synthesis │
|
|
153
|
+
│ (from hooks) (LLM) │ (LLM) │
|
|
154
|
+
│ │ │ │
|
|
155
|
+
│ Moltbook Search ◄── topics ◄─────────────────┤ │ │
|
|
156
|
+
│ (optional) │ ▼ │
|
|
157
|
+
│ │ OpenClaw │
|
|
158
|
+
│ Web Search ◄──── topics ◄────────────────────┘ Memory │
|
|
159
|
+
│ (optional) │
|
|
160
|
+
│ │
|
|
161
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
162
|
+
|
|
163
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
164
|
+
│ NIGHTTIME (Dream Cycle) │
|
|
165
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
166
|
+
│ │
|
|
167
|
+
│ Deep Memory ──► Decrypt ──► Dream Generation ──► OpenClaw │
|
|
168
|
+
│ (encrypted) (LLM) Memory │
|
|
169
|
+
│ │ │
|
|
170
|
+
│ ▼ │
|
|
171
|
+
│ Notify Operator │
|
|
172
|
+
│ (Telegram/Slack/etc) │
|
|
173
|
+
│ │ │
|
|
174
|
+
│ ▼ │
|
|
175
|
+
│ Operator Converses │
|
|
176
|
+
│ (feeds next cycle) │
|
|
177
|
+
│ │ │
|
|
178
|
+
│ ▼ │
|
|
179
|
+
│ [Optional: Moltbook] │
|
|
180
|
+
│ │
|
|
181
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
- **Daytime** (`src/waking.ts`): Queries deep memory for recent interactions → extracts topics via LLM → searches Moltbook (optional) and web (optional) → synthesizes context via LLM → stores reflection in deep memory
|
|
185
|
+
- **Night** (`src/dreamer.ts`): Decrypts all undreamed deep memories → generates surreal dream narrative via LLM → saves markdown locally → consolidates insight via LLM → stores in OpenClaw memory → notifies operator → marks memories as dreamed
|
|
186
|
+
- **Morning** (`src/reflection.ts`): Decomposes dream into themes → reflects in agent's voice → applies content filter → posts to Moltbook (only if enabled)
|
|
187
|
+
|
|
188
|
+
### Module Responsibilities
|
|
189
|
+
|
|
190
|
+
| Module | Role |
|
|
191
|
+
|---|---|
|
|
192
|
+
| `src/index.ts` | OpenClaw extension entry: registers tools, hooks, scheduler service; wraps gateway into budgeted LLM client |
|
|
193
|
+
| `src/cli.ts` | CLI commands: `register`, `status`, `dreams` (via Commander) |
|
|
194
|
+
| `src/waking.ts` | Reflection cycle: conversations → topics → context → synthesis → memory |
|
|
195
|
+
| `src/dreamer.ts` | Dream cycle: decrypt → dream → save → consolidate → store in OpenClaw memory → notify; also `postDreamJournal` for Moltbook |
|
|
196
|
+
| `src/topics.ts` | Topic extraction from recent interaction deep memories |
|
|
197
|
+
| `src/synthesis.ts` | Context gathering orchestrator: calls topics, web-search, moltbook-search; LLM synthesis |
|
|
198
|
+
| `src/web-search.ts` | Web search per topic via OpenClaw `api.webSearch` |
|
|
199
|
+
| `src/moltbook-search.ts` | Moltbook search per topic via `MoltbookClient.search()` |
|
|
200
|
+
| `src/notify.ts` | Dream notification generation (LLM) and delivery via `api.channels` |
|
|
201
|
+
| `src/memory.ts` | Encrypted deep memory system (SQLite); `remember()`, `getRecentDeepMemories()`, `formatDeepMemoryContext()` |
|
|
202
|
+
| `src/crypto.ts` | `Cipher` class (AES-256-GCM); `getOrCreateDreamKey()` for key management |
|
|
203
|
+
| `src/reflection.ts` | Dream reflection: decompose themes, reflect in agent voice, synthesize Moltbook post |
|
|
204
|
+
| `src/filter.ts` | Outbound content filter: loads rules from `Moltbook-filter.md`, fail-closed on error |
|
|
205
|
+
| `src/persona.ts` | All system prompt templates with `{{placeholder}}` substitution via `renderTemplate()` |
|
|
206
|
+
| `src/moltbook.ts` | `MoltbookClient` REST client (register, post, comment, upvote, search, feed, etc.) |
|
|
207
|
+
| `src/budget.ts` | Daily token budget: `withBudget()` wrapper, `BudgetExceededError`, usage tracking in state |
|
|
208
|
+
| `src/state.ts` | `AgentState` JSON persistence with atomic writes (tmp + rename) |
|
|
209
|
+
| `src/config.ts` | Env loading via dotenv, path constants, memory/LLM limits; creates data directories on import |
|
|
210
|
+
| `src/llm.ts` | `callWithRetry()` wrapper around `p-retry`; `WAKING_RETRY_OPTS` (3 retries, 1-10s) and `DREAM_RETRY_OPTS` (3 retries, 2-20s) |
|
|
211
|
+
| `src/logger.ts` | Winston logger with daily-rotating file + console transport |
|
|
212
|
+
| `src/identity.ts` | Loads `SOUL.md` / `IDENTITY.md` from workspace dir with path traversal protection; caches result |
|
|
213
|
+
| `src/types.ts` | All shared TypeScript interfaces (`LLMClient`, `OpenClawAPI`, `DecryptedMemory`, `Dream`, etc.) |
|
|
214
|
+
|
|
215
|
+
### Key Constants (from `src/config.ts`)
|
|
216
|
+
|
|
217
|
+
| Constant | Value | Usage |
|
|
218
|
+
|----------|-------|-------|
|
|
219
|
+
| `DEEP_MEMORY_CONTEXT_TOKENS` | 2000 | Token budget for deep memory context in prompts (~8000 chars) |
|
|
220
|
+
| `MAX_TOPICS_PER_CYCLE` | 5 | Max topics extracted per reflection cycle |
|
|
221
|
+
| `MAX_WEB_RESULTS_PER_TOPIC` | 3 | Web results fetched per topic |
|
|
222
|
+
| `MAX_MOLTBOOK_RESULTS_PER_TOPIC` | 5 | Moltbook results fetched per topic |
|
|
223
|
+
| `MAX_DAILY_TOKENS` | 800,000 | Daily token budget (~$20/day at Opus 4.5 output pricing) |
|
|
224
|
+
| `MAX_TOKENS_DREAM` | 2000 | Max output tokens for dream generation |
|
|
225
|
+
| `MAX_TOKENS_SYNTHESIS` | 2000 | Max output tokens for context synthesis |
|
|
226
|
+
| `MAX_TOKENS_REFLECTION` | 1500 | Max output tokens for dream reflection |
|
|
227
|
+
| `MAX_TOKENS_TOPIC_EXTRACTION` | 500 | Max output tokens for topic extraction |
|
|
228
|
+
| `MAX_TOKENS_SUMMARY` | 150 | Max output tokens for summaries |
|
|
229
|
+
| `MAX_TOKENS_CONSOLIDATION` | 150 | Max output tokens for dream consolidation |
|
|
230
|
+
|
|
231
|
+
### Data Directory Layout
|
|
232
|
+
|
|
233
|
+
All runtime data lives under `data/` (auto-created by `config.ts`, gitignored):
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
data/
|
|
237
|
+
├── memory/
|
|
238
|
+
│ ├── deep.db # Encrypted deep memory (SQLite, WAL mode)
|
|
239
|
+
│ ├── deep.db-wal # SQLite WAL file
|
|
240
|
+
│ ├── deep.db-shm # SQLite shared memory
|
|
241
|
+
│ └── state.json # Agent state (last_check, total_dreams, budget, etc.)
|
|
242
|
+
├── dreams/
|
|
243
|
+
│ └── YYYY-MM-DD_slug.md # Dream narrative markdown files
|
|
244
|
+
├── .dream_key # AES-256 key (base64, chmod 600) — security-critical
|
|
245
|
+
├── credentials.json # Moltbook API credentials (if registered)
|
|
246
|
+
└── electricsheep-YYYY-MM-DD.log # Daily rotating log files
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
The encryption key at `data/.dream_key` enforces the separation between waking and dreaming states. It is created with exclusive mode (`wx` flag) and `0o600` permissions.
|
|
250
|
+
|
|
251
|
+
## Cost & API Usage
|
|
252
|
+
|
|
253
|
+
Each reflection cycle makes 2-3 LLM calls (topic extraction, synthesis, summary). Each dream cycle makes 2-3 (dream generation, consolidation, optional notification message). The default schedule (4 reflections + 1 dream per day) produces ~10-15 API calls/day.
|
|
254
|
+
|
|
255
|
+
### Daily Token Budget
|
|
256
|
+
|
|
257
|
+
`src/budget.ts` implements a best-effort daily kill switch. All LLM clients are wrapped via `withBudget()` which checks cumulative token usage before each call and records usage after. Budget is checked pre-call, so the call that crosses the threshold still completes. Token counts rely on API response metadata and may miss tokens from retries, network failures, or partial responses. Usage is tracked in `state.json` (`budget_date`, `budget_tokens_used`) and resets at midnight UTC. Default limit: 800K tokens. Set `MAX_DAILY_TOKENS=0` to disable. The `LLMClient` interface returns `{ text, usage? }` so the OpenClaw gateway reports token counts.
|
|
258
|
+
|
|
259
|
+
## Test Coverage
|
|
260
|
+
|
|
261
|
+
Tests live in `test/` and use `node:test` with `tsx`. Each test creates an isolated temp dir via `ELECTRICSHEEP_DATA_DIR`.
|
|
262
|
+
|
|
263
|
+
| Test File | Modules Covered |
|
|
264
|
+
|---|---|
|
|
265
|
+
| `test/crypto.test.ts` | `Cipher`, `getOrCreateDreamKey` |
|
|
266
|
+
| `test/memory.test.ts` | Deep memory functions, `getRecentDeepMemories`, `formatDeepMemoryContext`, `remember` |
|
|
267
|
+
| `test/state.test.ts` | `loadState`, `saveState` |
|
|
268
|
+
| `test/budget.test.ts` | `withBudget`, budget tracking, `BudgetExceededError` |
|
|
269
|
+
| `test/persona.test.ts` | `renderTemplate`, prompt template validation |
|
|
270
|
+
| `test/dreamer.test.ts` | `runDreamCycle` with mock LLM |
|
|
271
|
+
| `test/waking.test.ts` | `runReflectionCycle` with mock LLM |
|
|
272
|
+
| `test/reflection.test.ts` | `reflectOnDreamJournal` |
|
|
273
|
+
| `test/filter.test.ts` | `applyFilter`, `clearFilterCache` |
|
|
274
|
+
| `test/moltbook.test.ts` | `MoltbookClient` (with `globalThis.fetch` mocking) |
|
|
275
|
+
|
|
276
|
+
Not currently tested: `index.ts`, `topics.ts`, `synthesis.ts`, `web-search.ts`, `moltbook-search.ts`, `notify.ts`, `identity.ts`, `llm.ts`, `cli.ts`, `config.ts`, `logger.ts`.
|
|
277
|
+
|
|
278
|
+
## Dependencies
|
|
279
|
+
|
|
280
|
+
**Runtime:** `better-sqlite3`, `commander`, `chalk`, `winston`, `winston-daily-rotate-file`, `p-retry`, `dotenv`
|
|
281
|
+
|
|
282
|
+
**Peer:** `openclaw` (>=1.0.0)
|
|
283
|
+
|
|
284
|
+
**Dev:** `typescript`, `tsx`, `eslint`, `typescript-eslint`, `eslint-config-prettier`, `prettier`, `standard-version`, `@types/better-sqlite3`, `@types/node`
|
|
285
|
+
|
|
286
|
+
**Node:** >=24.0.0 | **Module system:** ESM (`"type": "module"`) | **Target:** ES2023
|