@wipcomputer/wip-ldm-os 0.4.0 → 0.4.2
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/README.md +11 -11
- package/SKILL.md +1 -1
- package/bin/ldm.js +51 -2
- package/bin/wip-install.js +8 -0
- package/docs/acp/README.md +4 -0
- package/docs/acp/TECHNICAL.md +42 -0
- package/docs/bridge/README.md +55 -0
- package/docs/bridge/TECHNICAL.md +153 -0
- package/docs/recall/README.md +4 -0
- package/docs/recall/TECHNICAL.md +41 -0
- package/docs/shared-workspace/README.md +4 -0
- package/docs/shared-workspace/TECHNICAL.md +75 -0
- package/docs/skills/README.md +9 -4
- package/docs/skills/TECHNICAL.md +67 -0
- package/docs/system-pulse/README.md +4 -0
- package/docs/system-pulse/TECHNICAL.md +56 -0
- package/docs/universal-installer/SPEC.md +206 -0
- package/lib/bootstrap.mjs +92 -0
- package/lib/state.mjs +2 -2
- package/package.json +2 -1
- package/src/bridge/cli.ts +4 -4
- package/src/bridge/core.ts +1 -1
- package/src/bridge/mcp-server.ts +9 -9
- package/templates/hooks/pre-commit +19 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
###### WIP Computer
|
|
2
2
|
|
|
3
|
-
# LDM OS
|
|
3
|
+
# LDM OS: Learning Dreaming Machines
|
|
4
4
|
|
|
5
5
|
## All your AIs. One system.
|
|
6
6
|
|
|
@@ -47,23 +47,27 @@ That's it. Your AI reads the spec, explains what it does, and walks you through
|
|
|
47
47
|
|
|
48
48
|
Ships with LDM OS.
|
|
49
49
|
|
|
50
|
+
**Bridge**
|
|
51
|
+
- Cross-platform agent bridge. Enables Claude Code CLI to talk to OpenClaw CLI without a human in the middle.
|
|
52
|
+
- [Read more about Bridge](docs/bridge/README.md)
|
|
53
|
+
|
|
50
54
|
**Universal Installer**
|
|
51
55
|
- Point any skill, application, or plugin at any AI running LDM OS, and it will convert those skills to work with all of your AIs.
|
|
52
56
|
- Build applications that work with any AI, even ones that don't have LDM OS.
|
|
53
|
-
- [Read more about Universal Installer](docs/universal-installer.md)
|
|
57
|
+
- [Read more about Universal Installer](docs/universal-installer/README.md)
|
|
54
58
|
|
|
55
59
|
**Shared Workspace**
|
|
56
60
|
- One directory for all your AIs. Memories, tools, identity files, boot config. Every AI you use reads from and writes to the same place.
|
|
57
61
|
- Lives in one folder on your computer. Easy to back up, easy to move, easy to own.
|
|
58
|
-
- [Read more about Shared Workspace](docs/shared-workspace.md)
|
|
62
|
+
- [Read more about Shared Workspace](docs/shared-workspace/README.md)
|
|
59
63
|
|
|
60
64
|
**System Pulse**
|
|
61
65
|
- Is everything working? What's installed? What needs fixing? A complete picture of your AI setup in seconds.
|
|
62
|
-
- [Read more about System Pulse](docs/system-pulse.md)
|
|
66
|
+
- [Read more about System Pulse](docs/system-pulse/README.md)
|
|
63
67
|
|
|
64
68
|
**Recall**
|
|
65
69
|
- Every session, your AI starts with full context. Identity, memory, tools, what happened yesterday. No blank slates. No repeating yourself.
|
|
66
|
-
- [Read more about Recall](docs/recall.md)
|
|
70
|
+
- [Read more about Recall](docs/recall/README.md)
|
|
67
71
|
|
|
68
72
|
**LUME**
|
|
69
73
|
- Language for Unified Memory and Emergence. A memory language for AI agents to document their own learning and maintain continuity across sessions. Not a programming language. A way for your AI to write memories to itself, retrieve past learnings, track unfinished thoughts, and pass context between sessions.
|
|
@@ -95,15 +99,11 @@ The OS connects your AIs. Add-ons are what they actually use. Each one is a full
|
|
|
95
99
|
- Open-source agent runtime. Run AI agents 24/7 with identity, memory, and tool access. The existence proof for LDM OS.
|
|
96
100
|
- [Read more about OpenClaw](https://github.com/openclaw/openclaw)
|
|
97
101
|
|
|
98
|
-
|
|
99
|
-
- Cross-platform agent bridge. Enables Claude Code CLI to talk to OpenClaw CLI without a human in the middle.
|
|
100
|
-
- [Read more about Bridge](https://github.com/wipcomputer/wip-bridge)
|
|
101
|
-
|
|
102
|
-
[See all skills](docs/optional-skills.md)
|
|
102
|
+
[See all skills](docs/skills/README.md)
|
|
103
103
|
|
|
104
104
|
## More Info
|
|
105
105
|
|
|
106
|
-
- [Architecture, principles, and technical details](TECHNICAL.md)
|
|
106
|
+
- [Architecture, principles, and technical details](docs/universal-installer/TECHNICAL.md)
|
|
107
107
|
|
|
108
108
|
## License
|
|
109
109
|
|
package/SKILL.md
CHANGED
package/bin/ldm.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* ldm --version Show version
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from 'node:fs';
|
|
20
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, cpSync, chmodSync } from 'node:fs';
|
|
21
21
|
import { join, basename, resolve, dirname } from 'node:path';
|
|
22
22
|
import { execSync } from 'node:child_process';
|
|
23
23
|
import { fileURLToPath } from 'node:url';
|
|
@@ -146,6 +146,28 @@ function cleanStaleHooks() {
|
|
|
146
146
|
return cleaned;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
// ── Boot hook sync (#49) ──
|
|
150
|
+
|
|
151
|
+
function syncBootHook() {
|
|
152
|
+
const srcBoot = join(__dirname, '..', 'src', 'boot', 'boot-hook.mjs');
|
|
153
|
+
const destBoot = join(LDM_ROOT, 'shared', 'boot', 'boot-hook.mjs');
|
|
154
|
+
|
|
155
|
+
if (!existsSync(srcBoot)) return false;
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
const srcContent = readFileSync(srcBoot, 'utf8');
|
|
159
|
+
let destContent = '';
|
|
160
|
+
try { destContent = readFileSync(destBoot, 'utf8'); } catch {}
|
|
161
|
+
|
|
162
|
+
if (srcContent !== destContent) {
|
|
163
|
+
mkdirSync(dirname(destBoot), { recursive: true });
|
|
164
|
+
writeFileSync(destBoot, srcContent);
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
} catch {}
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
|
|
149
171
|
// ── Catalog helpers ──
|
|
150
172
|
|
|
151
173
|
function loadCatalog() {
|
|
@@ -172,6 +194,7 @@ async function cmdInit() {
|
|
|
172
194
|
join(LDM_ROOT, 'messages'),
|
|
173
195
|
join(LDM_ROOT, 'shared', 'boot'),
|
|
174
196
|
join(LDM_ROOT, 'shared', 'cron'),
|
|
197
|
+
join(LDM_ROOT, 'hooks'),
|
|
175
198
|
];
|
|
176
199
|
|
|
177
200
|
const existing = existsSync(VERSION_PATH);
|
|
@@ -230,6 +253,27 @@ async function cmdInit() {
|
|
|
230
253
|
console.log(` + registry.json created`);
|
|
231
254
|
}
|
|
232
255
|
|
|
256
|
+
// Install global git pre-commit hook (blocks commits on main)
|
|
257
|
+
const hooksDir = join(LDM_ROOT, 'hooks');
|
|
258
|
+
const preCommitDest = join(hooksDir, 'pre-commit');
|
|
259
|
+
const preCommitSrc = join(__dirname, '..', 'templates', 'hooks', 'pre-commit');
|
|
260
|
+
if (!existsSync(hooksDir)) mkdirSync(hooksDir, { recursive: true });
|
|
261
|
+
if (existsSync(preCommitSrc)) {
|
|
262
|
+
cpSync(preCommitSrc, preCommitDest);
|
|
263
|
+
chmodSync(preCommitDest, 0o755);
|
|
264
|
+
// Set global hooksPath if not already set to somewhere else
|
|
265
|
+
try {
|
|
266
|
+
const currentHooksPath = execSync('git config --global core.hooksPath', { encoding: 'utf8' }).trim();
|
|
267
|
+
if (currentHooksPath !== hooksDir) {
|
|
268
|
+
console.log(` ! core.hooksPath already set to ${currentHooksPath}. Not overwriting.`);
|
|
269
|
+
}
|
|
270
|
+
} catch {
|
|
271
|
+
// Not set. Set it.
|
|
272
|
+
execSync(`git config --global core.hooksPath "${hooksDir}"`);
|
|
273
|
+
console.log(` + git pre-commit hook installed (blocks commits on main)`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
233
277
|
console.log('');
|
|
234
278
|
console.log(` LDM OS v${PKG_VERSION} initialized at ${LDM_ROOT}`);
|
|
235
279
|
console.log('');
|
|
@@ -644,6 +688,11 @@ async function cmdInstallCatalog() {
|
|
|
644
688
|
updated++;
|
|
645
689
|
}
|
|
646
690
|
|
|
691
|
+
// Sync boot hook from npm package (#49)
|
|
692
|
+
if (syncBootHook()) {
|
|
693
|
+
ok('Boot hook updated (sessions, messages, updates now active)');
|
|
694
|
+
}
|
|
695
|
+
|
|
647
696
|
console.log('');
|
|
648
697
|
console.log(` Updated ${updated}/${updatable.length} extension(s).`);
|
|
649
698
|
|
|
@@ -1345,7 +1394,7 @@ async function main() {
|
|
|
1345
1394
|
await cmdUpdateAll();
|
|
1346
1395
|
break;
|
|
1347
1396
|
case 'doctor':
|
|
1348
|
-
cmdDoctor();
|
|
1397
|
+
await cmdDoctor();
|
|
1349
1398
|
break;
|
|
1350
1399
|
case 'status':
|
|
1351
1400
|
cmdStatus();
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// wip-install: thin bootstrap + delegate to ldm install.
|
|
3
|
+
// If ldm is on PATH, delegates immediately.
|
|
4
|
+
// If not, installs LDM OS from npm, then delegates.
|
|
5
|
+
// Replaces the standalone 700-line install.js from wip-ai-devops-toolbox.
|
|
6
|
+
|
|
7
|
+
import { run } from '../lib/bootstrap.mjs';
|
|
8
|
+
run(process.argv.slice(2));
|
package/docs/acp/README.md
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# ACP Compatibility ... Technical Reference
|
|
2
|
+
|
|
3
|
+
## Protocols
|
|
4
|
+
|
|
5
|
+
| Protocol | Full Name | Origin | License | Wire Format |
|
|
6
|
+
|----------|-----------|--------|---------|-------------|
|
|
7
|
+
| ACP-Client | Agent Client Protocol | Zed Industries | Apache 2.0 | JSON-RPC (stdio) + HTTP/WebSocket |
|
|
8
|
+
| ACP-Comm | Agent Communication Protocol | IBM / Linux Foundation | Apache 2.0 | REST/HTTP |
|
|
9
|
+
| MCP | Model Context Protocol | Anthropic | MIT | JSON-RPC (stdio) |
|
|
10
|
+
|
|
11
|
+
## How LDM OS Uses Each
|
|
12
|
+
|
|
13
|
+
**MCP (current):** All LDM OS tools (bridge, sessions, messages, updates, crystal) are MCP servers. Claude Code, Cursor, and any MCP client can use them. This is the primary interface.
|
|
14
|
+
|
|
15
|
+
**ACP-Client (available, not configured):** OpenClaw implements ACP-Client via `@agentclientprotocol/sdk`. It enables IDE-to-agent communication (Zed, VS Code). LDM OS could expose services via ACP-Client for IDE integration. The transport-agnostic core design supports adding ACP-Client as another wrapper.
|
|
16
|
+
|
|
17
|
+
**ACP-Comm (not implemented):** Agent-to-agent REST protocol. LDM OS's file-based message bus and session registry serve the same purpose locally. Cloud relay (Phase 7) may evaluate ACP-Comm as a wire protocol for remote agent-to-agent communication.
|
|
18
|
+
|
|
19
|
+
## Architecture
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
LDM OS Core (pure functions, zero deps)
|
|
23
|
+
|
|
|
24
|
+
|-- MCP wrapper (current, all tools)
|
|
25
|
+
|-- ACP-Client wrapper (future, IDE integration)
|
|
26
|
+
|-- ACP-Comm wrapper (future, cloud relay)
|
|
27
|
+
|-- HTTP wrapper (future, web/iOS)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Same core logic. Different transports. The core doesn't know or care which protocol is calling it.
|
|
31
|
+
|
|
32
|
+
## License Compatibility
|
|
33
|
+
|
|
34
|
+
Both ACP protocols are Apache 2.0. LDM OS is MIT + AGPLv3 dual license. Apache 2.0 is compatible with both. No license conflicts.
|
|
35
|
+
|
|
36
|
+
## Key Files
|
|
37
|
+
|
|
38
|
+
| File | What |
|
|
39
|
+
|------|------|
|
|
40
|
+
| `src/bridge/mcp-server.ts` | MCP server (current interface) |
|
|
41
|
+
| `lib/sessions.mjs` | Session register (could expose via ACP-Comm) |
|
|
42
|
+
| `lib/messages.mjs` | Message bus (could expose via ACP-Comm) |
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
###### WIP Computer
|
|
2
|
+
|
|
3
|
+
# Bridge
|
|
4
|
+
|
|
5
|
+
## Your AIs talk to each other.
|
|
6
|
+
|
|
7
|
+
Cross-platform agent communication. Bridge (MCP), Agent Client Protocol (ACP-Client, Zed Industries), and Agent Communication Protocol (ACP-Comm, IBM/Linux Foundation). Three protocols, one system. Claude Code sends a message, OpenClaw responds. OpenClaw sends a task, Claude Code executes it.
|
|
8
|
+
|
|
9
|
+
## Three Protocols, One System
|
|
10
|
+
|
|
11
|
+
LDM OS uses three complementary protocols. Bridge is one of them.
|
|
12
|
+
|
|
13
|
+
| | Bridge | ACP-Client | ACP-Comm |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| **What** | Agent-to-agent messaging + shared memory | IDE-to-agent communication | Agent-to-agent REST API |
|
|
16
|
+
| **Protocol** | MCP (JSON-RPC over stdio) | JSON-RPC over stdio + WebSocket | REST/HTTP |
|
|
17
|
+
| **Built by** | WIP Computer | Zed Industries | IBM / Linux Foundation |
|
|
18
|
+
| **In LDM OS** | Core (v0.3.0+) | Available via OpenClaw | Planned (Cloud Relay) |
|
|
19
|
+
| **What it connects** | Claude Code <-> OpenClaw agents | IDEs (Zed, VS Code) <-> agents | Cloud agents <-> each other |
|
|
20
|
+
| **Memory access** | Yes (search + read across agents) | No | No |
|
|
21
|
+
| **Skill sharing** | Yes (OpenClaw skills as MCP tools) | No | No |
|
|
22
|
+
| **Where it runs** | Localhost only | Localhost (stdio) + remote (WebSocket) | Cloud (HTTP endpoints) |
|
|
23
|
+
|
|
24
|
+
**Bridge** is how your AIs talk to each other and share memory. **ACP-Client** is how IDEs talk to agents (OpenClaw already implements this). **ACP-Comm** is how agents would talk across the network (planned for Cloud Relay, Phase 7).
|
|
25
|
+
|
|
26
|
+
All three are Apache 2.0 compatible with our MIT + AGPL license. See [ACP docs](../acp/README.md).
|
|
27
|
+
|
|
28
|
+
## Tools
|
|
29
|
+
|
|
30
|
+
| Tool | What |
|
|
31
|
+
|------|------|
|
|
32
|
+
| `lesa_send_message` | Send a message to the OpenClaw agent. Gets a response. |
|
|
33
|
+
| `lesa_check_inbox` | Check for messages the agent sent to you. |
|
|
34
|
+
| `lesa_conversation_search` | Semantic search over conversation history. |
|
|
35
|
+
| `lesa_memory_search` | Keyword search across workspace files. |
|
|
36
|
+
| `lesa_read_workspace` | Read a file from the agent's workspace. |
|
|
37
|
+
| `oc_skills_list` | List all OpenClaw skills. |
|
|
38
|
+
| `oc_skill_*` | Run any OpenClaw skill with scripts. |
|
|
39
|
+
|
|
40
|
+
## Message Flow
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
CC --lesa_send_message--> OpenClaw Gateway (localhost:18789) --> Lesa
|
|
44
|
+
CC <--lesa_check_inbox--- HTTP Inbox (localhost:18790) <-- Lesa
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Both directions are live. Everything is localhost. No cloud.
|
|
48
|
+
|
|
49
|
+
## Part of LDM OS
|
|
50
|
+
|
|
51
|
+
Bridge ships with LDM OS v0.3.0+. The standalone repo is deprecated: [wip-bridge-deprecated](https://github.com/wipcomputer/wip-bridge-deprecated).
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
[Technical Reference](./TECHNICAL.md)
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Bridge ... Technical Reference
|
|
2
|
+
|
|
3
|
+
## Architecture
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
Claude Code CLI
|
|
7
|
+
|
|
|
8
|
+
|-- MCP stdio --> wip-bridge MCP server (single process)
|
|
9
|
+
| |
|
|
10
|
+
| |-- lesa_send_message --> HTTP POST localhost:18789 (OpenClaw gateway)
|
|
11
|
+
| | |
|
|
12
|
+
| | v
|
|
13
|
+
| | Lesa's agent pipeline
|
|
14
|
+
| | |
|
|
15
|
+
| | v
|
|
16
|
+
| | Response returned
|
|
17
|
+
| |
|
|
18
|
+
| |-- lesa_check_inbox --> HTTP GET localhost:18790 (Bridge inbox)
|
|
19
|
+
| |
|
|
20
|
+
| |-- lesa_conversation_search --> SQLite (context-embeddings.sqlite)
|
|
21
|
+
| |
|
|
22
|
+
| |-- lesa_memory_search --> filesystem (workspace/*.md)
|
|
23
|
+
| |
|
|
24
|
+
| |-- oc_skill_* --> exec scripts in ~/.openclaw/extensions/*/skills/
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## MCP Tools
|
|
28
|
+
|
|
29
|
+
| Tool | What | Transport |
|
|
30
|
+
|------|------|-----------|
|
|
31
|
+
| `lesa_send_message` | Send message to OpenClaw agent | HTTP POST to gateway (localhost:18789) |
|
|
32
|
+
| `lesa_check_inbox` | Check for pending messages from agent | In-memory queue (drained on read) |
|
|
33
|
+
| `lesa_conversation_search` | Semantic search over conversation history | SQLite + OpenAI embeddings |
|
|
34
|
+
| `lesa_memory_search` | Keyword search across workspace .md files | Filesystem scan |
|
|
35
|
+
| `lesa_read_workspace` | Read a specific workspace file | Filesystem |
|
|
36
|
+
| `oc_skill_*` | Execute OpenClaw skill scripts | child_process exec |
|
|
37
|
+
| `oc_skills_list` | List all available OpenClaw skills | Filesystem scan |
|
|
38
|
+
|
|
39
|
+
## Config Resolution
|
|
40
|
+
|
|
41
|
+
Bridge resolves config in two steps:
|
|
42
|
+
|
|
43
|
+
1. **LDM OS path** (`~/.ldm/config.json`): checks for `openclawDir`, `workspaceDir`, `dbPath`
|
|
44
|
+
2. **Legacy path** (`OPENCLAW_DIR` env or `~/.openclaw`): fallback
|
|
45
|
+
|
|
46
|
+
Both return the same `BridgeConfig` shape: `openclawDir`, `workspaceDir`, `dbPath`, `inboxPort`, `embeddingModel`, `embeddingDimensions`.
|
|
47
|
+
|
|
48
|
+
## Gateway Authentication
|
|
49
|
+
|
|
50
|
+
Bridge reads the gateway auth token from `~/.openclaw/openclaw.json` (`gateway.auth.token`). Every HTTP request to the gateway includes `Authorization: Bearer <token>`.
|
|
51
|
+
|
|
52
|
+
## Conversation Search
|
|
53
|
+
|
|
54
|
+
Two modes:
|
|
55
|
+
1. **Vector search** (if OpenAI API key available): embeds query, computes cosine similarity against all conversation chunks, applies recency weighting (exponential decay, half-life ~50 days)
|
|
56
|
+
2. **Text search** (fallback): SQL LIKE query against chunk text
|
|
57
|
+
|
|
58
|
+
The API key is resolved from: environment variable > 1Password via service account token.
|
|
59
|
+
|
|
60
|
+
## Inbox Server
|
|
61
|
+
|
|
62
|
+
Bridge starts a localhost-only HTTP server on port 18790:
|
|
63
|
+
- `POST /message`: push a message (from OpenClaw agent)
|
|
64
|
+
- `GET /status`: check pending count
|
|
65
|
+
|
|
66
|
+
Messages are held in memory. `lesa_check_inbox` drains the queue.
|
|
67
|
+
|
|
68
|
+
## Key Files
|
|
69
|
+
|
|
70
|
+
| File | What |
|
|
71
|
+
|------|------|
|
|
72
|
+
| `src/bridge/core.ts` | Pure logic: config, messaging, search, skills |
|
|
73
|
+
| `src/bridge/mcp-server.ts` | MCP server: tool registration, inbox HTTP server |
|
|
74
|
+
| `src/bridge/cli.ts` | CLI wrapper (`lesa` command) |
|
|
75
|
+
| `dist/bridge/` | Compiled output (ships with npm package) |
|
|
76
|
+
|
|
77
|
+
## Node Communication (Future)
|
|
78
|
+
|
|
79
|
+
Bridge currently works localhost only (Core). For Node -> Core communication:
|
|
80
|
+
- Phase 7 (Cloud Relay) handles messaging via encrypted Cloudflare R2 dead drops
|
|
81
|
+
- Search, workspace read, and skill execution from a Node are NOT yet covered
|
|
82
|
+
- Two proposed solutions: proxy pattern (Node sends requests through relay) and sync pattern (replicate crystal.db to Node)
|
|
83
|
+
|
|
84
|
+
See `ai/products/plans-prds/current/ldm-stack-spec.md` for the full platform matrix.
|
|
85
|
+
|
|
86
|
+
## CLI Usage
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
lesa send "What are you working on?" # Message the OpenClaw agent
|
|
90
|
+
lesa search "API key resolution" # Semantic search (recency-weighted)
|
|
91
|
+
lesa memory "compaction" # Keyword search across workspace files
|
|
92
|
+
lesa read MEMORY.md # Read a workspace file
|
|
93
|
+
lesa read memory/2026-02-10.md # Read a daily log
|
|
94
|
+
lesa status # Show bridge configuration
|
|
95
|
+
lesa diagnose # Check gateway, inbox, DB, skills health
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Skill Bridge
|
|
99
|
+
|
|
100
|
+
On startup, Bridge scans OpenClaw's skill directories and exposes them as MCP tools. Claude Code gets the same skills the OpenClaw agent has.
|
|
101
|
+
|
|
102
|
+
1. Scans `extensions/*/node_modules/openclaw/skills/` (built-in) and `extensions/*/skills/` (custom)
|
|
103
|
+
2. Parses each `SKILL.md` frontmatter for name, description, requirements
|
|
104
|
+
3. Skills with a `scripts/` folder get registered as executable `oc_skill_{name}` tools
|
|
105
|
+
4. All skills show up in `oc_skills_list`
|
|
106
|
+
|
|
107
|
+
Skills that need API keys get them from the environment. The op-secrets plugin sets these from 1Password.
|
|
108
|
+
|
|
109
|
+
## Inbox Watcher (Auto-Relay)
|
|
110
|
+
|
|
111
|
+
Polls the inbox endpoint and auto-injects messages into a running Claude Code tmux session.
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
bash scripts/watch.sh # Alert mode (notification only)
|
|
115
|
+
bash scripts/watch.sh --auto claude:0.0 # Auto-inject into tmux pane
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
| Setting | Default | Description |
|
|
119
|
+
|---------|---------|-------------|
|
|
120
|
+
| `POLL_INTERVAL` | `5` | Seconds between inbox checks |
|
|
121
|
+
| `COOLDOWN` | `30` | Minimum seconds between alerts |
|
|
122
|
+
| `INBOX_URL` | `http://127.0.0.1:18790/status` | Inbox status endpoint |
|
|
123
|
+
|
|
124
|
+
## OpenClaw Skills (Lesa -> CC)
|
|
125
|
+
|
|
126
|
+
Two skills shipped with Bridge for the reverse direction:
|
|
127
|
+
|
|
128
|
+
| Skill | What |
|
|
129
|
+
|-------|------|
|
|
130
|
+
| `claude-code` | Invoke Claude Code CLI for coding tasks (`claude -p`) |
|
|
131
|
+
| `send-to-claude-code` | Push messages into CC's live inbox (POST localhost:18790) |
|
|
132
|
+
|
|
133
|
+
## Environment Variables
|
|
134
|
+
|
|
135
|
+
| Variable | Required | Default | Description |
|
|
136
|
+
|----------|----------|---------|-------------|
|
|
137
|
+
| `OPENCLAW_DIR` | Yes | `~/.openclaw` | Path to OpenClaw installation |
|
|
138
|
+
| `OPENAI_API_KEY` | For semantic search | Resolved from 1Password | OpenAI API key for embeddings |
|
|
139
|
+
| `LESA_BRIDGE_INBOX_PORT` | No | `18790` | Inbox HTTP server port |
|
|
140
|
+
|
|
141
|
+
## Ports
|
|
142
|
+
|
|
143
|
+
| Port | Service | Bound to |
|
|
144
|
+
|------|---------|----------|
|
|
145
|
+
| 18789 | OpenClaw gateway | localhost (managed by OpenClaw) |
|
|
146
|
+
| 18790 | Bridge inbox | localhost (managed by Bridge) |
|
|
147
|
+
|
|
148
|
+
## Requirements
|
|
149
|
+
|
|
150
|
+
- OpenClaw running with gateway enabled
|
|
151
|
+
- `gateway.auth.token` set in `openclaw.json`
|
|
152
|
+
- `gateway.http.endpoints.chatCompletions.enabled: true`
|
|
153
|
+
- OpenAI API key for semantic search (falls back to text search without it)
|
package/docs/recall/README.md
CHANGED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Recall ... Technical Reference
|
|
2
|
+
|
|
3
|
+
## Boot Sequence
|
|
4
|
+
|
|
5
|
+
Recall is implemented as a SessionStart hook. When Claude Code opens a session, the boot hook loads context files in order:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
1. CLAUDE.md Identity + structure (harness config)
|
|
9
|
+
2. SHARED-CONTEXT.md Current state (under 50 lines)
|
|
10
|
+
3. Most recent journal Narrative from last session
|
|
11
|
+
4. Daily logs (today + yesterday) Recency
|
|
12
|
+
5. Full history (cold start) Dream Weaver narrative
|
|
13
|
+
6. CONTEXT.md Agent's own state
|
|
14
|
+
7. SOUL.md Who this agent is
|
|
15
|
+
8. Agent journals Check for newer entries
|
|
16
|
+
9. Agent daily logs Check for newer entries
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Key Files
|
|
20
|
+
|
|
21
|
+
| File | What |
|
|
22
|
+
|------|------|
|
|
23
|
+
| `src/boot/boot-hook.mjs` | SessionStart hook (reads + injects context) |
|
|
24
|
+
| `src/boot/boot-config.json` | Which files to load, in what order |
|
|
25
|
+
| `src/boot/installer.mjs` | Deploys boot hook to `~/.ldm/shared/boot/` |
|
|
26
|
+
|
|
27
|
+
## How It Works
|
|
28
|
+
|
|
29
|
+
The boot hook reads `boot-config.json` to determine which files to load. Each entry specifies a path pattern and priority. Files are read in priority order and concatenated into the session context.
|
|
30
|
+
|
|
31
|
+
The hook runs with a 15-second timeout. If any file is missing, it's skipped silently. The boot sequence is additive. It never modifies files, only reads them.
|
|
32
|
+
|
|
33
|
+
## Harness Differences
|
|
34
|
+
|
|
35
|
+
**Claude Code CLI:** Full boot sequence. Identity, context, journals, daily logs all loaded via SessionStart hook.
|
|
36
|
+
|
|
37
|
+
**OpenClaw:** Has its own boot sequence (workspace files). Recall provides backup context loading if the harness boot fails or is incomplete.
|
|
38
|
+
|
|
39
|
+
## Session Registration
|
|
40
|
+
|
|
41
|
+
On boot, Recall also registers the session in the Agent Register (`~/.ldm/sessions/`). This enables other sessions to discover this one via `ldm sessions`.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Shared Workspace ... Technical Reference
|
|
2
|
+
|
|
3
|
+
## Directory Structure
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
~/.ldm/
|
|
7
|
+
config.json Machine-level config
|
|
8
|
+
version.json Installed version + timestamps
|
|
9
|
+
extensions/
|
|
10
|
+
registry.json Extension metadata
|
|
11
|
+
memory-crystal/ Extension files
|
|
12
|
+
wip-release/ Extension files
|
|
13
|
+
...
|
|
14
|
+
agents/
|
|
15
|
+
cc-mini/ Claude Code on Mac Mini
|
|
16
|
+
IDENTITY.md
|
|
17
|
+
SOUL.md
|
|
18
|
+
CONTEXT.md
|
|
19
|
+
REFERENCE.md
|
|
20
|
+
config.json
|
|
21
|
+
memory/
|
|
22
|
+
transcripts/ Raw JSONL session files
|
|
23
|
+
sessions/ MD per-session summaries
|
|
24
|
+
daily/ Daily log breadcrumbs
|
|
25
|
+
journals/ Dream Weaver narrative output
|
|
26
|
+
oc-lesa-mini/ OpenClaw/Lesa on Mac Mini
|
|
27
|
+
memory/
|
|
28
|
+
transcripts/ Raw JSONL copies (backup)
|
|
29
|
+
workspace/ Workspace .md snapshots
|
|
30
|
+
daily/ Daily log copies
|
|
31
|
+
memory/
|
|
32
|
+
crystal.db Shared vector DB (all agents)
|
|
33
|
+
sessions/ Active session files (Agent Register)
|
|
34
|
+
messages/ Inter-session messages (Message Bus)
|
|
35
|
+
shared/
|
|
36
|
+
boot/ Boot hook files
|
|
37
|
+
cron/ Cron job scripts
|
|
38
|
+
state/ Capture watermarks, role state
|
|
39
|
+
secrets/ Encryption keys, relay tokens
|
|
40
|
+
bin/ Deployed scripts
|
|
41
|
+
backups/ Daily backups
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Sacred Data
|
|
45
|
+
|
|
46
|
+
These paths are never overwritten during install or update:
|
|
47
|
+
|
|
48
|
+
- `memory/` (crystal.db, all vector data)
|
|
49
|
+
- `agents/` (identity, soul, context, journals, transcripts)
|
|
50
|
+
- `secrets/` (encryption keys, tokens)
|
|
51
|
+
- `state/` (watermarks, capture state)
|
|
52
|
+
- `backups/` (daily snapshots)
|
|
53
|
+
|
|
54
|
+
Only `extensions/` and `shared/` are updated by `ldm install`.
|
|
55
|
+
|
|
56
|
+
## Agent Identity
|
|
57
|
+
|
|
58
|
+
One agent per harness per machine. The agent ID is deterministic:
|
|
59
|
+
|
|
60
|
+
| Agent ID | Harness | Machine |
|
|
61
|
+
|----------|---------|---------|
|
|
62
|
+
| `cc-mini` | Claude Code CLI | Mac Mini |
|
|
63
|
+
| `cc-air` | Claude Code CLI | MacBook Air |
|
|
64
|
+
| `oc-lesa-mini` | OpenClaw | Mac Mini |
|
|
65
|
+
|
|
66
|
+
All agents share one `crystal.db`. Memory is shared. Identity is per-agent.
|
|
67
|
+
|
|
68
|
+
## Key Files
|
|
69
|
+
|
|
70
|
+
| File | What |
|
|
71
|
+
|------|------|
|
|
72
|
+
| `bin/ldm.js` | CLI: `ldm init` creates the workspace |
|
|
73
|
+
| `lib/deploy.mjs` | Extension deployment engine |
|
|
74
|
+
| `lib/state.mjs` | System state detection |
|
|
75
|
+
| `lib/safe.mjs` | Trash management (never delete, always move) |
|
package/docs/skills/README.md
CHANGED
|
@@ -6,6 +6,11 @@ Your AIs are only as powerful as what you give them. Here's everything available
|
|
|
6
6
|
|
|
7
7
|
## Core
|
|
8
8
|
|
|
9
|
+
**Bridge**
|
|
10
|
+
- Cross-platform agent communication. Bridge (MCP), Agent Client Protocol (ACP-Client), and Agent Communication Protocol (ACP-Comm). Three protocols, one system.
|
|
11
|
+
- *Included with LDM OS*
|
|
12
|
+
- [Read more about Bridge](../bridge/README.md)
|
|
13
|
+
|
|
9
14
|
**Memory Crystal**
|
|
10
15
|
- All your AI tools. One shared memory. Private, searchable, sovereign. Memory Crystal lets all your AIs remember you ... together. You use multiple AIs. They don't talk to each other. They can't search what the others know. Memory Crystal fixes this. All your AIs share one memory. Searchable and private. Anywhere in the world.
|
|
11
16
|
- *Stable*
|
|
@@ -28,10 +33,6 @@ Your AIs are only as powerful as what you give them. Here's everything available
|
|
|
28
33
|
- Open-source agent runtime. Run AI agents 24/7 with identity, memory, and tool access. The existence proof for LDM OS.
|
|
29
34
|
- [Read more about OpenClaw](https://github.com/openclaw/openclaw)
|
|
30
35
|
|
|
31
|
-
**Bridge**
|
|
32
|
-
- Cross-platform agent bridge. Enables Claude Code CLI to talk to OpenClaw CLI without a human in the middle.
|
|
33
|
-
- [Read more about Bridge](https://github.com/wipcomputer/wip-bridge)
|
|
34
|
-
|
|
35
36
|
## Identity
|
|
36
37
|
|
|
37
38
|
**Mirror Test** *(not yet public)*
|
|
@@ -75,3 +76,7 @@ Your AIs are only as powerful as what you give them. Here's everything available
|
|
|
75
76
|
**X Platform**
|
|
76
77
|
- X Platform API. Read posts, search tweets, post, upload media.
|
|
77
78
|
- [Read more about X Platform](https://github.com/wipcomputer/wip-xai-x)
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
[Technical Reference](./TECHNICAL.md)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Skills ... Technical Reference
|
|
2
|
+
|
|
3
|
+
## Catalog
|
|
4
|
+
|
|
5
|
+
Skills are defined in `catalog.json` at the LDM OS root. Each entry has:
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"id": "memory-crystal",
|
|
10
|
+
"name": "Memory Crystal",
|
|
11
|
+
"description": "Persistent memory for your AI.",
|
|
12
|
+
"npm": "@wipcomputer/memory-crystal",
|
|
13
|
+
"repo": "wipcomputer/memory-crystal",
|
|
14
|
+
"registryMatches": ["memory-crystal"],
|
|
15
|
+
"cliMatches": ["crystal"],
|
|
16
|
+
"recommended": true,
|
|
17
|
+
"status": "stable"
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Stacks
|
|
22
|
+
|
|
23
|
+
Stacks group skills for team installs. Defined in `catalog.json`:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"stacks": {
|
|
28
|
+
"core": {
|
|
29
|
+
"name": "WIP Core",
|
|
30
|
+
"components": ["memory-crystal", "wip-ai-devops-toolbox", "wip-1password", "wip-markdown-viewer"],
|
|
31
|
+
"mcpServers": []
|
|
32
|
+
},
|
|
33
|
+
"web": {
|
|
34
|
+
"name": "Web Development",
|
|
35
|
+
"components": [],
|
|
36
|
+
"mcpServers": [
|
|
37
|
+
{ "name": "playwright", "command": "npx", "args": ["-y", "@playwright/mcp@latest"] }
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Stacks are composable via the `includes` field.
|
|
45
|
+
|
|
46
|
+
## Interface Detection
|
|
47
|
+
|
|
48
|
+
`ldm install` auto-detects which interfaces a repo supports:
|
|
49
|
+
|
|
50
|
+
| Pattern | Interface | Install Action |
|
|
51
|
+
|---------|-----------|---------------|
|
|
52
|
+
| `package.json` with `bin` | CLI | `npm install -g` from registry |
|
|
53
|
+
| `main` or `exports` | Module | Reports import path |
|
|
54
|
+
| `mcp-server.mjs` | MCP | `claude mcp add --scope user` |
|
|
55
|
+
| `openclaw.plugin.json` | OpenClaw Plugin | Deploy to `~/.ldm/extensions/` + `~/.openclaw/extensions/` |
|
|
56
|
+
| `SKILL.md` | Skill | Deploy to `~/.openclaw/skills/` |
|
|
57
|
+
| `guard.mjs` or `claudeCode.hook` | CC Hook | Add to `~/.claude/settings.json` |
|
|
58
|
+
| `.claude-plugin/plugin.json` | CC Plugin | Register with marketplace |
|
|
59
|
+
|
|
60
|
+
## Key Files
|
|
61
|
+
|
|
62
|
+
| File | What |
|
|
63
|
+
|------|------|
|
|
64
|
+
| `catalog.json` | Component + stack definitions |
|
|
65
|
+
| `lib/detect.mjs` | Interface detection engine |
|
|
66
|
+
| `lib/deploy.mjs` | Deployment engine |
|
|
67
|
+
| `bin/ldm.js` | `ldm stack` and `ldm install` commands |
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# System Pulse ... Technical Reference
|
|
2
|
+
|
|
3
|
+
## Commands
|
|
4
|
+
|
|
5
|
+
### ldm doctor
|
|
6
|
+
|
|
7
|
+
Checks system health across all components:
|
|
8
|
+
|
|
9
|
+
1. `~/.ldm/` exists
|
|
10
|
+
2. `version.json` valid and version matches CLI
|
|
11
|
+
3. Full system state scan (extensions, MCP, CLIs, skills)
|
|
12
|
+
4. Reconciliation (registry vs deployed vs MCP registered)
|
|
13
|
+
5. Sacred directories exist (memory/, agents/, state/, sessions/, messages/)
|
|
14
|
+
6. Claude Code hooks configured (checks for stale paths)
|
|
15
|
+
7. MCP servers registered
|
|
16
|
+
8. CLI binaries on PATH
|
|
17
|
+
|
|
18
|
+
With `--fix`:
|
|
19
|
+
- Removes stale registry entries (registered but not deployed)
|
|
20
|
+
- Removes stale hook paths from `~/.claude/settings.json` (missing files, `/tmp/` paths)
|
|
21
|
+
|
|
22
|
+
### ldm status
|
|
23
|
+
|
|
24
|
+
Quick overview: version, install date, extension count, extension list with versions.
|
|
25
|
+
|
|
26
|
+
### ldm updates
|
|
27
|
+
|
|
28
|
+
Shows cached update check results. Use `--check` to re-scan npm for newer versions of installed extensions.
|
|
29
|
+
|
|
30
|
+
## State Detection
|
|
31
|
+
|
|
32
|
+
`lib/state.mjs` scans the real system:
|
|
33
|
+
|
|
34
|
+
| Source | What it finds |
|
|
35
|
+
|--------|--------------|
|
|
36
|
+
| `~/.claude.json` | MCP servers (user scope) |
|
|
37
|
+
| `~/.ldm/extensions/` | Deployed extensions (LDM) |
|
|
38
|
+
| `~/.openclaw/extensions/` | Deployed extensions (OpenClaw) |
|
|
39
|
+
| `~/.ldm/extensions/registry.json` | Registry metadata |
|
|
40
|
+
| PATH | CLI binaries (with 5s timeout per binary) |
|
|
41
|
+
| `~/.openclaw/skills/` | Deployed skills |
|
|
42
|
+
|
|
43
|
+
Reconciliation compares all sources and determines status:
|
|
44
|
+
- `healthy`: registered + deployed + source available
|
|
45
|
+
- `installed-unlinked`: registered + deployed, no source repo
|
|
46
|
+
- `registered-missing`: in registry but not deployed
|
|
47
|
+
- `deployed-unregistered`: deployed but not in registry
|
|
48
|
+
- `mcp-only`: MCP server without LDM management
|
|
49
|
+
|
|
50
|
+
## Key Files
|
|
51
|
+
|
|
52
|
+
| File | What |
|
|
53
|
+
|------|------|
|
|
54
|
+
| `bin/ldm.js` | `cmdDoctor()`, `cmdStatus()`, `cmdUpdates()` |
|
|
55
|
+
| `lib/state.mjs` | `detectSystemState()`, `reconcileState()`, `formatReconciliation()` |
|
|
56
|
+
| `lib/updates.mjs` | npm version checking, manifest caching |
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# The Universal Interface Specification
|
|
2
|
+
|
|
3
|
+
Every tool is a sensor, an actuator, or both. Every tool should be accessible through multiple interfaces. We call this the Universal Interface.
|
|
4
|
+
|
|
5
|
+
This is the spec.
|
|
6
|
+
|
|
7
|
+
## The Six Interfaces
|
|
8
|
+
|
|
9
|
+
### 1. CLI
|
|
10
|
+
|
|
11
|
+
A shell command. The most universal interface. If it has a terminal, it works.
|
|
12
|
+
|
|
13
|
+
**Convention:** `package.json` with a `bin` field.
|
|
14
|
+
|
|
15
|
+
**Detection:** `pkg.bin` exists.
|
|
16
|
+
|
|
17
|
+
**Install:** `npm install -g .` or `npm link`.
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"bin": {
|
|
22
|
+
"wip-grok": "./cli.mjs"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 2. Module
|
|
28
|
+
|
|
29
|
+
An importable ES module. The programmatic interface. Other tools compose with it.
|
|
30
|
+
|
|
31
|
+
**Convention:** `package.json` with `main` or `exports` field. File is `core.mjs` by convention.
|
|
32
|
+
|
|
33
|
+
**Detection:** `pkg.main` or `pkg.exports` exists.
|
|
34
|
+
|
|
35
|
+
**Install:** `npm install <package>` or import directly from path.
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"type": "module",
|
|
40
|
+
"main": "core.mjs",
|
|
41
|
+
"exports": {
|
|
42
|
+
".": "./core.mjs",
|
|
43
|
+
"./cli": "./cli.mjs"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 3. MCP Server
|
|
49
|
+
|
|
50
|
+
A JSON-RPC server implementing the Model Context Protocol. Any MCP-compatible agent can use it.
|
|
51
|
+
|
|
52
|
+
**Convention:** `mcp-server.mjs` (or `.js`, `.ts`) at the repo root. Uses `@modelcontextprotocol/sdk`.
|
|
53
|
+
|
|
54
|
+
**Detection:** One of `mcp-server.mjs`, `mcp-server.js`, `mcp-server.ts`, `dist/mcp-server.js` exists.
|
|
55
|
+
|
|
56
|
+
**Install:** Add to `.mcp.json`:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"tool-name": {
|
|
61
|
+
"command": "node",
|
|
62
|
+
"args": ["/path/to/mcp-server.mjs"]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 4. OpenClaw Plugin
|
|
68
|
+
|
|
69
|
+
A plugin for OpenClaw agents. Lifecycle hooks, tool registration, settings.
|
|
70
|
+
|
|
71
|
+
**Convention:** `openclaw.plugin.json` at the repo root.
|
|
72
|
+
|
|
73
|
+
**Detection:** `openclaw.plugin.json` exists.
|
|
74
|
+
|
|
75
|
+
**Install:** Copy to `~/.openclaw/extensions/<name>/`, run `npm install --omit=dev`.
|
|
76
|
+
|
|
77
|
+
### 5. Skill (SKILL.md)
|
|
78
|
+
|
|
79
|
+
A markdown file that teaches agents when and how to use the tool. The instruction interface.
|
|
80
|
+
|
|
81
|
+
**Convention:** `SKILL.md` at the repo root. YAML frontmatter with name, version, description, metadata.
|
|
82
|
+
|
|
83
|
+
**Detection:** `SKILL.md` exists.
|
|
84
|
+
|
|
85
|
+
**Install:** Referenced by path. Agents read it when they need the tool.
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
---
|
|
89
|
+
name: wip-grok
|
|
90
|
+
version: 1.0.0
|
|
91
|
+
description: xAI Grok API. Search the web, search X, generate images.
|
|
92
|
+
metadata:
|
|
93
|
+
category: search,media
|
|
94
|
+
capabilities:
|
|
95
|
+
- web-search
|
|
96
|
+
- image-generation
|
|
97
|
+
---
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 6. Claude Code Hook
|
|
101
|
+
|
|
102
|
+
A hook that runs during Claude Code's tool lifecycle (PreToolUse, Stop, etc.).
|
|
103
|
+
|
|
104
|
+
**Convention:** `guard.mjs` at repo root, or `claudeCode.hook` in `package.json`.
|
|
105
|
+
|
|
106
|
+
**Detection:** `guard.mjs` exists, or `pkg.claudeCode.hook` is defined.
|
|
107
|
+
|
|
108
|
+
**Install:** Added to `~/.claude/settings.json` under `hooks`.
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"hooks": {
|
|
113
|
+
"PreToolUse": [{
|
|
114
|
+
"matcher": "Edit|Write",
|
|
115
|
+
"hooks": [{
|
|
116
|
+
"type": "command",
|
|
117
|
+
"command": "node /path/to/guard.mjs",
|
|
118
|
+
"timeout": 5
|
|
119
|
+
}]
|
|
120
|
+
}]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Architecture
|
|
126
|
+
|
|
127
|
+
Every repo that follows this spec has the same basic structure:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
your-tool/
|
|
131
|
+
core.mjs pure logic, zero or minimal deps
|
|
132
|
+
cli.mjs thin CLI wrapper around core
|
|
133
|
+
mcp-server.mjs MCP server wrapping core functions as tools
|
|
134
|
+
SKILL.md agent instructions with YAML frontmatter
|
|
135
|
+
package.json name, bin, main, exports, type: module
|
|
136
|
+
README.md human documentation
|
|
137
|
+
ai/ development process (plans, todos, notes)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Not every tool needs all six interfaces. Build the ones that make sense.
|
|
141
|
+
|
|
142
|
+
The minimum viable agent-native tool has two interfaces: **Module** (importable) and **Skill** (agent instructions). Add CLI for humans. Add MCP for agents that speak MCP. Add OpenClaw/CC Hook for specific platforms.
|
|
143
|
+
|
|
144
|
+
## The `ai/` Folder
|
|
145
|
+
|
|
146
|
+
Every repo should have an `ai/` folder. This is where agents and humans collaborate on the project ... plans, todos, dev updates, research notes, conversations.
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
ai/
|
|
150
|
+
plan/ architecture plans, roadmaps
|
|
151
|
+
dev-updates/ what was built, session logs
|
|
152
|
+
todos/
|
|
153
|
+
PUNCHLIST.md blockers to ship
|
|
154
|
+
inboxes/ per-agent action items
|
|
155
|
+
notes/ research, references, raw conversation logs
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The `ai/` folder is the development process. It is not part of the published product.
|
|
159
|
+
|
|
160
|
+
**Public/private split:** If a repo is public, the `ai/` folder should not ship. The recommended pattern is to maintain a private working repo (with `ai/`) and a public repo (everything except `ai/`). The public repo has everything an LLM or human needs to understand and use the tool. The `ai/` folder is operational context for the team building it.
|
|
161
|
+
|
|
162
|
+
## The Reference Installer
|
|
163
|
+
|
|
164
|
+
`ldm install` is the primary installer (part of LDM OS). `wip-install` is the standalone fallback. Both scan a repo, detect which interfaces exist, and install them all. One command.
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
ldm install /path/to/repo # local (via LDM OS)
|
|
168
|
+
ldm install org/repo # from GitHub
|
|
169
|
+
ldm install org/repo --dry-run # detect only
|
|
170
|
+
wip-install /path/to/repo # standalone fallback (bootstraps LDM OS if needed)
|
|
171
|
+
wip-install --json /path/to/repo # JSON output
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
For toolbox repos (with a `tools/` directory containing sub-tools), the installer enters toolbox mode and installs each sub-tool.
|
|
175
|
+
|
|
176
|
+
## Examples
|
|
177
|
+
|
|
178
|
+
### AI DevOps Toolbox (this repo)
|
|
179
|
+
|
|
180
|
+
| # | Tool | Interfaces |
|
|
181
|
+
|---|------|------------|
|
|
182
|
+
| | **Repo Management** | |
|
|
183
|
+
| 1 | [Repo Visibility Guard](tools/wip-repo-permissions-hook/) | CLI + Module + MCP + OpenClaw + Skill + CC Hook |
|
|
184
|
+
| 2 | [Repo Manifest Reconciler](tools/wip-repos/) | CLI + Module + MCP + Skill |
|
|
185
|
+
| 3 | [Repo Init](tools/wip-repo-init/) | CLI + Skill |
|
|
186
|
+
| 4 | [README Formatter](tools/wip-readme-format/) | CLI + Skill |
|
|
187
|
+
| 5 | [Branch Guard](tools/wip-branch-guard/) | CLI + Module + CC Hook |
|
|
188
|
+
| | **License, Compliance, and Protection** | |
|
|
189
|
+
| 6 | [Identity File Protection](tools/wip-file-guard/) | CLI + Module + OpenClaw + Skill + CC Hook |
|
|
190
|
+
| 7 | [License Guard](tools/wip-license-guard/) | CLI + Skill |
|
|
191
|
+
| 8 | [License Rug-Pull Detection](tools/wip-license-hook/) | CLI + Module + MCP + Skill |
|
|
192
|
+
| | **Release & Deploy** | |
|
|
193
|
+
| 9 | [Release Pipeline](tools/wip-release/) | CLI + Module + MCP + Skill |
|
|
194
|
+
| 10 | [Private-to-Public Sync](tools/deploy-public/) | CLI + Skill |
|
|
195
|
+
| 11 | [Post-Merge Branch Naming](tools/post-merge-rename/) | CLI + Skill |
|
|
196
|
+
| 12 | [Universal Installer](tools/wip-universal-installer/) | CLI + Module + Skill |
|
|
197
|
+
|
|
198
|
+
### Other WIP Computer Tools
|
|
199
|
+
|
|
200
|
+
| Repo | Interfaces |
|
|
201
|
+
|------|------------|
|
|
202
|
+
| [Memory Crystal](https://github.com/wipcomputer/memory-crystal) | CLI + Module + MCP + OpenClaw + Skill |
|
|
203
|
+
| [LDM OS](https://github.com/wipcomputer/wip-ldm-os) | CLI + Module + Skill + CC Hook |
|
|
204
|
+
| [wip-grok](https://github.com/wipcomputer/wip-grok) | CLI + Module + MCP + Skill |
|
|
205
|
+
| [wip-x](https://github.com/wipcomputer/wip-x) | CLI + Module + MCP + Skill |
|
|
206
|
+
| [Markdown Viewer](https://github.com/wipcomputer/wip-markdown-viewer) | CLI + Module |
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/bootstrap.mjs
|
|
3
|
+
* Thin bootstrap for wip-install.
|
|
4
|
+
* If ldm is on PATH, delegates to ldm install.
|
|
5
|
+
* If not, installs LDM OS from npm, then delegates.
|
|
6
|
+
* This replaces the 700-line standalone install.js from the toolbox.
|
|
7
|
+
* Zero external dependencies.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { execSync } from 'node:child_process';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check if ldm CLI is available on PATH.
|
|
14
|
+
* @returns {boolean}
|
|
15
|
+
*/
|
|
16
|
+
export function isLdmAvailable() {
|
|
17
|
+
try {
|
|
18
|
+
execSync('ldm --version', { stdio: 'pipe', timeout: 5000 });
|
|
19
|
+
return true;
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Install LDM OS from npm registry.
|
|
27
|
+
* @returns {boolean} true if install succeeded
|
|
28
|
+
*/
|
|
29
|
+
export function bootstrapLdmOs() {
|
|
30
|
+
try {
|
|
31
|
+
execSync('npm install -g @wipcomputer/wip-ldm-os', { stdio: 'pipe', timeout: 120000 });
|
|
32
|
+
execSync('ldm init --yes --none', { stdio: 'pipe', timeout: 30000 });
|
|
33
|
+
return isLdmAvailable();
|
|
34
|
+
} catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Delegate to ldm install with the given arguments.
|
|
41
|
+
* @param {string} target - what to install (org/repo, path, or empty for update-all)
|
|
42
|
+
* @param {string[]} flags - CLI flags (--dry-run, --json, etc.)
|
|
43
|
+
*/
|
|
44
|
+
export function delegateToLdm(target, flags = []) {
|
|
45
|
+
const cmd = target
|
|
46
|
+
? `ldm install ${target} ${flags.join(' ')}`
|
|
47
|
+
: `ldm install ${flags.join(' ')}`;
|
|
48
|
+
execSync(cmd.trim(), { stdio: 'inherit' });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Full bootstrap + delegate flow.
|
|
53
|
+
* Called by wip-install as the entry point.
|
|
54
|
+
* @param {string[]} argv - process.argv.slice(2)
|
|
55
|
+
*/
|
|
56
|
+
export function run(argv) {
|
|
57
|
+
const target = argv.find(a => !a.startsWith('--'));
|
|
58
|
+
const flags = argv.filter(a => a.startsWith('--'));
|
|
59
|
+
const jsonOutput = flags.includes('--json');
|
|
60
|
+
|
|
61
|
+
if (isLdmAvailable()) {
|
|
62
|
+
if (!jsonOutput) {
|
|
63
|
+
console.log('');
|
|
64
|
+
console.log(' LDM OS detected. Delegating to ldm install...');
|
|
65
|
+
console.log('');
|
|
66
|
+
}
|
|
67
|
+
delegateToLdm(target, flags);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// LDM not on PATH, try bootstrap
|
|
72
|
+
if (!jsonOutput) {
|
|
73
|
+
console.log('');
|
|
74
|
+
console.log(' LDM OS not found. Installing...');
|
|
75
|
+
console.log('');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (bootstrapLdmOs()) {
|
|
79
|
+
if (!jsonOutput) {
|
|
80
|
+
console.log(' LDM OS installed. Delegating to ldm install...');
|
|
81
|
+
console.log('');
|
|
82
|
+
}
|
|
83
|
+
delegateToLdm(target, flags);
|
|
84
|
+
} else {
|
|
85
|
+
if (!jsonOutput) {
|
|
86
|
+
console.log(' LDM OS could not be installed automatically.');
|
|
87
|
+
console.log(' Install manually: npm install -g @wipcomputer/wip-ldm-os');
|
|
88
|
+
console.log('');
|
|
89
|
+
}
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
}
|
package/lib/state.mjs
CHANGED
|
@@ -89,11 +89,11 @@ function detectCLIBinaries() {
|
|
|
89
89
|
const binaries = {};
|
|
90
90
|
for (const bin of knownBins) {
|
|
91
91
|
try {
|
|
92
|
-
const path = execSync(`which ${bin} 2>/dev/null`, { encoding: 'utf8' }).trim();
|
|
92
|
+
const path = execSync(`which ${bin} 2>/dev/null`, { encoding: 'utf8', timeout: 5000 }).trim();
|
|
93
93
|
if (path) {
|
|
94
94
|
binaries[bin] = { path };
|
|
95
95
|
try {
|
|
96
|
-
const ver = execSync(`${bin} --version 2>/dev/null`, { encoding: 'utf8' }).trim().split('\n')[0];
|
|
96
|
+
const ver = execSync(`${bin} --version 2>/dev/null`, { encoding: 'utf8', timeout: 5000 }).trim().split('\n')[0];
|
|
97
97
|
binaries[bin].version = ver;
|
|
98
98
|
} catch {}
|
|
99
99
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wipcomputer/wip-ldm-os",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "LDM OS: identity, memory, and sovereignty infrastructure for AI agents",
|
|
6
6
|
"main": "src/boot/boot-hook.mjs",
|
|
7
7
|
"bin": {
|
|
8
8
|
"ldm": "bin/ldm.js",
|
|
9
9
|
"wip-ldm-os": "bin/ldm.js",
|
|
10
|
+
"wip-install": "bin/wip-install.js",
|
|
10
11
|
"ldm-scaffold": "bin/scaffold.sh",
|
|
11
12
|
"ldm-boot-install": "src/boot/install-cli.js",
|
|
12
13
|
"lesa": "dist/bridge/cli.js"
|
package/src/bridge/cli.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
2
|
+
// wip-bridge/cli.ts: CLI interface.
|
|
3
3
|
// lesa send "message", lesa inbox, lesa search "query", lesa read <file>
|
|
4
4
|
|
|
5
5
|
import { existsSync, statSync } from "node:fs";
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
const config = resolveConfig();
|
|
18
18
|
|
|
19
19
|
function usage(): void {
|
|
20
|
-
console.log(`
|
|
20
|
+
console.log(`wip-bridge: Claude Code CLI ↔ OpenClaw TUI agent bridge
|
|
21
21
|
|
|
22
22
|
Usage:
|
|
23
23
|
lesa send <message> Send a message to the OpenClaw agent
|
|
@@ -130,7 +130,7 @@ async function main(): Promise<void> {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
case "status": {
|
|
133
|
-
console.log(`
|
|
133
|
+
console.log(`wip-bridge status`);
|
|
134
134
|
console.log(` OpenClaw dir: ${config.openclawDir}`);
|
|
135
135
|
console.log(` Workspace: ${config.workspaceDir}`);
|
|
136
136
|
console.log(` Database: ${config.dbPath}`);
|
|
@@ -140,7 +140,7 @@ async function main(): Promise<void> {
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
case "diagnose": {
|
|
143
|
-
console.log("
|
|
143
|
+
console.log("wip-bridge diagnose\n");
|
|
144
144
|
let issues = 0;
|
|
145
145
|
|
|
146
146
|
// 1. OpenClaw dir
|
package/src/bridge/core.ts
CHANGED
package/src/bridge/mcp-server.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// wip-bridge/mcp-server.ts: MCP server wrapping core.
|
|
2
2
|
// Thin layer: registers tools, starts inbox HTTP server, connects transport.
|
|
3
3
|
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -73,12 +73,12 @@ function startInboxServer(cfg: BridgeConfig): void {
|
|
|
73
73
|
timestamp: new Date().toISOString(),
|
|
74
74
|
};
|
|
75
75
|
const queued = pushInbox(msg);
|
|
76
|
-
console.error(`
|
|
76
|
+
console.error(`wip-bridge inbox: message from ${msg.from}`);
|
|
77
77
|
|
|
78
78
|
try {
|
|
79
79
|
server.sendLoggingMessage({
|
|
80
80
|
level: "info",
|
|
81
|
-
logger: "
|
|
81
|
+
logger: "wip-bridge",
|
|
82
82
|
data: `[OpenClaw → Claude Code] ${msg.from}: ${msg.message}`,
|
|
83
83
|
});
|
|
84
84
|
} catch {}
|
|
@@ -103,18 +103,18 @@ function startInboxServer(cfg: BridgeConfig): void {
|
|
|
103
103
|
});
|
|
104
104
|
|
|
105
105
|
httpServer.listen(cfg.inboxPort, "127.0.0.1", () => {
|
|
106
|
-
console.error(`
|
|
106
|
+
console.error(`wip-bridge inbox listening on 127.0.0.1:${cfg.inboxPort}`);
|
|
107
107
|
});
|
|
108
108
|
|
|
109
109
|
httpServer.on("error", (err: Error) => {
|
|
110
|
-
console.error(`
|
|
110
|
+
console.error(`wip-bridge inbox server error: ${err.message}`);
|
|
111
111
|
});
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
// ── MCP Server ───────────────────────────────────────────────────────
|
|
115
115
|
|
|
116
116
|
const server = new McpServer({
|
|
117
|
-
name: "
|
|
117
|
+
name: "wip-bridge",
|
|
118
118
|
version: "0.3.0",
|
|
119
119
|
});
|
|
120
120
|
|
|
@@ -344,7 +344,7 @@ function registerSkillTools(skills: SkillInfo[]): void {
|
|
|
344
344
|
}
|
|
345
345
|
);
|
|
346
346
|
|
|
347
|
-
console.error(`
|
|
347
|
+
console.error(`wip-bridge: registered ${executableSkills.length} skill tools + oc_skills_list (${skills.length} total skills)`);
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
// ── Start ────────────────────────────────────────────────────────────
|
|
@@ -357,12 +357,12 @@ async function main() {
|
|
|
357
357
|
const skills = discoverSkills(config.openclawDir);
|
|
358
358
|
registerSkillTools(skills);
|
|
359
359
|
} catch (err: any) {
|
|
360
|
-
console.error(`
|
|
360
|
+
console.error(`wip-bridge: skill discovery failed: ${err.message}`);
|
|
361
361
|
}
|
|
362
362
|
|
|
363
363
|
const transport = new StdioServerTransport();
|
|
364
364
|
await server.connect(transport);
|
|
365
|
-
console.error(`
|
|
365
|
+
console.error(`wip-bridge MCP server running (openclaw: ${config.openclawDir})`);
|
|
366
366
|
}
|
|
367
367
|
|
|
368
368
|
main().catch((error) => {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# LDM OS: Global pre-commit hook
|
|
3
|
+
# Blocks commits on main/master. Use a branch or worktree.
|
|
4
|
+
# Installed by: ldm init
|
|
5
|
+
# Location: ~/.ldm/hooks/pre-commit
|
|
6
|
+
# Activated by: git config --global core.hooksPath ~/.ldm/hooks
|
|
7
|
+
|
|
8
|
+
branch=$(git branch --show-current 2>/dev/null)
|
|
9
|
+
|
|
10
|
+
if [ "$branch" = "main" ] || [ "$branch" = "master" ]; then
|
|
11
|
+
echo ""
|
|
12
|
+
echo " BLOCKED: Cannot commit on $branch."
|
|
13
|
+
echo " Create a branch first: git checkout -b cc-mini/your-feature"
|
|
14
|
+
echo " Or use a worktree: git worktree add /tmp/wt-name -b branch-name"
|
|
15
|
+
echo ""
|
|
16
|
+
echo " To bypass (emergencies only): git commit --no-verify"
|
|
17
|
+
echo ""
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|