# Plan: Harness-Agnostic Multi-Cadence Summaries (Final)

**Date:** 2026-03-24
**Author:** cc-mini (with Parker)
**Issue:** #193, #194

## Context

Each agent writes their own summaries. The system doesn't care what harness the agent runs on. If it's persistent (OpenClaw, Letta, Hermes), the agent writes its own summary via a prompt deployed to its harness. If it's ephemeral (Claude Code, Codex), a script generates it from crystal + daily logs. The org-wide summary at `operations/updates/` is always generated by a specific model (configurable, default Opus 4.6) that reads all agent summaries and combines them.

Adding a new agent means: add it to config.json, give it a harness type, deploy the prompt. The system handles the rest.

## How Harnesses Work

```
config.json agents:
  cc-mini:      harness: claude-code     -> ephemeral, script generates summary
  cc-air:       harness: claude-code     -> ephemeral, script generates summary
  oc-lesa-mini: harness: openclaw        -> persistent, agent writes own summary
  hermes:       harness: letta           -> persistent, agent writes own summary
  codex-agent:  harness: codex           -> ephemeral, script generates summary
```

**Persistent harnesses** (openclaw, letta, hermes, etc.):
- Agent has continuity. Runs 24/7 or long sessions.
- Agent reads the prompt from `~/.ldm/shared/prompts/daily-agent-summary.md`
- Agent reads its own data from `~/.ldm/agents/{agentId}/memory/`
- Agent writes its summary to `team/{agent}/automated/memory/summaries/daily/`
- Script skips this agent. Checks if file exists for org-wide combine.

**Ephemeral harnesses** (claude-code, codex, etc.):
- No persistence between sessions. Script generates.
- Script reads crystal `--agent {id} --since date --until date+1`
- Script reads `~/.ldm/agents/{id}/memory/daily/date.md`
- Script calls `claude -p` with the prompt
- Script writes to `team/{agent}/automated/memory/summaries/daily/`

**Org-wide combine** (always script):
- Reads ALL agent summaries for the date (regardless of harness)
- Combines via configured model (default: `claude -p` with Opus 4.6)
- Writes to `operations/updates/team/daily/`

**Backfill** (always script, `--force` flag):
- Overrides harness type. Script generates for everyone.
- Used for historical dates where no agent was running.

## Architecture

```
~/.ldm/agents/cc-mini/memory/          <- SOURCE (raw data)
  transcripts/ (939 JSONL files)
  daily/ (35 logs)
  journals/ (6 files)
       |
       v (CC reads, summarizes via prompt)

~/wipcomputerinc/team/cc-mini/automated/memory/summaries/
  daily/    <- CC writes daily summary
  weekly/   <- CC reads 7 dailies, writes weekly
  monthly/  <- CC reads 4 weeklies, writes monthly
  quarterly/<- CC reads 3 monthlies, writes quarterly

~/.ldm/agents/oc-lesa-mini/memory/     <- SOURCE (raw data)
  transcripts/ (1009 JSONL files)
  daily/ (42 logs)
       |
       v (Lesa reads, summarizes via prompt)

~/wipcomputerinc/team/Lēsa/automated/memory/summaries/
  daily/    <- Lesa writes daily summary
  weekly/   <- Lesa reads 7 dailies, writes weekly
  monthly/  <- Lesa reads 4 weeklies, writes monthly
  quarterly/

THEN:
  both agent summaries
       |
       v (script combines)

~/wipcomputerinc/operations/updates/
  team/daily/   <- combines cc-mini + Lesa daily summaries
  dev/daily/    <- git log summary (script-generated)
```

## Prompts (saved at ~/.ldm/shared/prompts/)

### daily-agent-summary.md
```
Read your transcripts and daily logs from ~/.ldm/agents/{agentId}/memory/ for {date}.

Write a daily summary:
- What did you work on?
- What decisions were made?
- What shipped?
- What's unresolved?
- Who did you interact with?

Write in first person. Be specific. Name repos, tickets, people.
```

### weekly-agent-summary.md
```
Read your 7 daily summaries from team/{agent}/automated/memory/summaries/daily/.

Write a weekly summary:
- What themes emerged?
- What decisions stuck? What changed?
- What shipped vs what was planned?
- Open threads going into next week.
- One sentence: what was this week about?
```

### monthly-agent-summary.md
```
Read your 4 weekly summaries.

Write a monthly summary:
- Major themes.
- What shipped.
- How priorities shifted.
- Patterns emerging.
- One paragraph: the narrative of this month.
```

