@wipcomputer/wip-ldm-os 0.4.38 → 0.4.41

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/SKILL.md CHANGED
@@ -5,7 +5,7 @@ license: MIT
5
5
  interface: [cli, skill]
6
6
  metadata:
7
7
  display-name: "LDM OS"
8
- version: "0.4.38"
8
+ version: "0.4.41"
9
9
  homepage: "https://github.com/wipcomputer/wip-ldm-os"
10
10
  author: "Parker Todd Brooks"
11
11
  category: infrastructure
package/bin/ldm.js CHANGED
@@ -261,9 +261,42 @@ async function cmdInit() {
261
261
  join(LDM_ROOT, 'messages'),
262
262
  join(LDM_ROOT, 'shared', 'boot'),
263
263
  join(LDM_ROOT, 'shared', 'cron'),
264
+ join(LDM_ROOT, 'shared', 'rules'),
265
+ join(LDM_ROOT, 'shared', 'prompts'),
264
266
  join(LDM_ROOT, 'hooks'),
265
267
  ];
266
268
 
269
+ // Scaffold per-agent memory dirs
270
+ try {
271
+ const config = JSON.parse(readFileSync(join(LDM_ROOT, 'config.json'), 'utf8'));
272
+ const agents = config.agents || [];
273
+ const agentList = Array.isArray(agents) ? agents : Object.keys(agents);
274
+ for (const agentId of agentList) {
275
+ for (const sub of ['memory/daily', 'memory/journals', 'memory/sessions', 'memory/transcripts']) {
276
+ dirs.push(join(LDM_ROOT, 'agents', agentId, sub));
277
+ }
278
+ }
279
+
280
+ // Scaffold workspace output dirs if workspace is configured
281
+ const workspace = config.workspace;
282
+ if (workspace && existsSync(workspace)) {
283
+ // Per-agent workspace dirs
284
+ const agentNameMap = { 'cc-mini': 'cc-mini', 'cc-air': 'cc-air', 'oc-lesa-mini': 'Lēsa' };
285
+ for (const agentId of agentList) {
286
+ const teamName = agentNameMap[agentId] || agentId;
287
+ for (const sub of ['journals', 'automated/memory/summaries/daily', 'automated/memory/summaries/weekly', 'automated/memory/summaries/monthly', 'automated/memory/summaries/quarterly']) {
288
+ dirs.push(join(workspace, 'team', teamName, sub));
289
+ }
290
+ }
291
+ // Org-wide dirs
292
+ for (const track of ['team', 'dev']) {
293
+ for (const cadence of ['daily', 'weekly', 'monthly', 'quarterly']) {
294
+ dirs.push(join(workspace, 'operations', 'updates', track, cadence));
295
+ }
296
+ }
297
+ }
298
+ } catch {} // config.json may not exist on first init
299
+
267
300
  const existing = existsSync(VERSION_PATH);
268
301
 
