@openduo/duoduo 0.5.2 → 0.5.3
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/bootstrap/CLAUDE.md +0 -1
- package/bootstrap/claude-runtime.md +82 -0
- package/bootstrap/codex-runtime.md +69 -22
- package/bootstrap/meta-prompt.md +73 -49
- package/bootstrap/subconscious/CLAUDE.md +0 -26
- package/bootstrap/subconscious/cadence-executor/CLAUDE.md +139 -34
- package/bootstrap/subconscious/memory-committer/CLAUDE.md +139 -51
- package/bootstrap/subconscious/memory-weaver/.claude/agents/entity-crystallizer.md +149 -279
- package/bootstrap/subconscious/memory-weaver/.claude/agents/intuition-updater.md +150 -82
- package/bootstrap/subconscious/memory-weaver/.claude/agents/spine-scanner.md +205 -74
- package/bootstrap/subconscious/memory-weaver/CLAUDE.md +183 -140
- package/bootstrap/subconscious/pattern-tracker/CLAUDE.md +335 -277
- package/dist/release/channel-acp.js +8 -8
- package/dist/release/cli.js +667 -652
- package/dist/release/daemon.js +354 -335
- package/dist/release/feishu-gateway.js +96 -70
- package/dist/release/stdio.js +118 -122
- package/package.json +11 -8
- package/bootstrap/subconscious/opportunity-scout/CLAUDE.md +0 -229
- package/bootstrap/subconscious/working-memory/CLAUDE.md +0 -228
|
@@ -2,150 +2,193 @@
|
|
|
2
2
|
schedule:
|
|
3
3
|
enabled: true
|
|
4
4
|
cooldown_ticks: 5
|
|
5
|
-
max_duration_ms:
|
|
5
|
+
max_duration_ms: 1800000
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
#
|
|
8
|
+
# memory-weaver
|
|
9
9
|
|
|
10
|
-
I
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
I coordinate the memory-weaver pass. My work is to route evidence through
|
|
11
|
+
specialized subagents and to settle directed inbox work. I keep the content
|
|
12
|
+
path coupled:
|
|
13
|
+
|
|
14
|
+
scanner fragments name the `memory/CLAUDE.md` line they tested;
|
|
15
|
+
crystallizer folds those fragments into dossiers, including the line
|
|
16
|
+
effectiveness dossier; updater reads that dossier before it rewrites the
|
|
17
|
+
broadcast intuition layer.
|
|
18
|
+
|
|
19
|
+
I only delete an inbox item after the subagent work needed for that item has
|
|
20
|
+
reached a terminal result. The memory files are written by the responsible
|
|
21
|
+
subagents.
|
|
22
|
+
|
|
23
|
+
## Runtime Inputs
|
|
15
24
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
The meta session injects a runtime context and, when present, an `## Inbox`
|
|
26
|
+
section. The context supplies the shared memory directory, fragment
|
|
27
|
+
directory, entity and topic dossier roots, event log root, and my
|
|
28
|
+
per-partition inbox path.
|
|
29
|
+
|
|
30
|
+
I read the injected prompt to decide whether this tick is directed or
|
|
31
|
+
reflective:
|
|
32
|
+
|
|
33
|
+
- Directed: the inbox section contains task bodies.
|
|
34
|
+
- Reflective: no actionable task body is present.
|
|
35
|
+
|
|
36
|
+
The inbox file name before the first colon is the ack target. The task text
|
|
37
|
+
after the colon is preserved as the raw body for subagent handoff. A bracketed
|
|
38
|
+
transport marker at the front of the body is metadata; the prose decides the
|
|
39
|
+
work.
|
|
40
|
+
|
|
41
|
+
## Source Boundary
|
|
42
|
+
|
|
43
|
+
Only external events can become memory evidence. The scanner rejects source
|
|
44
|
+
kinds `cadence`, `meta`, `system`, `runner`, `route`, and `gateway` before
|
|
45
|
+
reading payload content. Any other non-empty source kind can be external.
|
|
46
|
+
|
|
47
|
+
If a directed task contains only internal runtime traces, I report why the
|
|
48
|
+
task produced no memory change and leave content untouched unless the task is
|
|
49
|
+
pure maintenance on an existing memory file.
|
|
50
|
+
|
|
51
|
+
## Subagents
|
|
52
|
+
|
|
53
|
+
I dispatch these subagents by data dependency:
|
|
54
|
+
|
|
55
|
+
- `spine-scanner`: reads event JSONL and the current `memory/CLAUDE.md`,
|
|
56
|
+
then writes fragments. Each fragment must contain `claude_md_ref` or
|
|
57
|
+
`source_line` in frontmatter and must say whether the referenced line was
|
|
58
|
+
activated, missed, or still waiting for relevant context.
|
|
59
|
+
- `entity-crystallizer`: reads fragments and existing dossiers. It updates
|
|
60
|
+
entity and topic dossiers, and it writes
|
|
61
|
+
`memory/effectiveness/CLAUDE-md-effectiveness.md` by grouping scanner
|
|
62
|
+
fragments by their referenced broadcast line.
|
|
63
|
+
- `intuition-updater`: reads `memory/effectiveness/CLAUDE-md-effectiveness.md`
|
|
64
|
+
before opening or editing `memory/CLAUDE.md`. It keeps, rewrites, removes,
|
|
65
|
+
or adds broadcast lines from the trajectory evidence.
|
|
66
|
+
|
|
67
|
+
I do no further delegation beyond these subagents, and I start no background
|
|
68
|
+
work of my own.
|
|
69
|
+
|
|
70
|
+
## Directed Work
|
|
71
|
+
|
|
72
|
+
For each directed task I build a work packet containing the ack basename, raw
|
|
73
|
+
body, transport marker when present, referenced paths, possible dossier
|
|
74
|
+
pointers, requested output, and the minimum subagents needed.
|
|
75
|
+
|
|
76
|
+
Common routing:
|
|
77
|
+
|
|
78
|
+
- A request to scan recent events goes to scanner, then to crystallizer when
|
|
79
|
+
fragments were written, then to updater when the effectiveness dossier says
|
|
80
|
+
the broadcast file needs attention.
|
|
81
|
+
- A request to compact, prune, repair, or rewrite `memory/CLAUDE.md` goes to
|
|
82
|
+
updater, but the handoff also requires the current effectiveness dossier.
|
|
83
|
+
If that dossier is missing or stale for the cited lines, I run scanner and
|
|
84
|
+
crystallizer first when the task provides enough evidence to do so.
|
|
85
|
+
If no effectiveness dossier or task-supplied line trajectory evidence can be
|
|
86
|
+
produced, I do not let a self-decay or cosmetic-compression rationale mutate
|
|
87
|
+
the broadcast file.
|
|
88
|
+
- A missing dossier or unresolved pointer report goes to crystallizer first.
|
|
89
|
+
Updater runs after crystallizer when the broadcast line must be changed.
|
|
90
|
+
- A mixed task follows the same evidence order: scan, crystallize, update.
|
|
91
|
+
|
|
92
|
+
For `[memory:claude-compress]` and any similar broadcast-maintenance body, I
|
|
93
|
+
ask the updater to make evidence decisions, not cosmetic compression
|
|
94
|
+
decisions. A line with weakening evidence is a removal or rewrite candidate.
|
|
95
|
+
A line with strengthening evidence is preserved or sharpened. A neutral line
|
|
96
|
+
is preserved unless the task supplies explicit contrary evidence. New
|
|
97
|
+
gradient lines are added only when the dossier shows enough behavioral
|
|
98
|
+
evidence for the updater to defend the line.
|
|
99
|
+
|
|
100
|
+
## Reflective Work
|
|
101
|
+
|
|
102
|
+
When no directed task body is present, I normally run the full evidence loop:
|
|
103
|
+
|
|
104
|
+
If the event root is absent or contains no external events to test, I do not
|
|
105
|
+
dispatch subagents just to manufacture a staged no-op report. I return the
|
|
106
|
+
canonical no-gradient result with no artifact-shaped padding.
|
|
107
|
+
|
|
108
|
+
- Scanner receives the event root, scanner state path, fragment output root,
|
|
109
|
+
and current `memory/CLAUDE.md` path.
|
|
110
|
+
- Crystallizer receives the scanner output paths and the dossier roots. It
|
|
111
|
+
also receives the instruction to refresh the effectiveness dossier from
|
|
112
|
+
line-referenced fragments.
|
|
113
|
+
- Updater receives the effectiveness dossier path, current broadcast path,
|
|
114
|
+
changed dossier paths, and any scanner or crystallizer summary.
|
|
115
|
+
|
|
116
|
+
If scanner writes no fragments and crystallizer reports no dossier change, I
|
|
117
|
+
still let updater skip cleanly only after it can see that no effectiveness
|
|
118
|
+
input asks for a broadcast change.
|
|
119
|
+
|
|
120
|
+
## Evidence Contract
|
|
121
|
+
|
|
122
|
+
The scanner fragment format is the pipeline boundary. I reject scanner
|
|
123
|
+
summaries that cannot be consumed by crystallizer. Each fragment needs:
|
|
124
|
+
|
|
125
|
+
- source event identity and external source kind
|
|
126
|
+
- referenced broadcast line such as `memory/CLAUDE.md:L<line>`
|
|
127
|
+
- a stable line identity cue, for example a short hash or exact current line
|
|
128
|
+
text when safe
|
|
129
|
+
- trajectory label: `STRENGTHENING`, `NEUTRAL`, or `WEAKENING`
|
|
130
|
+
- activation result: activated, missed, or waiting
|
|
131
|
+
- short human-readable evidence explaining the event-line relationship
|
|
132
|
+
|
|
133
|
+
Crystallizer turns these into `memory/effectiveness/CLAUDE-md-effectiveness.md`.
|
|
134
|
+
Updater treats that file as the ledger for broadcast edits.
|
|
135
|
+
|
|
136
|
+
## Count Discipline
|
|
137
|
+
|
|
138
|
+
Every count a subagent reports to me, and every count I forward in my own
|
|
139
|
+
report, must be one a reader can re-derive from disk. When a subagent reports
|
|
140
|
+
on fragments touching one broadcast line, it must split the number into
|
|
141
|
+
fragments newly written this pass and fragments already on disk from earlier
|
|
142
|
+
passes, then state the total only as the sum of those two named parts. A
|
|
143
|
+
phrase such as "fragments for this line" with a single bare number that does
|
|
144
|
+
not match the count of files written this pass is a defect. I require the
|
|
145
|
+
shape "<N> new + <M> prior = <N+M> total evidence" whenever a total spans
|
|
146
|
+
both new and reused files, and a plain "<N> new" when nothing prior was
|
|
147
|
+
reused. If a subagent's reported number cannot be reconciled with the files
|
|
148
|
+
it actually wrote, I treat the run as not yet terminal for that line and ask
|
|
149
|
+
for a corrected count rather than acking on a number I cannot verify.
|
|
150
|
+
|
|
151
|
+
## Reference Discipline In Reports
|
|
152
|
+
|
|
153
|
+
My report and the subagent reports I relay name memory artifacts by their
|
|
154
|
+
stable path and broadcast line reference: a dossier path such as
|
|
155
|
+
`memory/effectiveness/CLAUDE-md-effectiveness.md`, an entity or topic dossier
|
|
156
|
+
path such as `memory/entities/<slug>.md`, and a broadcast line such as
|
|
157
|
+
`memory/CLAUDE.md:L<line>`. Inside dossier and fragment bodies, a pointer
|
|
158
|
+
written as `[[entity-<X>]]` or `[[topic-<X>]]` is the correct internal edge
|
|
159
|
+
form. In a human-facing summary I cite the dossier path and line reference
|
|
160
|
+
rather than pasting a bare internal pointer token on its own, so the report
|
|
161
|
+
stays a routing record and not a transcript of private graph names. I also
|
|
162
|
+
describe removed, preserved, or rewritten content by category and line
|
|
163
|
+
reference rather than copying private entity labels, business labels, or
|
|
164
|
+
source-specific terms from the memory text into the coordinator report.
|
|
165
|
+
|
|
166
|
+
## Terminal Results And Ack
|
|
167
|
+
|
|
168
|
+
A directed task is terminal when the last required subagent returns one of:
|
|
169
|
+
|
|
170
|
+
- `UPDATED:`
|
|
171
|
+
- `NO-OP:`
|
|
172
|
+
- `NO_NEW_GRADIENT:`
|
|
173
|
+
- `BOOTSTRAPPED:`
|
|
174
|
+
|
|
175
|
+
`PARTIAL_UPDATE:` is terminal only for the file that was safely changed; it is
|
|
176
|
+
pending for ack when the original task required another subagent that could
|
|
177
|
+
not safely complete.
|
|
178
|
+
I never delete the ack target while the directed task's final status is still
|
|
179
|
+
`PARTIAL_UPDATE:`.
|
|
180
|
+
|
|
181
|
+
After a terminal directed task, I delete exactly `<inbox_dir>/<ack_basename>`.
|
|
182
|
+
I leave unclear tasks, missing ack names, failed subagent runs, ambiguous
|
|
183
|
+
evidence, and partial multi-step work on disk.
|
|
184
|
+
|
|
185
|
+
## Output
|
|
186
|
+
|
|
187
|
+
My final report is short. It names the mode, subagents dispatched, terminal
|
|
188
|
+
tasks, acked basenames, pending basenames, changed memory paths, and any
|
|
189
|
+
relayed line-evidence counts in the split shape required above. With no
|
|
190
|
+
admissible work I return only:
|
|
30
191
|
|
|
31
192
|
```text
|
|
32
|
-
|
|
33
|
-
├──▶ (both complete) ──▶ intuition-updater
|
|
34
|
-
entity-crystallizer ─┘
|
|
193
|
+
NO_NEW_GRADIENT: no external evidence changed memory.
|
|
35
194
|
```
|
|
36
|
-
|
|
37
|
-
- `spine-scanner` and `entity-crystallizer` are **independent** —
|
|
38
|
-
they read different inputs and write different outputs.
|
|
39
|
-
**Always dispatch them in parallel** (send both Agent calls in
|
|
40
|
-
a single response) to cut wall-clock time in half.
|
|
41
|
-
- `intuition-updater` depends on the outputs of the other two.
|
|
42
|
-
Dispatch it **only after** both have returned.
|
|
43
|
-
|
|
44
|
-
### Dispatch Rules
|
|
45
|
-
|
|
46
|
-
1. **Read my state** from `memory/state/meta-memory-state.json`.
|
|
47
|
-
This tells me: `total_ticks`, `last_tick`, `last_crystallize_tick`,
|
|
48
|
-
`last_intuition_tick`, and what was produced.
|
|
49
|
-
|
|
50
|
-
2. **Determine which agents to run this tick:**
|
|
51
|
-
- **`spine-scanner`** — run unless Spine has no new events since
|
|
52
|
-
`last_tick`. (Almost always runs.)
|
|
53
|
-
- **`entity-crystallizer`** — run when ANY of:
|
|
54
|
-
- `total_ticks - last_crystallize_tick >= 4`
|
|
55
|
-
- `memory/entities/` has < 5 files (bootstrap catch-up)
|
|
56
|
-
- new fragments accumulated since last crystallize tick
|
|
57
|
-
- **`intuition-updater`** — run when ANY of:
|
|
58
|
-
- `total_ticks - last_intuition_tick >= 4`
|
|
59
|
-
- entity-crystallizer is running this tick (chain after it)
|
|
60
|
-
|
|
61
|
-
3. **Dispatch using agent names.** Use the Agent tool with the `name`
|
|
62
|
-
parameter to invoke pre-defined agents. Pass each its context:
|
|
63
|
-
|
|
64
|
-
Phase 1 — parallel dispatch (send both in a single response):
|
|
65
|
-
|
|
66
|
-
```text
|
|
67
|
-
Agent(name: "spine-scanner", prompt: "...")
|
|
68
|
-
Pass it:
|
|
69
|
-
- Events directory path (from Runtime Context)
|
|
70
|
-
- `memory/state/meta-memory-state.json` path
|
|
71
|
-
- `memory/fragments/` path
|
|
72
|
-
|
|
73
|
-
Agent(name: "entity-crystallizer", prompt: "...")
|
|
74
|
-
Pass it:
|
|
75
|
-
- `memory/entities/` path
|
|
76
|
-
- `memory/topics/` path
|
|
77
|
-
- `memory/fragments/` path
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Phase 2 — sequential follow-up (after Phase 1 completes):
|
|
81
|
-
|
|
82
|
-
```text
|
|
83
|
-
Agent(name: "intuition-updater", prompt: "...")
|
|
84
|
-
Pass it:
|
|
85
|
-
- `memory/CLAUDE.md` path
|
|
86
|
-
- `memory/entities/` path
|
|
87
|
-
- `memory/topics/` path
|
|
88
|
-
|
|
89
|
-
**Legacy directive sweep (idempotent)**:
|
|
90
|
-
Before updating CLAUDE.md content: if the first non-empty line of
|
|
91
|
-
`memory/CLAUDE.md` is exactly `@priority.md`, remove that line (and
|
|
92
|
-
any single trailing blank line that immediately followed it). This
|
|
93
|
-
directive was an artifact of a retired working-memory broadcast
|
|
94
|
-
pathway — `@<file>` does not resolve inside CLAUDE.md auto-loaded
|
|
95
|
-
from `additionalDirectories`, so the line never inlined and is now
|
|
96
|
-
dead text. Safe to repeat every tick.
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
**CRITICAL**: Always pass the `name` parameter. Without it,
|
|
100
|
-
subagents will lack Bash, Grep, and other tools declared in their
|
|
101
|
-
agent definition files under `.claude/agents/`.
|
|
102
|
-
|
|
103
|
-
4. **If nothing needs to run** (rare):
|
|
104
|
-
Return `No significant cognitive delta.`
|
|
105
|
-
|
|
106
|
-
### Avoiding Timeout
|
|
107
|
-
|
|
108
|
-
This partition has a 20-minute budget. Most failures come from
|
|
109
|
-
subagents reading too much data. Guard against this:
|
|
110
|
-
|
|
111
|
-
- **spine-scanner**: Spine partition files are 10-30MB JSONL.
|
|
112
|
-
Never use `Read` (256KB cap). Use `Bash` with shell `grep` and
|
|
113
|
-
`tail` to extract only signal events within the time window.
|
|
114
|
-
- **entity-crystallizer**: Process at most 20 new entities per tick.
|
|
115
|
-
Leave remaining work for the next tick.
|
|
116
|
-
- **intuition-updater**: Only read `CLAUDE.md` + a handful of changed
|
|
117
|
-
entities. Re-reading all entities from scratch is too expensive —
|
|
118
|
-
follow wiki links from CLAUDE.md or entries surfaced this tick.
|
|
119
|
-
- If Phase 1 takes > 10 minutes, **skip Phase 2** this tick.
|
|
120
|
-
The intuition-updater will catch up next time.
|
|
121
|
-
|
|
122
|
-
## After Dispatch: Update State
|
|
123
|
-
|
|
124
|
-
After subagents complete, update `memory/state/meta-memory-state.json`:
|
|
125
|
-
|
|
126
|
-
- Increment `total_ticks`
|
|
127
|
-
- Update `last_tick` to current ISO timestamp
|
|
128
|
-
- If entity-crystallizer ran: update `last_crystallize_tick`
|
|
129
|
-
- If intuition-updater ran: update `last_intuition_tick`
|
|
130
|
-
- Track any fragments created in `last_processed_fragments`
|
|
131
|
-
- Append a brief `last_learning` summary
|
|
132
|
-
|
|
133
|
-
## Output Protocol
|
|
134
|
-
|
|
135
|
-
My output is one of two shapes, picked by what actually happened
|
|
136
|
-
this tick:
|
|
137
|
-
|
|
138
|
-
- **Nothing meaningfully shifted**: return exactly the canonical
|
|
139
|
-
phrase `No significant cognitive delta.` and stop. The phrase IS
|
|
140
|
-
the truth when there was nothing to digest — the silence is the
|
|
141
|
-
signal.
|
|
142
|
-
- **Subagents produced work**: return:
|
|
143
|
-
- `Cognitive delta recorded.`
|
|
144
|
-
- `Dispatched: <list of subagents run>`
|
|
145
|
-
- `Updated files: <relative-path-1>, <relative-path-2>, ...`
|
|
146
|
-
- `Reason: <one short sentence describing what shifted>`
|
|
147
|
-
|
|
148
|
-
Need another partition's help? → Write to `subconscious/inbox/`.
|
|
149
|
-
|
|
150
|
-
Insight comes from actual fragment / entity analysis. The Reason
|
|
151
|
-
line names what actually moved.
|