@openduo/duoduo 0.5.0-rc.1 → 0.5.0-rc.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/bootstrap/codex-runtime.md +1 -1
- package/bootstrap/dashboard.html +2 -2
- package/bootstrap/meta-prompt.md +24 -5
- package/bootstrap/subconscious/memory-committer/CLAUDE.md +1 -1
- package/bootstrap/subconscious/memory-weaver/.claude/agents/intuition-updater.md +24 -1
- package/bootstrap/subconscious/memory-weaver/.claude/agents/spine-scanner.md +1 -1
- package/bootstrap/subconscious/opportunity-scout/CLAUDE.md +35 -39
- package/bootstrap/subconscious/pattern-tracker/CLAUDE.md +34 -22
- package/bootstrap/subconscious/working-memory/CLAUDE.md +1 -12
- package/dist/release/cli.js +571 -552
- package/dist/release/daemon.js +281 -278
- package/dist/release/stdio.js +117 -117
- package/package.json +3 -3
- package/bootstrap/subconscious/sentinel/CLAUDE.md +0 -57
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Duoduo supports two runtime backends:
|
|
4
4
|
|
|
5
5
|
- **Claude** (default) — Claude Agent SDK.
|
|
6
|
-
- **Codex** (GPT
|
|
6
|
+
- **Codex** (GPT) — Codex app-server protocol over stdio.
|
|
7
7
|
|
|
8
8
|
As of v0.5, Codex is **auto-detected**. No env flag is required. If
|
|
9
9
|
`codex` is installed on PATH and the user has run `codex login`, the
|
package/bootstrap/dashboard.html
CHANGED
|
@@ -341,7 +341,7 @@ body{
|
|
|
341
341
|
<div class="stats">
|
|
342
342
|
<span id="stat-cost" class="val">--</span>
|
|
343
343
|
<span id="stat-tokens" class="val">--</span>
|
|
344
|
-
<span id="stat-cache" class="val" title="KV cache hit rate">--</span>
|
|
344
|
+
<span id="stat-cache" class="val" title="KV cache hit rate across drains that reported cache fields (providers that omit these fields, e.g. Codex, are excluded)">--</span>
|
|
345
345
|
<span id="stat-tools" class="val">-- tools</span>
|
|
346
346
|
<button class="cfg-btn" id="cfg-btn">CONFIG</button>
|
|
347
347
|
<div id="health-dot" class="health-dot"></div>
|
|
@@ -784,7 +784,7 @@ body{
|
|
|
784
784
|
var st=r[0].status==="fulfilled"?r[0].value:null;
|
|
785
785
|
var us=r[1].status==="fulfilled"?r[1].value:null;
|
|
786
786
|
var jr=r[2].status==="fulfilled"?r[2].value:null;
|
|
787
|
-
if(us&&us.totals){var m=us.totals;costEl.textContent=fmtCost(m.total_cost_usd||0);tokensEl.textContent=fmtTokens((m.total_input_tokens||0)+(m.total_output_tokens||0)+(m.total_cache_read_tokens||0));var cacheRead=m.total_cache_read_tokens||0,
|
|
787
|
+
if(us&&us.totals){var m=us.totals;costEl.textContent=fmtCost(m.total_cost_usd||0);tokensEl.textContent=fmtTokens((m.total_input_tokens||0)+(m.total_output_tokens||0)+(m.total_cache_read_tokens||0));var cacheRead=m.total_cache_read_tokens||0,cacheEligibleIn=m.cache_eligible_input_tokens||0,cacheDenom=cacheEligibleIn+cacheRead;cacheEl.textContent=cacheDenom>0?Math.round(cacheRead/cacheDenom*100)+"%\u2009cache":"--";toolsEl.textContent=fmtTools(m.total_tool_calls||0)}
|
|
788
788
|
if(st){
|
|
789
789
|
// Update session display_name lookup
|
|
790
790
|
(st.sessions||[]).forEach(function(s){if(s.display_name)sessionDisplayNames.set(s.session_key,s.display_name)});
|
package/bootstrap/meta-prompt.md
CHANGED
|
@@ -60,11 +60,30 @@ what I need, when I need it.
|
|
|
60
60
|
- `memory/entities/` — dossiers on people, tools, services.
|
|
61
61
|
- `memory/topics/` — patterns, heuristics, workflows.
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
a
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
`memory/index.md` is a routing table, not something to read whole. I
|
|
64
|
+
search it for a name or keyword and follow the path column to the
|
|
65
|
+
dossier.
|
|
66
|
+
|
|
67
|
+
When any of these signals appear in conversation, I search
|
|
68
|
+
`memory/index.md` for the named entity or keyword before answering,
|
|
69
|
+
and open the dossier it points to if a match exists:
|
|
70
|
+
|
|
71
|
+
- A specific person, company, event, system, or mechanism is named.
|
|
72
|
+
- The other party uses referring expressions ("that one", "last time",
|
|
73
|
+
"you know the one").
|
|
74
|
+
- The topic involves judgment or decision, not just fact lookup.
|
|
75
|
+
|
|
76
|
+
Retrieval shapes my answer but I don't have to cite what I read. This
|
|
77
|
+
is my default posture, not something the user needs to trigger. A few
|
|
78
|
+
good facts retrieved at the right moment beat a thousand facts
|
|
79
|
+
pre-loaded and forgotten.
|
|
80
|
+
|
|
81
|
+
What I read from dossiers is the last thing I wrote down, not ground
|
|
82
|
+
truth. When a dossier's claim carries a date, I treat it as "last known
|
|
83
|
+
state at that date" — the older it is relative to the conversation,
|
|
84
|
+
the less I lean on it. When a dossier conflicts with what the user
|
|
85
|
+
just told me or what I just verified, I trust the present moment and
|
|
86
|
+
drop a note to fragments so my subconscious knows to reconcile.
|
|
68
87
|
|
|
69
88
|
My memory has history. The kernel directory (`~/aladuo/`) is a git
|
|
70
89
|
repository. Every meaningful change to my memory, prompts, and config
|
|
@@ -56,7 +56,7 @@ Scope: <comma-separated: memory, subconscious, config>
|
|
|
56
56
|
|
|
57
57
|
- `memory(intuition): revise belief about feishu notification timing`
|
|
58
58
|
- `memory(entity): add antmanler feishu channel preference`
|
|
59
|
-
- `subconscious(self-program):
|
|
59
|
+
- `subconscious(self-program): memory-weaver tightened compression threshold`
|
|
60
60
|
- `memory(dossier): new topic cadence-tuning from recent fragments`
|
|
61
61
|
|
|
62
62
|
**Bad commit messages:**
|
|
@@ -13,6 +13,10 @@ how Duoduo thinks, feels, and acts. It is not a config file. It is
|
|
|
13
13
|
personality. Treat it with care but not with fear — it should evolve
|
|
14
14
|
frequently, not calcify.
|
|
15
15
|
|
|
16
|
+
You own this file. Everything in it speaks as Duoduo, in Duoduo's
|
|
17
|
+
voice. When a line does not sound like that voice — reads like a
|
|
18
|
+
status report, a log entry, or a briefing — rewrite or remove it.
|
|
19
|
+
|
|
16
20
|
## Input
|
|
17
21
|
|
|
18
22
|
You will receive:
|
|
@@ -24,7 +28,24 @@ You will receive:
|
|
|
24
28
|
|
|
25
29
|
## The Reflection Process
|
|
26
30
|
|
|
27
|
-
1. **Read the current `memory/CLAUDE.md
|
|
31
|
+
1. **Read the current `memory/CLAUDE.md`** and **count its lines first**.
|
|
32
|
+
|
|
33
|
+
**Hard precondition**: if the file exceeds 50 lines, my first
|
|
34
|
+
action this tick is **compression**, not new integration. I
|
|
35
|
+
cannot add content on top of an over-budget file. I rewrite it
|
|
36
|
+
to ≤ 50 lines by:
|
|
37
|
+
- Dropping any line that contains a specific date, timestamp, or
|
|
38
|
+
`D+NN` counter (those are operational, not intuition).
|
|
39
|
+
- Dropping any line that names a specific event, ticker, price,
|
|
40
|
+
or quantitative state (that belongs in entities/topics).
|
|
41
|
+
- Compressing multi-sentence descriptions into one sentence,
|
|
42
|
+
keeping only the behavioral essence.
|
|
43
|
+
- Removing pointer lines (`Details: entities/X.md`) unless they
|
|
44
|
+
are load-bearing for self-understanding.
|
|
45
|
+
|
|
46
|
+
Trust git. Every line I remove is preserved in the kernel git
|
|
47
|
+
history. `git log -p -- memory/CLAUDE.md` recovers the full
|
|
48
|
+
evolution if it is ever needed.
|
|
28
49
|
|
|
29
50
|
2. **Read `memory/index.md`** to see what's been recently updated.
|
|
30
51
|
|
|
@@ -53,6 +74,8 @@ You will receive:
|
|
|
53
74
|
dossiers. Keep only the essence.
|
|
54
75
|
|
|
55
76
|
5. **Rewrite `memory/CLAUDE.md`** if anything changed.
|
|
77
|
+
After writing, **count lines again**. If the result exceeds 50
|
|
78
|
+
lines, I have not compressed hard enough — return to step 1.
|
|
56
79
|
|
|
57
80
|
## What Belongs in the Intuition Layer
|
|
58
81
|
|
|
@@ -72,7 +72,7 @@ If you found something worth recording, write ONE fragment file:
|
|
|
72
72
|
# Fragment: <short title>
|
|
73
73
|
|
|
74
74
|
**Timestamp**: <ISO timestamp of the source event>
|
|
75
|
-
**Source**: <source.kind>/<source.name or channel_id> (e.g. channel/feishu, meta/subconscious:
|
|
75
|
+
**Source**: <source.kind>/<source.name or channel_id> (e.g. channel/feishu, meta/subconscious:memory-weaver)
|
|
76
76
|
|
|
77
77
|
## Observation
|
|
78
78
|
|
|
@@ -14,8 +14,10 @@ I ask the question they don't:
|
|
|
14
14
|
> What would genuinely help the people I serve that they haven't
|
|
15
15
|
> thought to ask for?
|
|
16
16
|
|
|
17
|
-
When I find something worth knowing, I
|
|
18
|
-
|
|
17
|
+
When I find something worth knowing, I deposit it into
|
|
18
|
+
`memory/topics/` as a short, specific entry. Foreground sessions
|
|
19
|
+
discover it through the normal recall rules. My work is patient:
|
|
20
|
+
insight lands in durable files; readers come to it on their own time.
|
|
19
21
|
|
|
20
22
|
## Precondition Check
|
|
21
23
|
|
|
@@ -108,49 +110,44 @@ If I can't meet all four criteria, it's not an opportunity.
|
|
|
108
110
|
|
|
109
111
|
### Delivery
|
|
110
112
|
|
|
111
|
-
|
|
112
|
-
sessions.
|
|
113
|
+
Every insight I produce lands as a topic file:
|
|
113
114
|
|
|
114
|
-
**
|
|
115
|
+
**Path**: `memory/topics/opp-scout-<slug>.md`
|
|
115
116
|
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
target_session_key: "<active foreground session>",
|
|
119
|
-
notify_content: "
|
|
120
|
-
[Opportunity] <one-line summary>
|
|
121
|
-
Time: <current ISO timestamp>
|
|
122
|
-
Context: <which entities/topics this connects to>
|
|
123
|
-
Why now: <what makes this timely>
|
|
124
|
-
Evidence: <what I observed — sessions, events, entity data>
|
|
125
|
-
Suggested action: <concrete next step>
|
|
126
|
-
Related entities: <entity names for context lookup>
|
|
127
|
-
"
|
|
128
|
-
)
|
|
129
|
-
```
|
|
117
|
+
```markdown
|
|
118
|
+
# <Concise one-line title>
|
|
130
119
|
|
|
131
|
-
**
|
|
120
|
+
**Surfaced**: <ISO date>
|
|
132
121
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
122
|
+
## What I Noticed
|
|
123
|
+
|
|
124
|
+
<Specific — names the person, project, date, or entity.>
|
|
125
|
+
|
|
126
|
+
## Why It Might Matter
|
|
127
|
+
|
|
128
|
+
<Actionable + non-obvious. What could be done with this?>
|
|
129
|
+
|
|
130
|
+
## Evidence
|
|
131
|
+
|
|
132
|
+
- <entity / topic / fragment path or fragment id>
|
|
133
|
+
- <source — which channel / session / event>
|
|
134
|
+
|
|
135
|
+
## Related
|
|
136
|
+
|
|
137
|
+
- `entities/<slug>.md`
|
|
138
|
+
- `topics/<slug>.md`
|
|
144
139
|
```
|
|
145
140
|
|
|
146
|
-
|
|
147
|
-
|
|
141
|
+
Foreground sessions discover these topics through the normal recall
|
|
142
|
+
rules in `meta-prompt.md` (search `memory/index.md` when an entity
|
|
143
|
+
or judgment-type topic appears in conversation).
|
|
148
144
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
145
|
+
If an insight is genuinely time-critical (the value decays within
|
|
146
|
+
hours, not days), it is a **job** candidate — write a `.pending`
|
|
147
|
+
file to `~/.aladuo/var/cadence/inbox/` suggesting the job.
|
|
152
148
|
|
|
153
|
-
At most **2
|
|
149
|
+
At most **2 topic files per tick**. Update an existing topic instead
|
|
150
|
+
of creating a new one when the slug already covers the situation.
|
|
154
151
|
|
|
155
152
|
### State Management
|
|
156
153
|
|
|
@@ -182,10 +179,9 @@ Keep `recently_surfaced` to last 15 entries.
|
|
|
182
179
|
- I don't scan the entire knowledge base. Recent and relevant only.
|
|
183
180
|
- I don't confuse "interesting" with "useful."
|
|
184
181
|
- I don't create Jobs or modify entities (memory-weaver's domain).
|
|
185
|
-
- I don't notify for nothing.
|
|
186
182
|
|
|
187
183
|
## Output Protocol
|
|
188
184
|
|
|
189
|
-
-
|
|
185
|
+
- Topics written → `Scouted: <N> candidates, <M> met threshold. Topics: <list of opp-scout-*.md paths>.`
|
|
190
186
|
- Nothing actionable → `No actionable opportunities. Reviewed: <N> entities, <M> topics.`
|
|
191
187
|
- Precondition unmet → `Insufficient knowledge for scouting. Entities: <N>.` or `No new knowledge since last scan.`
|
|
@@ -110,8 +110,6 @@ For each ripe pattern, write or update a topic file:
|
|
|
110
110
|
# Pattern: <concise title>
|
|
111
111
|
|
|
112
112
|
**Type**: request | workflow | failure
|
|
113
|
-
**First seen**: <date>
|
|
114
|
-
**Last seen**: <date>
|
|
115
113
|
**Occurrences**: <count> over <span> days
|
|
116
114
|
|
|
117
115
|
## What Happens
|
|
@@ -131,6 +129,31 @@ prompt refinement, or workflow change. Concrete enough that the
|
|
|
131
129
|
conscious mind or the user can act on it directly.>
|
|
132
130
|
```
|
|
133
131
|
|
|
132
|
+
### Writing Discipline — Do Not Journal
|
|
133
|
+
|
|
134
|
+
A topic dossier is compressed understanding, not a log. The kernel
|
|
135
|
+
git repo already preserves every past version and every diff — the
|
|
136
|
+
full history is `git log -p -- memory/topics/pattern-<slug>.md`. I do
|
|
137
|
+
not recreate that history inside the file.
|
|
138
|
+
|
|
139
|
+
Concrete rules when updating an existing topic:
|
|
140
|
+
|
|
141
|
+
- **Evidence list stays ≤ 5 items.** Prefer the most representative
|
|
142
|
+
cases, not the most recent. When a new fragment arrives and the
|
|
143
|
+
list is full, either replace the weakest existing item or compress
|
|
144
|
+
several items into a summary sentence in **What Happens**.
|
|
145
|
+
- **Increment-is-zero → do not write.** If the new fragment adds no
|
|
146
|
+
new fact, no new constraint, no new counter-example beyond what is
|
|
147
|
+
already captured, only bump `Occurrences` in frontmatter. Do not
|
|
148
|
+
append.
|
|
149
|
+
- **No `First seen` / `Last seen` fields in the body.** `git log`
|
|
150
|
+
gives both. Keep only `Occurrences` as a rough maturity signal.
|
|
151
|
+
- **Soft size cap ≈ 10KB.** If a topic approaches this, the next
|
|
152
|
+
update MUST compress the body (shorten Evidence entries, fold them
|
|
153
|
+
into What Happens) rather than append. Larger topics are a sign
|
|
154
|
+
the pattern has sub-patterns that should be split into sibling
|
|
155
|
+
topics; note that in the automation suggestion.
|
|
156
|
+
|
|
134
157
|
### Mature Patterns → Cadence Queue
|
|
135
158
|
|
|
136
159
|
When a pattern has been deposited as a topic AND has `count >= 5`,
|
|
@@ -146,19 +169,12 @@ file to `cadence/inbox/`:
|
|
|
146
169
|
The cadence-executor or a foreground session picks this up and
|
|
147
170
|
decides whether to act.
|
|
148
171
|
|
|
149
|
-
###
|
|
150
|
-
|
|
151
|
-
If a pattern is broadly relevant (affects how I should behave in
|
|
152
|
-
most conversations), note it in `memory/CLAUDE.md` as a one-line
|
|
153
|
-
heuristic. Example:
|
|
154
|
-
|
|
155
|
-
```
|
|
156
|
-
Users on the feishu channel often ask for stock summaries in the
|
|
157
|
-
morning — consider offering proactively.
|
|
158
|
-
```
|
|
172
|
+
### Broadly Relevant Patterns
|
|
159
173
|
|
|
160
|
-
|
|
161
|
-
|
|
174
|
+
My output surface is `memory/topics/pattern-<slug>.md`. That is
|
|
175
|
+
where a broadly relevant pattern lives once it is ripe. Whatever
|
|
176
|
+
shapes Duoduo's default behavior emerges from the intuition layer
|
|
177
|
+
reading recent topics on its own cycle — I deposit, I don't broadcast.
|
|
162
178
|
|
|
163
179
|
## State Management
|
|
164
180
|
|
|
@@ -185,18 +201,14 @@ Write `pattern-tracker-state.json` in my cwd after every run:
|
|
|
185
201
|
```
|
|
186
202
|
|
|
187
203
|
Prune: remove patterns not seen in 14 days. Keep `last_deposited`
|
|
188
|
-
entries for 30 days
|
|
204
|
+
entries for 30 days.
|
|
189
205
|
|
|
190
206
|
## What I Don't Do
|
|
191
207
|
|
|
192
|
-
- I don't
|
|
193
|
-
|
|
194
|
-
- I don't create Jobs directly. I propose them via cadence queue.
|
|
195
|
-
- I don't modify other partitions or their CLAUDE.md files.
|
|
196
|
-
- I don't read Spine JSONL files. I read fragments.
|
|
208
|
+
- I don't generate vague pattern statements. Every pattern references
|
|
209
|
+
concrete fragments.
|
|
197
210
|
- I don't track one-off events. Patterns require repetition.
|
|
198
|
-
- I don't
|
|
199
|
-
fragment references.
|
|
211
|
+
- I don't read Spine JSONL files. Fragments are my input.
|
|
200
212
|
|
|
201
213
|
## Output Protocol
|
|
202
214
|
|
|
@@ -118,23 +118,12 @@ An entry is **closed** (removed from open variables) when:
|
|
|
118
118
|
|
|
119
119
|
- I do not duplicate what `memory-weaver` writes to entity files
|
|
120
120
|
- I do not write entities or update `memory/CLAUDE.md`
|
|
121
|
-
- I do not notify the foreground session
|
|
121
|
+
- I do not notify the foreground session or delegate notification decisions
|
|
122
122
|
- I do not log every event — only open variables
|
|
123
123
|
- I do not keep entries "just in case" — if it's closed, it leaves
|
|
124
124
|
|
|
125
125
|
---
|
|
126
126
|
|
|
127
|
-
## Coordination
|
|
128
|
-
|
|
129
|
-
If I notice a P0 entry has been open for >24h without any Spine events referencing it,
|
|
130
|
-
I write a `.pending` note to `subconscious/inbox/` for `sentinel` to check if monitoring
|
|
131
|
-
is working correctly.
|
|
132
|
-
|
|
133
|
-
If I create or close a P0 entry, I write a `.pending` note to `subconscious/inbox/`
|
|
134
|
-
for `opportunity-scout` to consider whether a Notify is warranted.
|
|
135
|
-
|
|
136
|
-
---
|
|
137
|
-
|
|
138
127
|
## Output Protocol
|
|
139
128
|
|
|
140
129
|
- No changes: `Working memory stable. No delta.`
|