### org-daily-team.md
```
Read both agent daily summaries:
- team/cc-mini/automated/memory/summaries/daily/{date}.md
- team/Lēsa/automated/memory/summaries/daily/{date}.md

Combine into one org-wide team summary. What happened across the whole team.
```

### daily-dev.md
```
Read git log output from all repos for {date}.
Summarize: what shipped, PRs merged, releases, tickets closed. Be factual.
```

## How It Runs

### Script logic (per agent)

```
for each agent in config.json:
  harness = agent.harness
  if harness is persistent (openclaw, letta, hermes):
    check if team/{agent}/automated/memory/summaries/daily/{date}.md exists
    if exists: skip (agent wrote it)
    if missing AND not --force: warn "agent didn't write summary"
    if missing AND --force: generate via script (backfill mode)
  if harness is ephemeral (claude-code, codex):
    always generate via script
```

### Org-wide combine (always script)

```
read all team/{agent}/automated/memory/summaries/daily/{date}.md
combine via claude -p (model from config, default Opus 4.6)
write to operations/updates/team/daily/{date}.md
```

### Dev summary (always script)

```
git log across all repos for {date}
summarize via claude -p
write to operations/updates/dev/daily/{date}.md
```

### config.json

```json
"agents": {
  "cc-mini": { "harness": "claude-code", "machine": "mac-mini", "prefix": "cc-mini" },
  "cc-air": { "harness": "claude-code", "machine": "macbook-air", "prefix": "cc-air" },
  "lesa-mini": { "harness": "openclaw", "machine": "mac-mini", "prefix": "lesa-mini" }
},
"summaries": {
  "combineModel": "claude-opus-4-6",
  "persistentHarnesses": ["openclaw", "letta", "hermes"],
  "ephemeralHarnesses": ["claude-code", "codex"]
}
```

### Each harness gets its own prompt

Deployed by `ldm install` to the harness's native location:
- Claude Code: `~/.claude/commands/daily-summary.md` (invocable as /user:daily-summary)
- OpenClaw: skill or scheduled task that reads the prompt from `~/.ldm/shared/prompts/`
- Letta: equivalent trigger mechanism
- Codex: ephemeral, script handles it

## Backfill (Day 1 to today)

### Prerequisites
- MC #63: `--until` flag ... DONE
- `--date` flag on ldm-summary.sh ... DONE
- `--force` flag (overrides persistent harness, generates for all agents)

### How

```bash
# Step 1: All dailies (--force generates for ALL agents including persistent)
for date in $(python3 -c "
from datetime import datetime, timedelta
d = datetime(2026,2,5)
while d < datetime(2026,3,25):
  print(d.strftime('%Y-%m-%d'))
  d += timedelta(days=1)
"); do
  ldm-summary.sh daily --date "$date" --force
done

# Step 2: All weeklies (Sun-Mon weeks)
for date in 2026-02-09 2026-02-16 2026-02-23 2026-03-02 2026-03-09 2026-03-16 2026-03-23; do
  ldm-summary.sh weekly --date "$date" --force
done

# Step 3: Monthlies
ldm-summary.sh monthly --date 2026-02-28 --force
ldm-summary.sh monthly --date 2026-03-25 --force

# Step 4: Quarterly
ldm-summary.sh quarterly --date 2026-03-25 --force
```

~171 claude -p calls. ~1-1.5 hours. Can run overnight.

### Going forward

After backfill:
- Persistent agents (Lesa) write their own dailies. Script skips them.
- Ephemeral agents (CC) get script-generated dailies.
- Weekly/monthly/quarterly: each agent consolidates their own (persistent: self, ephemeral: script).
- Org-wide always combines via script.

## Implementation Order