269
302
  if (DRY_RUN) {
@@ -379,6 +412,70 @@ async function cmdInit() {
379
412
  chmodSync(restoreDest, 0o755);
380
413
  console.log(` + ldm-restore.sh deployed to ~/.ldm/bin/`);
381
414
  }
415
+ const summarySrc = join(__dirname, '..', 'scripts', 'ldm-summary.sh');
416
+ const summaryDest = join(LDM_ROOT, 'bin', 'ldm-summary.sh');
417
+ if (existsSync(summarySrc)) {
418
+ cpSync(summarySrc, summaryDest);
419
+ chmodSync(summaryDest, 0o755);
420
+ console.log(` + ldm-summary.sh deployed to ~/.ldm/bin/`);
421
+ }
422
+
423
+ // Deploy shared rules to ~/.ldm/shared/rules/ and to harnesses
424
+ const rulesSrc = join(__dirname, '..', 'shared', 'rules');
425
+ const rulesDest = join(LDM_ROOT, 'shared', 'rules');
426
+ if (existsSync(rulesSrc)) {
427
+ mkdirSync(rulesDest, { recursive: true });
428
+ let rulesCount = 0;
429
+ for (const file of readdirSync(rulesSrc)) {
430
+ if (!file.endsWith('.md')) continue;
431
+ cpSync(join(rulesSrc, file), join(rulesDest, file));
432
+ rulesCount++;
433
+ }
434
+ if (rulesCount > 0) {
435
+ console.log(` + ${rulesCount} shared rules deployed to ~/.ldm/shared/rules/`);
436
+
437
+ // Deploy to Claude Code harness (~/.claude/rules/)
438
+ const claudeRules = join(HOME, '.claude', 'rules');
439
+ if (existsSync(join(HOME, '.claude'))) {
440
+ mkdirSync(claudeRules, { recursive: true });
441
+ for (const file of readdirSync(rulesDest)) {
442
+ if (!file.endsWith('.md')) continue;
443
+ cpSync(join(rulesDest, file), join(claudeRules, file));
444
+ }
445
+ console.log(` + rules deployed to ~/.claude/rules/`);
446
+ }
447
+
448
+ // Deploy to OpenClaw harness (~/.openclaw/workspace/DEV-RULES.md)
449
+ const ocWorkspace = join(HOME, '.openclaw', 'workspace');
450
+ if (existsSync(ocWorkspace)) {
451
+ let combined = '# Dev Rules (deployed by ldm install)\n\n';
452
+ combined += '> Do not edit this file. It is regenerated by `ldm install`.\n';
453
+ combined += '> Source: ~/.ldm/shared/rules/\n\n';
454
+ for (const file of readdirSync(rulesDest).sort()) {
455
+ if (!file.endsWith('.md')) continue;
456
+ combined += readFileSync(join(rulesDest, file), 'utf8') + '\n\n---\n\n';
457
+ }
458
+ writeFileSync(join(ocWorkspace, 'DEV-RULES.md'), combined);
459
+ console.log(` + rules deployed to ~/.openclaw/workspace/DEV-RULES.md`);
460
+ }
461
+ }
462
+ }
463
+
464
+ // Deploy shared prompts to ~/.ldm/shared/prompts/
465
+ const promptsSrc = join(__dirname, '..', 'shared', 'prompts');
466
+ const promptsDest = join(LDM_ROOT, 'shared', 'prompts');
467
+ if (existsSync(promptsSrc)) {
468
+ mkdirSync(promptsDest, { recursive: true });
469
+ let promptsCount = 0;
470
+ for (const file of readdirSync(promptsSrc)) {
471
+ if (!file.endsWith('.md')) continue;
472
+ cpSync(join(promptsSrc, file), join(promptsDest, file));
473
+ promptsCount++;
474
+ }
475
+ if (promptsCount > 0) {
476
+ console.log(` + ${promptsCount} shared prompts deployed to ~/.ldm/shared/prompts/`);
477
+ }
478
+ }
382
479
 
383
480
  console.log('');
384
481
  console.log(` LDM OS v${PKG_VERSION} initialized at ${LDM_ROOT}`);
@@ -39,3 +39,9 @@ The hook runs with a 15-second timeout. If any file is missing, it's skipped sil
39
39
  ## Session Registration
40
40
 
41
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`.
42
+
43
+ ## Connection to Total Recall
44
+
45
+ Recall loads context at session start. [Total Recall](../total-recall/TECHNICAL.md) fills the memory that Recall serves. Total Recall imports historical conversations, generates multi-cadence summaries (daily/weekly/monthly/quarterly), and writes everything to Memory Crystal. On the next session start, Recall picks up the new data automatically.
46
+
47
+ Without Total Recall, Recall only has what was captured going forward. With Total Recall, Recall has the complete history.
@@ -0,0 +1,84 @@
1
+ ###### WIP Computer
2
+
3
+ # Total Recall
4
+
5
+ ## Connect your AI accounts. Bring every memory home. Never lose a conversation again.
6
+
7
+ Total Recall is LDM OS's memory import and consolidation system. It connects to AI platforms, imports conversation history, and uses Dream Weaver to consolidate raw data into searchable, structured memories in Memory Crystal.
8
+
9
+ It also generates multi-cadence summaries (daily, weekly, monthly, quarterly) for every agent.
10
+
11
+ ## The Pipeline
12
+
13
+ ```
14
+ 1. CONNECT -> Sign into your AI accounts (Anthropic, OpenAI, xAI, etc.)
15
+ 2. IMPORT -> Pull every conversation (API, data export, or automation)
16
+ 3. RELIVE -> Dream Weaver processes raw conversations into memories
17
+ 4. CRYSTAL -> Consolidated memories stored in Memory Crystal
18
+ 5. SUMMARIZE -> Multi-cadence summaries (daily/weekly/monthly/quarterly)
19
+ 6. MONITOR -> System check alerts when any agent stops capturing
20
+ ```
21
+
22
+ ## Two Modes
23
+
24
+ ### Going Forward (daily)
25
+
26
+ Each agent writes its own daily summary. Persistent agents (OpenClaw, Letta) write from their own context. Ephemeral agents (Claude Code, Codex) get script-generated summaries from crystal + daily logs. Org-wide summaries combine all agents.
27
+
28
+ ```bash
29
+ ~/.ldm/bin/ldm-summary.sh daily # today
30
+ ~/.ldm/bin/ldm-summary.sh daily --team-only # team track only
31
+ ~/.ldm/bin/ldm-summary.sh daily --dev-only # dev track only
32
+ ```
33
+
34
+ ### Backfill (historical)
35
+
36
+ Import and summarize everything from day 1. Uses `--force` to generate for all agents regardless of harness type.
37
+
38
+ ```bash
39
+ ~/.ldm/bin/ldm-summary.sh daily --date 2026-02-10 --force # one day
40
+ bash scripts/backfill-summaries.sh # all days
41
+ ```
42
+
43
+ ## Output Locations
44
+
45
+ ### Per-agent
46
+ ```
47
+ ~/wipcomputerinc/team/{agent}/automated/memory/summaries/
48
+ daily/YYYY-MM-DD.md
49
+ weekly/YYYY-MM-DD.md
50
+ monthly/YYYY-MM.md
51
+ quarterly/YYYY-QX.md
52
+ ```
53
+
54
+ ### Org-wide
55
+ ```
56
+ ~/wipcomputerinc/operations/updates/
57
+ team/daily/YYYY-MM-DD.md <- conversations, decisions, insights
58
+ dev/daily/YYYY-MM-DD.md <- code shipped, PRs, releases
59
+ ```
60
+
61
+ ## Recursive Consolidation
62
+
63
+ Each level reads the level below:
64
+
65
+ ```
66
+ Transcripts + Crystal -> Daily summaries
67
+ 7 dailies -> Weekly summary
68
+ 4 weeklies -> Monthly summary
69
+ 3 monthlies -> Quarterly summary
70
+ ```
71
+
72
+ This is the Dream Weaver paper's consolidation architecture applied at four cadences.
73
+
74
+ ## Connection to Recall
75
+
76
+ [Recall](../recall/README.md) loads context at session start. Total Recall fills the memory that Recall serves. Without Total Recall, Recall only has what was captured going forward. With Total Recall, Recall has the complete history.
77
+
78
+ ## Part of LDM OS
79
+
80
+ Total Recall is included with LDM OS. Summaries activate after `ldm init`. External imports are opt-in per platform.
81
+
82
+ ---
83
+
84
+ [Technical Reference](./TECHNICAL.md)
@@ -0,0 +1,124 @@
1
+ # Total Recall ... Technical Reference
2
+
3
+ ## Architecture
4
+
5
+ ```
6
+ ~/.ldm/agents/{agentId}/memory/ <- SOURCE (raw data per agent)
7
+ daily/ <- daily logs
8
+ journals/ <- Dream Weaver journals
9
+ sessions/ <- session exports (.md)
10
+ transcripts/ <- raw JSONL
11
+ |
12
+ v
13
+ Dream Weaver (prompts at ~/.ldm/shared/prompts/)
14
+ |
15
+ v
16
+ ~/wipcomputerinc/team/{agent}/automated/memory/summaries/
17
+ daily/ weekly/ monthly/ quarterly/ <- per-agent summaries
18
+ |
19
+ v (combine all agents)
20
+ ~/wipcomputerinc/operations/updates/
21
+ team/ daily/ weekly/ monthly/ quarterly/ <- org-wide team
22
+ dev/ daily/ weekly/ monthly/ quarterly/ <- org-wide dev (from git)
23
+ ```
24
+
25
+ ## Harness Logic
26
+
27
+ Each agent in `~/.ldm/config.json` has a harness type:
28
+
29
+ | Harness | Behavior | Examples |
30
+ |---------|----------|---------|
31
+ | Persistent (openclaw, letta, hermes) | Agent writes own summaries via prompt | Lesa |
32
+ | Ephemeral (claude-code, codex) | Script generates from crystal + daily logs | CC |
33
+
34
+ ```
35
+ for each agent:
36
+ if persistent AND summary file exists: skip (agent wrote it)
37
+ if persistent AND file missing AND --force: generate via script
38
+ if ephemeral: always generate via script
39
+ ```
40
+
41
+ ## Key Files
42
+
43
+ | File | What |
44
+ |------|------|
45
+ | `scripts/ldm-summary.sh` | Orchestrator. Per-agent search, org-wide combine. |
46
+ | `scripts/backfill-summaries.sh` | Loop: dailies -> weeklies -> monthlies -> quarterly |
47
+ | `shared/prompts/daily-agent-summary.md` | Prompt for daily per-agent summary |
48
+ | `shared/prompts/weekly-agent-summary.md` | Prompt for weekly (reads 7 dailies) |
49
+ | `shared/prompts/monthly-agent-summary.md` | Prompt for monthly (reads 4 weeklies) |
50
+ | `shared/prompts/quarterly-agent-summary.md` | Prompt for quarterly (reads 3 monthlies) |
51
+ | `shared/prompts/org-daily-team.md` | Prompt for combining agent summaries |
52
+ | `shared/prompts/daily-dev.md` | Prompt for git log summary |
53
+ | `bin/ldm.js` | Installer. Deploys scripts + prompts. Scaffolds dirs. |
54
+
55
+ ## Data Sources
56
+
57
+ ### Team track (conversations, decisions)
58
+
59
+ - `~/.ldm/agents/{agentId}/memory/daily/{date}.md` ... raw daily log
60
+ - `crystal search --agent {id} --since {date} --until {date+1}` ... crystal chunks for that day
61
+ - Both fed to Dream Weaver prompt to produce the summary
62
+
63
+ ### Dev track (code shipped)
64
+
65
+ - `git log --since={date} --until={date+1} --oneline --all` across all repos in workspace
66
+ - Fed to prompt to produce factual dev summary
67
+
68
+ ## Config
69
+
70
+ `~/wipcomputerinc/settings/config.json`:
71
+
72
+ ```json
73
+ "summaries": {
74
+ "cadences": ["daily", "weekly", "monthly", "quarterly"],
75
+ "tracks": ["team", "dev"],
76
+ "schedule": {
77
+ "daily": "06:00",
78
+ "weekly": "Monday 07:00",
79
+ "monthly": "1st 08:00",
80
+ "quarterly": "1st of Q 09:00"
81
+ },
82
+ "perAgent": "team/{agent}/automated/memory/summaries/",
83
+ "orgWide": "operations/updates/"
84
+ }
85
+ ```
86
+
87
+ `~/.ldm/config.json`:
88
+
89
+ ```json
90
+ "agents": ["cc-mini", "oc-lesa-mini"]
91
+ ```
92
+
93
+ ## Schedule
94
+
95
+ Cron via LDM Dev Tools.app:
96
+
97
+ ```
98
+ 0 6 * * * ldm-summary.sh daily
99
+ 0 7 * * 1 ldm-summary.sh weekly (Monday)
100
+ 0 8 1 * * ldm-summary.sh monthly (1st of month)
101
+ 0 9 1 1,4,7,10 * ldm-summary.sh quarterly (1st of quarter)
102
+ ```
103
+
104
+ ## External Imports (Future)
105
+
106
+ Total Recall will also import from external platforms:
107
+
108
+ | Platform | Method | Status |
109
+ |----------|--------|--------|
110
+ | Anthropic (Claude) | API / data export | Planned |
111
+ | OpenAI (ChatGPT) | API / data export | Planned |
112
+ | xAI (Grok) | API | Planned |
113
+ | X (Twitter) | Full archive import | Planned |
114
+ | Apple Music | Listening history | Planned |
115
+ | Browser | Chrome/Safari extension | Planned |
116
+
117
+ Each import follows the same pipeline: CONNECT -> IMPORT -> RELIVE -> CRYSTAL.
118
+
119
+ ## Connection to Other Components
120
+
121
+ - **[Recall](../recall/TECHNICAL.md)** ... loads context at session start. Total Recall fills what Recall serves.
122
+ - **[Bridge](../bridge/TECHNICAL.md)** ... agent-to-agent communication. Summaries are shared via the workspace, not Bridge.
123
+ - **[Memory Crystal](https://github.com/wipcomputer/memory-crystal)** ... storage + search. Total Recall writes to Crystal. Crystal search provides data for summaries.
124
+ - **[Dream Weaver](https://github.com/wipcomputer/dream-weaver-protocol)** ... consolidation engine. Prompts invoke Dream Weaver via `claude -p`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipcomputer/wip-ldm-os",
3
- "version": "0.4.38",
3
+ "version": "0.4.41",
4
4
  "type": "module",
5
5
  "description": "LDM OS: identity, memory, and sovereignty infrastructure for AI agents",
6
6
  "engines": {
@@ -37,6 +37,8 @@
37
37
  "dist/bridge/",
38
38
  "templates/",
39
39
  "docs/",
40
+ "shared/",
41
+ "scripts/",
40
42
  "catalog.json",
41
43
  "SKILL.md"
42
44
  ],
@@ -0,0 +1,112 @@
1
+ #!/bin/bash
2
+ # backfill-summaries.sh — Generate all historical summaries from day 1.
3
+ # Part of Total Recall. Uses ldm-summary.sh with --force --date.
4
+ #
5
+ # Usage:
6
+ # backfill-summaries.sh # full backfill (Feb 5 to yesterday)
7
+ # backfill-summaries.sh --dry-run # preview
8
+ # backfill-summaries.sh --from 2026-03-01 # partial backfill
9
+ #
10
+ # Order: dailies first, then weeklies, monthlies, quarterly.
11
+ # Each level reads the level below. Must complete in order.
12
+
13
+ set -euo pipefail
14
+ export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"
15
+
16
+ SUMMARY_SCRIPT="$HOME/.ldm/bin/ldm-summary.sh"
17
+ DRY_RUN=false
18
+ FROM_DATE="2026-02-05"
19
+
20
+ while [[ $# -gt 0 ]]; do
21
+ case "$1" in
22
+ --dry-run) DRY_RUN=true; shift ;;
23
+ --from) FROM_DATE="$2"; shift 2 ;;
24
+ *) echo "Unknown: $1" >&2; exit 1 ;;
25
+ esac
26
+ done
27
+
28
+ if [ ! -f "$SUMMARY_SCRIPT" ]; then
29
+ echo "ERROR: ldm-summary.sh not found. Run ldm install first." >&2
30
+ exit 1
31
+ fi
32
+
33
+ YESTERDAY=$(python3 -c "from datetime import datetime, timedelta; print((datetime.now()-timedelta(days=1)).strftime('%Y-%m-%d'))")
34
+ FLAGS="--force"
35
+ [ "$DRY_RUN" = true ] && FLAGS="$FLAGS --dry-run"
36
+
37
+ echo "=== Total Recall: Backfill Summaries ==="
38
+ echo " From: $FROM_DATE"
39
+ echo " To: $YESTERDAY"
40
+ echo " Mode: $([ "$DRY_RUN" = true ] && echo 'DRY RUN' || echo 'LIVE')"
41
+ echo ""
42
+
43
+ # ── Step 1: Dailies ──
44
+
45
+ echo "=== STEP 1: Daily summaries ==="
46
+ DAILY_COUNT=0
47
+ for date in $(python3 -c "
48
+ from datetime import datetime, timedelta
49
+ d = datetime.strptime('$FROM_DATE', '%Y-%m-%d')
50
+ end = datetime.strptime('$YESTERDAY', '%Y-%m-%d')
51
+ while d <= end:
52
+ print(d.strftime('%Y-%m-%d'))
53
+ d += timedelta(days=1)
54
+ "); do
55
+ echo "--- $date ---"
56
+ bash "$SUMMARY_SCRIPT" daily --date "$date" $FLAGS 2>&1 | grep -E "->|DRY RUN|No data|No git"
57
+ DAILY_COUNT=$((DAILY_COUNT + 1))
58
+ done
59
+ echo " Dailies: $DAILY_COUNT days"
60
+ echo ""
61
+
62
+ # ── Step 2: Weeklies (Sunday to Saturday) ──
63
+
64
+ echo "=== STEP 2: Weekly summaries ==="
65
+ WEEKLY_COUNT=0
66
+ for date in $(python3 -c "
67
+ from datetime import datetime, timedelta
68
+ # Start from first Sunday >= FROM_DATE
69
+ d = datetime.strptime('$FROM_DATE', '%Y-%m-%d')
70
+ while d.weekday() != 6: d += timedelta(days=1) # find Sunday
71
+ end = datetime.now()
72
+ while d <= end:
73
+ # Use the Saturday (end of week) as the date
74
+ sat = d + timedelta(days=6)
75
+ print(sat.strftime('%Y-%m-%d'))
76
+ d += timedelta(days=7)
77
+ "); do
78
+ echo "--- Week ending $date ---"
79
+ bash "$SUMMARY_SCRIPT" weekly --date "$date" $FLAGS 2>&1 | grep -E "->|DRY RUN|No "
80
+ WEEKLY_COUNT=$((WEEKLY_COUNT + 1))
81
+ done
82
+ echo " Weeklies: $WEEKLY_COUNT weeks"
83
+ echo ""
84
+
85
+ # ── Step 3: Monthlies ──
86
+
87
+ echo "=== STEP 3: Monthly summaries ==="
88
+ for date in $(python3 -c "
89
+ from datetime import datetime
90
+ import calendar
91
+ d = datetime.strptime('$FROM_DATE', '%Y-%m-%d')
92
+ now = datetime.now()
93
+ while d <= now:
94
+ last_day = calendar.monthrange(d.year, d.month)[1]
95
+ print(f'{d.year}-{d.month:02d}-{last_day:02d}')
96
+ if d.month == 12: d = d.replace(year=d.year+1, month=1, day=1)
97
+ else: d = d.replace(month=d.month+1, day=1)
98
+ "); do
99
+ echo "--- Month ending $date ---"
100
+ bash "$SUMMARY_SCRIPT" monthly --date "$date" $FLAGS 2>&1 | grep -E "->|DRY RUN|No "
101
+ done
102
+ echo ""
103
+
104
+ # ── Step 4: Quarterly ──
105
+
106
+ echo "=== STEP 4: Quarterly summary ==="
107
+ bash "$SUMMARY_SCRIPT" quarterly --date "$(date +%Y-%m-%d)" $FLAGS 2>&1 | grep -E "->|DRY RUN|No "
108
+
109
+ echo ""
110
+ echo "=== Backfill complete ==="
111
+ echo " $DAILY_COUNT dailies processed"
112
+ echo " $WEEKLY_COUNT weeklies processed"