limbo-ai 1.30.0 → 1.32.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/.gitlab-ci.yml +209 -0
- package/ARCHITECTURE.md +20 -24
- package/README.md +9 -9
- package/RELEASES.md +32 -0
- package/SECURITY.md +13 -13
- package/cli.js +209 -83
- package/docker-compose.dev.yml +3 -0
- package/docker-compose.test.yml +60 -13
- package/evals/cli.js +2 -7
- package/evals/docker-compose.eval.yml +7 -6
- package/evals/promptfoo/assertions.js +215 -0
- package/evals/promptfoo/hooks.js +119 -0
- package/evals/promptfoo/promptfooconfig.yaml +106 -0
- package/evals/promptfoo/provider.js +206 -0
- package/evals/promptfoo/run.sh +25 -0
- package/evals/promptfoo/seeds/notes/eval-seed-birthday.md +9 -0
- package/evals/vault-seed/maps/personal-map.md +0 -2
- package/lib/telegram-notify.js +97 -0
- package/lib/wakeup.js +206 -0
- package/mcp-server/index.js +20 -5
- package/mcp-server/tools/update-instance.js +59 -0
- package/mcp-server/tools/workspace.js +4 -4
- package/package.json +7 -4
- package/setup-server/public/index.html +57 -248
- package/setup-server/server.js +86 -61
- package/test/cli-auth.test.js +13 -18
- package/test/cli-compose.test.js +471 -0
- package/test/cli-registry.test.js +95 -0
- package/test/cli-wizard-parity.test.js +5 -2
- package/test/entrypoint.test.js +873 -0
- package/test/mcp-tools.test.js +606 -0
- package/test/openclaw-migration.test.js +317 -0
- package/test/red-phase.test.js +181 -0
- package/test/setup-server.test.js +524 -14
- package/test/update-system.test.js +210 -0
- package/config.toml.template +0 -27
- package/test/zeroclaw-migration.test.js +0 -305
package/.gitlab-ci.yml
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# GitLab CI/CD — equivalent of .github/workflows/{ci,promote,publish}.yml
|
|
2
|
+
# GitHub Actions originals are kept intact for when the account is restored.
|
|
3
|
+
|
|
4
|
+
stages:
|
|
5
|
+
- test
|
|
6
|
+
- promote
|
|
7
|
+
- release
|
|
8
|
+
|
|
9
|
+
variables:
|
|
10
|
+
NODE_VERSION: "22"
|
|
11
|
+
DOCKER_TLS_CERTDIR: "/certs"
|
|
12
|
+
|
|
13
|
+
# ─── CI: runs on MRs and staging pushes ───────────────────────────
|
|
14
|
+
|
|
15
|
+
docker-build:
|
|
16
|
+
stage: test
|
|
17
|
+
image: docker:latest
|
|
18
|
+
services:
|
|
19
|
+
- docker:dind
|
|
20
|
+
rules:
|
|
21
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
22
|
+
- if: $CI_COMMIT_BRANCH == "staging"
|
|
23
|
+
script:
|
|
24
|
+
- docker build --tag limbo:ci-test .
|
|
25
|
+
|
|
26
|
+
mcp-server-check:
|
|
27
|
+
stage: test
|
|
28
|
+
image: node:${NODE_VERSION}
|
|
29
|
+
rules:
|
|
30
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
31
|
+
- if: $CI_COMMIT_BRANCH == "staging"
|
|
32
|
+
before_script:
|
|
33
|
+
- cd mcp-server && npm ci && cd ..
|
|
34
|
+
script:
|
|
35
|
+
- node --check mcp-server/index.js
|
|
36
|
+
- node --check setup-server/server.js
|
|
37
|
+
|
|
38
|
+
tests:
|
|
39
|
+
stage: test
|
|
40
|
+
image: node:${NODE_VERSION}
|
|
41
|
+
rules:
|
|
42
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
43
|
+
- if: $CI_COMMIT_BRANCH == "staging"
|
|
44
|
+
before_script:
|
|
45
|
+
- cd mcp-server && npm ci && cd ..
|
|
46
|
+
script:
|
|
47
|
+
- node -e "require('./cli.js')"
|
|
48
|
+
- node --test test/cli-filter.test.js test/cli-auth.test.js test/openclaw-migration.test.js test/setup-server.test.js test/entrypoint.test.js test/cli-compose.test.js test/red-phase.test.js test/mcp-tools.test.js test/cli-wizard-parity.test.js
|
|
49
|
+
|
|
50
|
+
# ─── PROMOTE: auto-create MR from staging → main ──────────────────
|
|
51
|
+
|
|
52
|
+
promote-staging-to-main:
|
|
53
|
+
stage: promote
|
|
54
|
+
image: alpine:latest
|
|
55
|
+
rules:
|
|
56
|
+
- if: $CI_COMMIT_BRANCH == "staging"
|
|
57
|
+
before_script:
|
|
58
|
+
- apk add --no-cache curl jq git
|
|
59
|
+
script:
|
|
60
|
+
- |
|
|
61
|
+
# Determine bump type from commits on staging not on main
|
|
62
|
+
git fetch origin main
|
|
63
|
+
COMMITS=$(git log origin/main..origin/staging --pretty=format:"%s" 2>/dev/null || echo "")
|
|
64
|
+
echo "--- Commits on staging not on main ---"
|
|
65
|
+
echo "$COMMITS"
|
|
66
|
+
|
|
67
|
+
if echo "$COMMITS" | grep -qE "^feat(\(.+\))?!:|BREAKING CHANGE"; then
|
|
68
|
+
TYPE="feat!"
|
|
69
|
+
elif echo "$COMMITS" | grep -qE "^feat(\(.+\))?:"; then
|
|
70
|
+
TYPE="feat"
|
|
71
|
+
elif echo "$COMMITS" | grep -qE "^fix(\(.+\))?:"; then
|
|
72
|
+
TYPE="fix"
|
|
73
|
+
else
|
|
74
|
+
TYPE="chore"
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
echo "Bump type: $TYPE"
|
|
78
|
+
|
|
79
|
+
# Check for existing MR
|
|
80
|
+
EXISTING=$(curl -s --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
|
|
81
|
+
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests?source_branch=staging&target_branch=main&state=opened" \
|
|
82
|
+
| jq '.[0].iid // empty')
|
|
83
|
+
|
|
84
|
+
if [ -z "$EXISTING" ]; then
|
|
85
|
+
# Create new MR
|
|
86
|
+
curl -s --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
|
|
87
|
+
-X POST "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests" \
|
|
88
|
+
-d "source_branch=staging" \
|
|
89
|
+
-d "target_branch=main" \
|
|
90
|
+
-d "title=${TYPE}: promote staging to main" \
|
|
91
|
+
-d "remove_source_branch=false" | jq '.web_url'
|
|
92
|
+
echo "Created new MR"
|
|
93
|
+
else
|
|
94
|
+
# Update existing MR title
|
|
95
|
+
curl -s --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
|
|
96
|
+
-X PUT "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests/${EXISTING}" \
|
|
97
|
+
-d "title=${TYPE}: promote staging to main" | jq '.web_url'
|
|
98
|
+
echo "Updated existing MR #${EXISTING}"
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# ─── RELEASE: version bump + npm publish + docker push + tag ──────
|
|
102
|
+
|
|
103
|
+
release:
|
|
104
|
+
stage: release
|
|
105
|
+
image: docker:latest
|
|
106
|
+
services:
|
|
107
|
+
- docker:dind
|
|
108
|
+
id_tokens:
|
|
109
|
+
NPM_ID_TOKEN:
|
|
110
|
+
aud: npm:registry.npmjs.org
|
|
111
|
+
SIGSTORE_ID_TOKEN:
|
|
112
|
+
aud: sigstore
|
|
113
|
+
environment: production
|
|
114
|
+
rules:
|
|
115
|
+
- if: $CI_COMMIT_BRANCH == "main"
|
|
116
|
+
when: on_success
|
|
117
|
+
variables:
|
|
118
|
+
GIT_STRATEGY: clone
|
|
119
|
+
GIT_DEPTH: "0"
|
|
120
|
+
before_script:
|
|
121
|
+
- apk add --no-cache nodejs npm git jq curl
|
|
122
|
+
- npm install -g npm@11.6.2
|
|
123
|
+
script:
|
|
124
|
+
- |
|
|
125
|
+
# Skip bot commits
|
|
126
|
+
if echo "$CI_COMMIT_MESSAGE" | grep -q "\[skip ci\]"; then
|
|
127
|
+
echo "Skipping release for [skip ci] commit"
|
|
128
|
+
exit 0
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
# Determine version bump
|
|
132
|
+
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
|
133
|
+
if [ -z "$LAST_TAG" ]; then
|
|
134
|
+
RANGE="HEAD"
|
|
135
|
+
else
|
|
136
|
+
RANGE="${LAST_TAG}..HEAD"
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
COMMITS=$(git log "$RANGE" --first-parent --pretty=format:"%B" 2>/dev/null || echo "")
|
|
140
|
+
echo "--- First-parent commits since last tag ---"
|
|
141
|
+
echo "$COMMITS"
|
|
142
|
+
|
|
143
|
+
if echo "$COMMITS" | grep -qE "^feat(\(.+\))?!:|BREAKING CHANGE"; then
|
|
144
|
+
BUMP="major"
|
|
145
|
+
elif echo "$COMMITS" | grep -qE "^feat(\(.+\))?:"; then
|
|
146
|
+
BUMP="minor"
|
|
147
|
+
elif echo "$COMMITS" | grep -qE "^fix(\(.+\))?:"; then
|
|
148
|
+
BUMP="patch"
|
|
149
|
+
else
|
|
150
|
+
echo "No releasable changes found on main."
|
|
151
|
+
exit 0
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
echo "Bump type: $BUMP"
|
|
155
|
+
|
|
156
|
+
# Bump version
|
|
157
|
+
npm version "$BUMP" --no-git-tag-version
|
|
158
|
+
VERSION=$(node -p "require('./package.json').version")
|
|
159
|
+
MAJOR=$(echo "$VERSION" | cut -d. -f1)
|
|
160
|
+
MINOR=$(echo "$VERSION" | cut -d. -f1-2)
|
|
161
|
+
echo "Publishing version: $VERSION"
|
|
162
|
+
|
|
163
|
+
# Docker: build and push to GitLab Container Registry
|
|
164
|
+
IMAGE="${CI_REGISTRY_IMAGE}"
|
|
165
|
+
echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
|
|
166
|
+
|
|
167
|
+
docker build \
|
|
168
|
+
--tag "${IMAGE}:${VERSION}" \
|
|
169
|
+
--tag "${IMAGE}:${MINOR}" \
|
|
170
|
+
--tag "${IMAGE}:${MAJOR}" \
|
|
171
|
+
--tag "${IMAGE}:latest" \
|
|
172
|
+
.
|
|
173
|
+
|
|
174
|
+
docker push "${IMAGE}:${VERSION}"
|
|
175
|
+
docker push "${IMAGE}:${MINOR}"
|
|
176
|
+
docker push "${IMAGE}:${MAJOR}"
|
|
177
|
+
docker push "${IMAGE}:latest"
|
|
178
|
+
|
|
179
|
+
# npm publish (trusted publishing via OIDC — no token needed)
|
|
180
|
+
npm publish --provenance --access public
|
|
181
|
+
|
|
182
|
+
# Git: commit version bump and tag
|
|
183
|
+
git config user.name "gitlab-ci[bot]"
|
|
184
|
+
git config user.email "gitlab-ci[bot]@users.noreply.gitlab.com"
|
|
185
|
+
git remote set-url origin "https://oauth2:${GITLAB_TOKEN}@gitlab.com/${CI_PROJECT_PATH}.git"
|
|
186
|
+
git add package.json
|
|
187
|
+
git commit -m "chore: release v${VERSION} [skip ci]"
|
|
188
|
+
git tag "v${VERSION}"
|
|
189
|
+
git checkout -B main
|
|
190
|
+
git push origin main --follow-tags
|
|
191
|
+
|
|
192
|
+
# Create GitLab Release
|
|
193
|
+
PREV_TAG=$(git describe --tags --abbrev=0 "v${VERSION}^" 2>/dev/null || echo "")
|
|
194
|
+
if [ -n "$PREV_TAG" ]; then
|
|
195
|
+
CHANGELOG=$(git log "${PREV_TAG}..HEAD" --pretty=format:"- %s (%h)" --no-merges)
|
|
196
|
+
else
|
|
197
|
+
CHANGELOG=$(git log HEAD --pretty=format:"- %s (%h)" --no-merges)
|
|
198
|
+
fi
|
|
199
|
+
|
|
200
|
+
curl -s --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
|
|
201
|
+
-X POST "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/releases" \
|
|
202
|
+
-H "Content-Type: application/json" \
|
|
203
|
+
-d "{
|
|
204
|
+
\"tag_name\": \"v${VERSION}\",
|
|
205
|
+
\"name\": \"Limbo v${VERSION}\",
|
|
206
|
+
\"description\": $(echo "$CHANGELOG" | jq -Rs .)
|
|
207
|
+
}"
|
|
208
|
+
|
|
209
|
+
echo "Released v${VERSION}"
|
package/ARCHITECTURE.md
CHANGED
|
@@ -5,16 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
## What Is Limbo
|
|
7
7
|
|
|
8
|
-
Self-hosted personal AI memory agent. Runs as a Docker container exposing
|
|
8
|
+
Self-hosted personal AI memory agent. Runs as a Docker container exposing an OpenClaw gateway (WebSocket on :18789). Users interact via Telegram. The agent stores and retrieves knowledge from a markdown vault using MCP tools.
|
|
9
9
|
|
|
10
|
-
**Stack**:
|
|
10
|
+
**Stack**: OpenClaw (Node.js agent runtime) + Node.js MCP server + SQLite FTS5 + Telegram bot.
|
|
11
11
|
|
|
12
12
|
**Published as**: `limbo-ai` on npm — the CLI (`npx limbo-ai`) handles install, start, stop, update, and setup.
|
|
13
13
|
|
|
14
14
|
## High-Level Flow
|
|
15
15
|
|
|
16
16
|
```
|
|
17
|
-
User (Telegram) →
|
|
17
|
+
User (Telegram) → OpenClaw Gateway (:18789) → LLM (configurable provider)
|
|
18
18
|
↓
|
|
19
19
|
MCP Tools (stdio)
|
|
20
20
|
↓
|
|
@@ -26,8 +26,8 @@ User (Telegram) → ZeroClaw Gateway (:18789) → LLM (configurable provider)
|
|
|
26
26
|
```
|
|
27
27
|
limbo/
|
|
28
28
|
├── cli.js # Main CLI (84KB) — install, start, stop, update, configure
|
|
29
|
-
├── Dockerfile # Multi-stage: deps →
|
|
30
|
-
├──
|
|
29
|
+
├── Dockerfile # Multi-stage: deps → runtime (node:22-slim)
|
|
30
|
+
├── openclaw.json.template # OpenClaw config — rendered by entrypoint via envsubst
|
|
31
31
|
├── docker-compose.yml # Production reference (generated per-user into ~/.limbo)
|
|
32
32
|
├── docker-compose.dev.yml # Local dev
|
|
33
33
|
├── docker-compose.test.yml # Local testing
|
|
@@ -45,7 +45,7 @@ limbo/
|
|
|
45
45
|
│ ├── store-file.js # vault_store_file — binary files (images/PDFs) + linked note
|
|
46
46
|
│ └── get-file.js # vault_get_file — retrieve stored files as base64
|
|
47
47
|
│
|
|
48
|
-
├── workspace/ # Agent persona files (injected into
|
|
48
|
+
├── workspace/ # Agent persona files (injected into OpenClaw context)
|
|
49
49
|
│ ├── system/ # Product-owned, root-owned, reset every boot
|
|
50
50
|
│ │ ├── AGENTS.md # Behavioral workflows and rules
|
|
51
51
|
│ │ ├── TOOLS.md # Tool usage instructions
|
|
@@ -64,7 +64,6 @@ limbo/
|
|
|
64
64
|
│
|
|
65
65
|
├── scripts/
|
|
66
66
|
│ ├── entrypoint.sh # Container startup (13KB) — 12-stage orchestration
|
|
67
|
-
│ ├── build-zeroclaw.sh # Custom ZeroClaw image builder (multi-platform)
|
|
68
67
|
│ └── install.sh # Server provisioning (Ubuntu/Debian)
|
|
69
68
|
│
|
|
70
69
|
├── evals/ # End-to-end eval framework
|
|
@@ -81,7 +80,7 @@ limbo/
|
|
|
81
80
|
├── test/ # Unit tests (node --test)
|
|
82
81
|
│ ├── cli-filter.test.js
|
|
83
82
|
│ ├── cli-auth.test.js
|
|
84
|
-
│ ├──
|
|
83
|
+
│ ├── openclaw-migration.test.js
|
|
85
84
|
│ ├── setup-server.test.js
|
|
86
85
|
│ └── cli-wizard-parity.test.js
|
|
87
86
|
│
|
|
@@ -90,36 +89,33 @@ limbo/
|
|
|
90
89
|
└── squid/ # Squid proxy config (for container network access)
|
|
91
90
|
```
|
|
92
91
|
|
|
93
|
-
## Docker Build (
|
|
92
|
+
## Docker Build (2 stages)
|
|
94
93
|
|
|
95
94
|
1. **deps** (node:22-slim) — `npm ci` + compile better-sqlite3 native addon
|
|
96
|
-
2. **
|
|
97
|
-
3. **runtime** (node:22-slim) — non-root `limbo` user, copies app + binary + node_modules
|
|
95
|
+
2. **runtime** (node:22-slim) — non-root `limbo` user, copies app + node_modules (OpenClaw included as npm dependency)
|
|
98
96
|
|
|
99
97
|
**Data volume**: `/data` — contains vault/, db/, config/, logs/, backups/, memory/
|
|
100
98
|
|
|
101
|
-
**Build arg**: `ZEROCLAW_IMAGE` — override to test custom ZeroClaw builds locally.
|
|
102
|
-
|
|
103
99
|
## Entrypoint Flow (scripts/entrypoint.sh)
|
|
104
100
|
|
|
105
101
|
12-stage startup:
|
|
106
102
|
1. Directory setup (`/data/*`)
|
|
107
|
-
2. Secrets sync (`/run/secrets/` → `$
|
|
103
|
+
2. Secrets sync (`/run/secrets/` → `$OPENCLAW_STATE_DIR/secrets/`)
|
|
108
104
|
3. First-run detection (presence of `.env` in /data)
|
|
109
105
|
4. Setup wizard (if no `MODEL_PROVIDER` in .env → serve wizard on :18789)
|
|
110
106
|
5. Workspace file seeding (templates → /data, system files symlinked)
|
|
111
|
-
6. Config template rendering (envsubst on
|
|
112
|
-
7. Feature sections (Telegram, Voice, Web Search) conditionally
|
|
107
|
+
6. Config template rendering (envsubst on openclaw.json.template)
|
|
108
|
+
7. Feature sections (Telegram, Voice, Web Search) conditionally merged into openclaw.json
|
|
113
109
|
8. Auth profiles generation
|
|
114
110
|
9. Migration runner
|
|
115
111
|
10. FTS index build
|
|
116
112
|
11. MCP server registration
|
|
117
|
-
12.
|
|
113
|
+
12. OpenClaw launch
|
|
118
114
|
|
|
119
115
|
## MCP Server Details
|
|
120
116
|
|
|
121
117
|
- **Protocol**: JSON-RPC 2.0 over stdio
|
|
122
|
-
- **Invoked by
|
|
118
|
+
- **Invoked by OpenClaw**: `node /app/mcp-server/index.js`
|
|
123
119
|
- **Vault path**: `/data/vault/` (markdown files with YAML frontmatter)
|
|
124
120
|
- **FTS database**: `/data/db/fts.db` (SQLite, WAL mode)
|
|
125
121
|
- **Index**: In-memory hashmap of all vault notes, rebuilt on startup
|
|
@@ -145,18 +141,18 @@ topics:
|
|
|
145
141
|
|
|
146
142
|
These are documented in the vault but rarely change:
|
|
147
143
|
|
|
148
|
-
- **Extension = MCP tools, not
|
|
149
|
-
- **Separate container, not plugin**. Limbo is a standalone Docker container
|
|
144
|
+
- **Extension = MCP tools, not OpenClaw core**. New capabilities go in `mcp-server/tools/` as Node.js.
|
|
145
|
+
- **Separate container, not plugin**. Limbo is a standalone Docker container with OpenClaw as an npm dependency.
|
|
150
146
|
- **System files reset on boot, user files persist**. AGENTS.md/TOOLS.md overwrite from image; SOUL.md/IDENTITY.md/USER.md survive across container restarts.
|
|
151
147
|
- **Maps live in vault/maps/, notes in vault/notes/**. Separated to simplify `vault_update_map`.
|
|
152
|
-
- **Feature integration pattern**: wizard toggle → secret file → env var → entrypoint
|
|
148
|
+
- **Feature integration pattern**: wizard toggle → secret file → env var → entrypoint merges JSON config section.
|
|
153
149
|
- **Minimal .env triggers setup wizard**. Container detects first run by absence of `MODEL_PROVIDER`.
|
|
154
150
|
|
|
155
151
|
## Eval System
|
|
156
152
|
|
|
157
153
|
- 20+ JSON test cases in `evals/cases/`
|
|
158
154
|
- Each case: sends message via WebSocket, asserts on tool_called + response_matches + vault_state
|
|
159
|
-
- Current baseline: 94.0% (FTS5 +
|
|
155
|
+
- Current baseline: 94.0% (FTS5 + OpenClaw)
|
|
160
156
|
- `node evals/cli.js run` → `compare --strict` → `promote`
|
|
161
157
|
- Uses real LLM calls (costs tokens)
|
|
162
158
|
|
|
@@ -166,13 +162,13 @@ Key env vars (see `.env.example` for full list):
|
|
|
166
162
|
- `MODEL_PROVIDER` — anthropic, openai, etc.
|
|
167
163
|
- `TELEGRAM_ENABLED` — true/false
|
|
168
164
|
- `LIMBO_PORT` — gateway port (default 18789)
|
|
169
|
-
- `
|
|
165
|
+
- `OPENCLAW_STATE_DIR` — where OpenClaw stores its state
|
|
170
166
|
- `LIMBO_EVAL` — enables MCP tool call logging
|
|
171
167
|
|
|
172
168
|
## Testing
|
|
173
169
|
|
|
174
170
|
```bash
|
|
175
|
-
npm test # runs: cli-filter, cli-auth,
|
|
171
|
+
npm test # runs: cli-filter, cli-auth, openclaw-migration, setup-server, cli-wizard-parity
|
|
176
172
|
```
|
|
177
173
|
|
|
178
174
|
Tests use Node.js built-in test runner (`node --test`).
|
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
-
Limbo is a second brain with a conversational interface. It stores atomic notes in a local vault, searches them semantically, and maintains Maps of Content (MOCs) to keep knowledge navigable. Runs in a Docker container, accessible via Telegram or the
|
|
18
|
+
Limbo is a second brain with a conversational interface. It stores atomic notes in a local vault, searches them semantically, and maintains Maps of Content (MOCs) to keep knowledge navigable. Runs in a Docker container, accessible via Telegram or the OpenClaw gateway.
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
@@ -95,9 +95,9 @@ limbo config web-search --enable --api-key BSA_xxx # Enable web search
|
|
|
95
95
|
|
|
96
96
|
The setup wizard walks you through creating a Telegram bot and pairing it. Message your bot and Limbo responds — full agent with personality, memory logic, and vault tools.
|
|
97
97
|
|
|
98
|
-
###
|
|
98
|
+
### OpenClaw gateway
|
|
99
99
|
|
|
100
|
-
Any [
|
|
100
|
+
Any [OpenClaw](https://github.com/openclaw-ai/openclaw)-compatible client can connect via WebSocket:
|
|
101
101
|
|
|
102
102
|
```
|
|
103
103
|
ws://localhost:18789
|
|
@@ -153,7 +153,7 @@ limbo config web-search --disable
|
|
|
153
153
|
| Recommended | 1 GB | 1 | 5 GB |
|
|
154
154
|
| With other services | 2 GB | 1 | 10 GB |
|
|
155
155
|
|
|
156
|
-
Limbo uses ~
|
|
156
|
+
Limbo uses ~150 MB at rest, peaks ~300 MB during agent runs. CPU usage is negligible.
|
|
157
157
|
|
|
158
158
|
---
|
|
159
159
|
|
|
@@ -164,8 +164,8 @@ Limbo uses ~35 MB at rest, peaks ~70 MB during cold starts. CPU usage is negligi
|
|
|
164
164
|
│ Docker Container │
|
|
165
165
|
│ │
|
|
166
166
|
│ ┌─────────────┐ ┌────────────────┐ │
|
|
167
|
-
│ │
|
|
168
|
-
│ │
|
|
167
|
+
│ │ OpenClaw │◄──►│ LLM (Claude │ │
|
|
168
|
+
│ │ gateway │ │ or OpenAI) │ │
|
|
169
169
|
│ │ :18789 │ └────────┬───────┘ │
|
|
170
170
|
│ └──────┬──────┘ │ │
|
|
171
171
|
│ │ ┌────────▼───────┐ │
|
|
@@ -179,8 +179,8 @@ Limbo uses ~35 MB at rest, peaks ~70 MB during cold starts. CPU usage is negligi
|
|
|
179
179
|
└─────────────────────────────────────────┘
|
|
180
180
|
```
|
|
181
181
|
|
|
182
|
-
- **
|
|
183
|
-
- **MCP server** — Node.js vault read/write tools, spawned by
|
|
182
|
+
- **OpenClaw** — Node.js runtime (~150 MB) handling connections, LLM routing, Telegram, and MCP tools
|
|
183
|
+
- **MCP server** — Node.js vault read/write tools, spawned by OpenClaw
|
|
184
184
|
- **Vault** — plain markdown with YAML frontmatter, persisted in a Docker volume
|
|
185
185
|
|
|
186
186
|
---
|
|
@@ -215,7 +215,7 @@ Managed by `limbo start`, stored in `~/.limbo/.env`.
|
|
|
215
215
|
| `AUTH_MODE` | `api-key` | `api-key` or `subscription` |
|
|
216
216
|
| `MODEL_PROVIDER` | `anthropic` | `anthropic`, `openai`, `openai-codex`, or `openrouter` |
|
|
217
217
|
| `MODEL_NAME` | `claude-sonnet-4-6` | Model to use |
|
|
218
|
-
| `RUNTIME_REASONING_EFFORT` | `medium` |
|
|
218
|
+
| `RUNTIME_REASONING_EFFORT` | `medium` | OpenClaw reasoning effort override |
|
|
219
219
|
| `TELEGRAM_ENABLED` | `false` | Enable Telegram integration |
|
|
220
220
|
| `VOICE_ENABLED` | `false` | Enable Groq voice transcription |
|
|
221
221
|
| `WEB_SEARCH_ENABLED` | `false` | Enable Brave web search |
|
package/RELEASES.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Limbo Releases
|
|
2
|
+
|
|
3
|
+
> User-facing changelog. The section for the latest version (above the first `---`)
|
|
4
|
+
> is sent to users as the update notification in Telegram. Keep it non-technical
|
|
5
|
+
> and human-readable. Technical details go below the `---` separator.
|
|
6
|
+
>
|
|
7
|
+
> Format:
|
|
8
|
+
> ```
|
|
9
|
+
> ## vX.Y.Z
|
|
10
|
+
>
|
|
11
|
+
> - Human-readable change 1
|
|
12
|
+
> - Human-readable change 2
|
|
13
|
+
>
|
|
14
|
+
> ---
|
|
15
|
+
>
|
|
16
|
+
> ### Technical changelog
|
|
17
|
+
> - feat: technical description (#PR)
|
|
18
|
+
> - fix: technical description (#PR)
|
|
19
|
+
> ```
|
|
20
|
+
|
|
21
|
+
## v1.30.0
|
|
22
|
+
|
|
23
|
+
- Limbo now notifies you when a new version is available
|
|
24
|
+
- You can update directly from Telegram with one tap
|
|
25
|
+
- Improved startup reliability
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
### Technical changelog
|
|
30
|
+
- feat: update notification system with wakeup routine
|
|
31
|
+
- feat: update_instance MCP tool + flag-file bridge to host
|
|
32
|
+
- feat: telegram-notify lib for deterministic system messages
|
package/SECURITY.md
CHANGED
|
@@ -10,14 +10,14 @@ Limbo runs inside a Docker container with the following hardening:
|
|
|
10
10
|
- **Capabilities dropped**: All Linux capabilities are dropped (`cap_drop: ALL`)
|
|
11
11
|
- **Process limit**: PID limit of 200 prevents fork bombs
|
|
12
12
|
- **Loopback binding**: Gateway only listens on `127.0.0.1` — not exposed to LAN
|
|
13
|
-
- **Writable paths**: Only `/data` (volume), `/home/limbo/.
|
|
13
|
+
- **Writable paths**: Only `/data` (volume), `/home/limbo/.openclaw` (volume), `/tmp` (tmpfs), and `/home/limbo/.npm` (tmpfs) are writable
|
|
14
14
|
|
|
15
15
|
## What Agents Can Access
|
|
16
16
|
|
|
17
17
|
Inside the container, the AI agent can:
|
|
18
18
|
|
|
19
19
|
- Read and write vault notes in `/data/vault/` (via MCP tools only)
|
|
20
|
-
- Execute MCP tools registered through
|
|
20
|
+
- Execute MCP tools registered through OpenClaw native MCP (vault_search, vault_read, vault_write_note, vault_update_map)
|
|
21
21
|
- Search the web and fetch URLs (`web_search`, `web_fetch` — enabled for recommendations, link previews, etc.)
|
|
22
22
|
- Respond to Telegram messages (if enabled, with pairing required)
|
|
23
23
|
- Make network requests to AI provider APIs (Anthropic, OpenAI, OpenRouter)
|
|
@@ -36,7 +36,7 @@ Inside the container, the AI agent can:
|
|
|
36
36
|
- **Access host filesystem**: Only the bind-mounted vault directory is accessible
|
|
37
37
|
- **Spawn unlimited processes**: PID limit of 200
|
|
38
38
|
|
|
39
|
-
##
|
|
39
|
+
## OpenClaw Tool Policy
|
|
40
40
|
|
|
41
41
|
The agent runs with the most restrictive tool profile. On top of that:
|
|
42
42
|
|
|
@@ -57,18 +57,18 @@ API keys are stored as Docker Compose secrets:
|
|
|
57
57
|
- **Not in environment**: Secrets are scrubbed from the process environment before the gateway starts
|
|
58
58
|
- **Not in `docker inspect`**: Docker secrets don't appear in container inspect output
|
|
59
59
|
- **`.env` file**: Only contains non-sensitive configuration (model provider, model name, language, etc.)
|
|
60
|
-
- **Gateway auth**:
|
|
60
|
+
- **Gateway auth**: OpenClaw manages its own gateway authentication internally. All secrets (API keys, bot tokens) are scrubbed from the process environment before the daemon starts
|
|
61
61
|
|
|
62
|
-
##
|
|
62
|
+
## OpenClaw Security
|
|
63
63
|
|
|
64
|
-
Limbo uses
|
|
64
|
+
Limbo uses OpenClaw in a **personal assistant trust model** (one trusted operator per gateway). Key settings in `openclaw.json`:
|
|
65
65
|
|
|
66
|
-
- `
|
|
67
|
-
- `
|
|
68
|
-
- `
|
|
69
|
-
- `
|
|
70
|
-
- `
|
|
71
|
-
- `
|
|
66
|
+
- `"host": "127.0.0.1"` — loopback only, no LAN exposure
|
|
67
|
+
- `"allowPublicBind": false` — prevents binding to all interfaces
|
|
68
|
+
- `"auth.mode": "token"` — all WebSocket clients must present a valid token
|
|
69
|
+
- `"auth.tokenFile": "/run/secrets/gateway_token"` — reads auth token from Docker secret
|
|
70
|
+
- `"session.dmScope": "per-channel-peer"` — DM sessions are isolated per sender (when using Telegram)
|
|
71
|
+
- `"channels.telegram.dmPolicy": "pairing"` — unknown Telegram senders must be explicitly approved
|
|
72
72
|
|
|
73
73
|
## Network Access
|
|
74
74
|
|
|
@@ -105,4 +105,4 @@ If you discover a security vulnerability in Limbo:
|
|
|
105
105
|
3. Include: description, reproduction steps, affected version, and impact assessment
|
|
106
106
|
4. We will acknowledge within 48 hours and work on a fix
|
|
107
107
|
|
|
108
|
-
For vulnerabilities in
|
|
108
|
+
For vulnerabilities in OpenClaw itself, follow their responsible disclosure process at https://github.com/openclaw-ai/openclaw/security
|