1. Add `--until` to crystal search (MC #63)
2. Add `--agent` filter to crystal search CLI (if not already there)
3. Write prompts to `shared/prompts/` in wip-ldm-os-private
4. Fix `ldm-summary.sh`: per-agent crystal search, separate per-agent and org-wide steps
5. Add `--date` flag to ldm-summary.sh for backfill
6. Deploy prompts via ldm install
7. Tell Lesa her prompt and schedule
8. Backfill CC dailies (Feb 5 - today)
9. Lesa backfills her own dailies
10. Run weeklies, monthlies, quarterly

## Memory Consolidation in .ldm/

All memory systems should be referenced or copied in `.ldm/` as the single source of truth.

### Every harness has a memory system. All captured in .ldm/.

Claude Code has three levels of memory:
- **Level 1 (global):** `~/.claude/CLAUDE.md`, `~/.claude/settings.json`
- **Level 2 (working dir):** `~/.openclaw/.claude/` (we use .openclaw as our CWD) ... recommended: use org root `~/wipcomputerinc/.claude/` instead
- **Level 3 (per-repo):** `<repo>/.claude/` ... stays in the repo, not captured in .ldm/
- **Auto-memory:** `~/.claude/projects/-Users-lesa--openclaw/memory/` (per-project memory files)

OpenClaw has:
- **Workspace:** `~/.openclaw/workspace/` (MEMORY.md, TOOLS.md, IDENTITY.md, SOUL.md, daily logs)
- **main.sqlite:** `~/.openclaw/memory/main.sqlite` (conversations)
- **Context embeddings:** `~/.openclaw/memory/context-embeddings.sqlite` (deprecated, crystal replaced)

Future harnesses (Letta, Hermes, Codex) will have their own. Each needs capture.

### What needs to be in .ldm/

| Harness memory | Current location | .ldm/ capture |
|---------------|-----------------|---------------|
| Crystal | `~/.ldm/memory/crystal.db` | Already there (primary) |
| CC Level 1 | `~/.claude/CLAUDE.md`, `settings.json` | Copy to `~/.ldm/harnesses/claude/` |
| CC Level 2 | `~/.openclaw/.claude/` (current) or `~/wipcomputerinc/.claude/` (recommended) | Copy to `~/.ldm/harnesses/claude/level2/` |
| CC auto-memory | `~/.claude/projects/-Users-lesa--openclaw/memory/` | Copy to `~/.ldm/harnesses/claude/auto-memory/` |
| OC workspace | `~/.openclaw/workspace/` | Copy to `~/.ldm/agents/oc-lesa-mini/memory/dot-openclaw-workspace/` (DONE, needs sync) |
| OC main.sqlite | `~/.openclaw/memory/main.sqlite` | Symlink or move to `~/.ldm/memory/` long-term |
| OC context-embeddings | `~/.openclaw/memory/context-embeddings.sqlite` | Deprecated. Skip. |
| Per-repo .claude/ | `<repo>/.claude/` | Stays in repo. Not captured. Committed to git. |

### New structure in .ldm/

```
~/.ldm/
  memory/
    crystal.db                          <- shared across all agents
  agents/
    cc-mini/
      SOUL.md, IDENTITY.md, etc.        <- identity (already here)
      memory/
        daily/                          <- daily logs (already here)
        journals/                       <- journals (already here)
        sessions/                       <- session exports (already here)
        transcripts/                    <- raw JSONL (already here)
        dot-claude-auto-memory/         <- NEW: copy of ~/.claude/projects/.../memory/
        dot-claude-config/              <- NEW: copy of ~/.claude/CLAUDE.md, settings.json
    oc-lesa-mini/
      memory/
        daily/                          <- daily logs (already here)
        sessions/                       <- session exports (already here)
        transcripts/                    <- raw JSONL (already here)
        dot-openclaw-workspace/         <- DONE: copy of ~/.openclaw/workspace/
        dot-openclaw-main.sqlite        <- NEW: copy of ~/.openclaw/memory/main.sqlite
```

Each agent carries all their memory. The harness is just how they run. The memory is theirs.

### Sync mechanism

`ldm-backup.sh` already captures everything for backup. For live sync:
- Add a `ldm sync` command (or cron step) that copies harness memory to `~/.ldm/harnesses/`
- Runs after backup or on its own schedule
- New harnesses register their memory locations in config.json

### Level 2 recommendation

Currently CC opens in `~/.openclaw/` so Level 2 is `~/.openclaw/.claude/`. Better: open CC in `~/wipcomputerinc/` so Level 2 is `~/wipcomputerinc/.claude/`. The workspace owns the rules, not the OpenClaw harness dir. This is the three-level CLAUDE.md split we planned earlier.

## Files to Modify

| Repo | File | Change |
|------|------|--------|
| memory-crystal-private | src/core.ts, cli.ts, mcp-server.ts | Add --until filter |
| wip-ldm-os-private | shared/prompts/*.md | New prompt templates |
| wip-ldm-os-private | scripts/ldm-summary.sh | Per-agent search, --date flag, org-wide combines agents |
| wip-ldm-os-private | bin/ldm.js | Deploy prompts |

## Verification

```bash
# Single day backfill
ldm-summary.sh daily --date 2026-02-10

# Check per-agent
cat ~/wipcomputerinc/team/cc-mini/automated/memory/summaries/daily/2026-02-10.md
cat ~/wipcomputerinc/team/Lēsa/automated/memory/summaries/daily/2026-02-10.md

# Check org-wide
cat ~/wipcomputerinc/operations/updates/team/daily/2026-02-10.md

# Verify trip wire: if .ldm/agents/ is empty, summary should fail
```
