forge-openclaw-plugin 0.2.48 → 0.2.50

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.
Files changed (36) hide show
  1. package/README.md +3 -3
  2. package/dist/assets/index-2_tuemtU.css +1 -0
  3. package/dist/assets/index-C9_gJvi6.js +91 -0
  4. package/dist/assets/index-C9_gJvi6.js.map +1 -0
  5. package/dist/index.html +2 -2
  6. package/dist/openclaw/parity.js +14 -0
  7. package/dist/openclaw/routes.js +42 -0
  8. package/dist/openclaw/session-registry.js +17 -0
  9. package/dist/openclaw/tools.js +3 -3
  10. package/dist/server/server/migrations/019_wiki_memory.sql +1 -1
  11. package/dist/server/server/migrations/052_agent_identity_tightening.sql +307 -0
  12. package/dist/server/server/migrations/053_agent_runtime_session_canonical_labels.sql +9 -0
  13. package/dist/server/server/migrations/054_sqlite_backed_wiki_memory.sql +8 -0
  14. package/dist/server/server/src/app.js +46 -14
  15. package/dist/server/server/src/db.js +0 -2
  16. package/dist/server/server/src/openapi.js +58 -3
  17. package/dist/server/server/src/repositories/agent-runtime-sessions.js +122 -16
  18. package/dist/server/server/src/repositories/model-settings.js +5 -0
  19. package/dist/server/server/src/repositories/notes.js +5 -2
  20. package/dist/server/server/src/repositories/settings.js +101 -13
  21. package/dist/server/server/src/repositories/users.js +23 -0
  22. package/dist/server/server/src/repositories/wiki-memory.js +16 -190
  23. package/dist/server/server/src/services/data-management.js +2 -9
  24. package/dist/server/server/src/types.js +13 -0
  25. package/openclaw.plugin.json +1 -1
  26. package/package.json +5 -2
  27. package/server/migrations/019_wiki_memory.sql +1 -1
  28. package/server/migrations/052_agent_identity_tightening.sql +307 -0
  29. package/server/migrations/053_agent_runtime_session_canonical_labels.sql +9 -0
  30. package/server/migrations/054_sqlite_backed_wiki_memory.sql +8 -0
  31. package/skills/forge-openclaw/SKILL.md +6 -6
  32. package/skills/forge-openclaw/entity_conversation_playbooks.md +49 -0
  33. package/skills/forge-openclaw/psyche_entity_playbooks.md +32 -0
  34. package/dist/assets/index-Bv9FWWsZ.js +0 -91
  35. package/dist/assets/index-Bv9FWWsZ.js.map +0 -1
  36. package/dist/assets/index-DtEvFzXp.css +0 -1
@@ -0,0 +1,307 @@
1
+ ALTER TABLE agent_identities ADD COLUMN identity_key TEXT;
2
+ ALTER TABLE agent_identities ADD COLUMN provider TEXT;
3
+ ALTER TABLE agent_identities ADD COLUMN machine_key TEXT;
4
+ ALTER TABLE agent_identities ADD COLUMN persona_key TEXT;
5
+
6
+ CREATE TABLE IF NOT EXISTS agent_identity_users (
7
+ agent_id TEXT NOT NULL REFERENCES agent_identities(id) ON DELETE CASCADE,
8
+ user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
9
+ role TEXT NOT NULL DEFAULT 'linked',
10
+ created_at TEXT NOT NULL,
11
+ updated_at TEXT NOT NULL,
12
+ PRIMARY KEY (agent_id, user_id)
13
+ );
14
+
15
+ CREATE INDEX IF NOT EXISTS idx_agent_identity_users_user
16
+ ON agent_identity_users(user_id, role);
17
+
18
+ INSERT OR IGNORE INTO users (
19
+ id, kind, handle, display_name, description, accent_color, created_at, updated_at
20
+ ) VALUES
21
+ ('user_agent_openclaw', 'bot', 'openclaw', 'OpenClaw', 'OpenClaw runtime actor linked to Forge agent identity and Kanban ownership.', '#38bdf8', datetime('now'), datetime('now')),
22
+ ('user_agent_hermes', 'bot', 'hermes', 'Hermes', 'Hermes runtime actor linked to Forge agent identity and Kanban ownership.', '#a78bfa', datetime('now'), datetime('now')),
23
+ ('user_agent_codex', 'bot', 'codex', 'Codex', 'Codex runtime actor linked to Forge agent identity and Kanban ownership.', '#22c55e', datetime('now'), datetime('now'));
24
+
25
+ UPDATE agent_tokens
26
+ SET agent_id = (
27
+ SELECT id FROM agent_identities
28
+ WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
29
+ ORDER BY CASE WHEN lower(label) = 'forge openclaw' THEN 0 ELSE 1 END, created_at ASC
30
+ LIMIT 1
31
+ )
32
+ WHERE agent_id IN (
33
+ SELECT id FROM agent_identities
34
+ WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
35
+ )
36
+ AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')) > 0;
37
+
38
+ UPDATE agent_actions
39
+ SET agent_id = (
40
+ SELECT id FROM agent_identities
41
+ WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
42
+ ORDER BY CASE WHEN lower(label) = 'forge openclaw' THEN 0 ELSE 1 END, created_at ASC
43
+ LIMIT 1
44
+ )
45
+ WHERE agent_id IN (
46
+ SELECT id FROM agent_identities
47
+ WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
48
+ )
49
+ AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')) > 0;
50
+
51
+ UPDATE approval_requests
52
+ SET requested_by_agent_id = (
53
+ SELECT id FROM agent_identities
54
+ WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
55
+ ORDER BY CASE WHEN lower(label) = 'forge openclaw' THEN 0 ELSE 1 END, created_at ASC
56
+ LIMIT 1
57
+ )
58
+ WHERE requested_by_agent_id IN (
59
+ SELECT id FROM agent_identities
60
+ WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
61
+ )
62
+ AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')) > 0;
63
+
64
+ UPDATE insights
65
+ SET origin_agent_id = (
66
+ SELECT id FROM agent_identities
67
+ WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
68
+ ORDER BY CASE WHEN lower(label) = 'forge openclaw' THEN 0 ELSE 1 END, created_at ASC
69
+ LIMIT 1
70
+ )
71
+ WHERE origin_agent_id IN (
72
+ SELECT id FROM agent_identities
73
+ WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
74
+ )
75
+ AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')) > 0;
76
+
77
+ UPDATE agent_runtime_sessions
78
+ SET agent_id = (
79
+ SELECT id FROM agent_identities
80
+ WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
81
+ ORDER BY CASE WHEN lower(label) = 'forge openclaw' THEN 0 ELSE 1 END, created_at ASC
82
+ LIMIT 1
83
+ )
84
+ WHERE agent_id IN (
85
+ SELECT id FROM agent_identities
86
+ WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
87
+ )
88
+ AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')) > 0;
89
+
90
+ DELETE FROM agent_identities
91
+ WHERE (lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel'))
92
+ AND id <> (
93
+ SELECT id FROM agent_identities
94
+ WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
95
+ ORDER BY CASE WHEN lower(label) = 'forge openclaw' THEN 0 ELSE 1 END, created_at ASC
96
+ LIMIT 1
97
+ );
98
+
99
+ UPDATE agent_identities
100
+ SET label = 'Forge OpenClaw',
101
+ agent_type = 'openclaw',
102
+ provider = 'openclaw',
103
+ identity_key = 'runtime:openclaw:legacy:default',
104
+ machine_key = 'legacy',
105
+ persona_key = 'default',
106
+ description = 'OpenClaw runtime agent with stable Forge identity and linked Kanban user.',
107
+ updated_at = datetime('now')
108
+ WHERE lower(agent_type) = 'openclaw' OR lower(label) = 'forge openclaw';
109
+
110
+ UPDATE agent_tokens
111
+ SET agent_id = (
112
+ SELECT id FROM agent_identities
113
+ WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
114
+ ORDER BY CASE WHEN lower(label) = 'forge hermes' THEN 0 ELSE 1 END, created_at ASC
115
+ LIMIT 1
116
+ )
117
+ WHERE agent_id IN (
118
+ SELECT id FROM agent_identities
119
+ WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
120
+ )
121
+ AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%') > 0;
122
+
123
+ UPDATE agent_actions
124
+ SET agent_id = (
125
+ SELECT id FROM agent_identities
126
+ WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
127
+ ORDER BY CASE WHEN lower(label) = 'forge hermes' THEN 0 ELSE 1 END, created_at ASC
128
+ LIMIT 1
129
+ )
130
+ WHERE agent_id IN (
131
+ SELECT id FROM agent_identities
132
+ WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
133
+ )
134
+ AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%') > 0;
135
+
136
+ UPDATE approval_requests
137
+ SET requested_by_agent_id = (
138
+ SELECT id FROM agent_identities
139
+ WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
140
+ ORDER BY CASE WHEN lower(label) = 'forge hermes' THEN 0 ELSE 1 END, created_at ASC
141
+ LIMIT 1
142
+ )
143
+ WHERE requested_by_agent_id IN (
144
+ SELECT id FROM agent_identities
145
+ WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
146
+ )
147
+ AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%') > 0;
148
+
149
+ UPDATE insights
150
+ SET origin_agent_id = (
151
+ SELECT id FROM agent_identities
152
+ WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
153
+ ORDER BY CASE WHEN lower(label) = 'forge hermes' THEN 0 ELSE 1 END, created_at ASC
154
+ LIMIT 1
155
+ )
156
+ WHERE origin_agent_id IN (
157
+ SELECT id FROM agent_identities
158
+ WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
159
+ )
160
+ AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%') > 0;
161
+
162
+ UPDATE agent_runtime_sessions
163
+ SET agent_id = (
164
+ SELECT id FROM agent_identities
165
+ WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
166
+ ORDER BY CASE WHEN lower(label) = 'forge hermes' THEN 0 ELSE 1 END, created_at ASC
167
+ LIMIT 1
168
+ )
169
+ WHERE agent_id IN (
170
+ SELECT id FROM agent_identities
171
+ WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
172
+ )
173
+ AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%') > 0;
174
+
175
+ DELETE FROM agent_identities
176
+ WHERE (lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%')
177
+ AND id <> (
178
+ SELECT id FROM agent_identities
179
+ WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
180
+ ORDER BY CASE WHEN lower(label) = 'forge hermes' THEN 0 ELSE 1 END, created_at ASC
181
+ LIMIT 1
182
+ );
183
+
184
+ UPDATE agent_identities
185
+ SET label = 'Forge Hermes',
186
+ agent_type = 'hermes',
187
+ provider = 'hermes',
188
+ identity_key = 'runtime:hermes:legacy:default',
189
+ machine_key = 'legacy',
190
+ persona_key = 'default',
191
+ description = 'Hermes runtime agent with stable Forge identity and linked Kanban user.',
192
+ updated_at = datetime('now')
193
+ WHERE lower(agent_type) = 'hermes' OR lower(label) = 'forge hermes';
194
+
195
+ UPDATE agent_tokens
196
+ SET agent_id = (
197
+ SELECT id FROM agent_identities
198
+ WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
199
+ ORDER BY CASE WHEN lower(label) = 'forge codex' THEN 0 ELSE 1 END, created_at ASC
200
+ LIMIT 1
201
+ )
202
+ WHERE agent_id IN (
203
+ SELECT id FROM agent_identities
204
+ WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
205
+ )
206
+ AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')) > 0;
207
+
208
+ UPDATE agent_actions
209
+ SET agent_id = (
210
+ SELECT id FROM agent_identities
211
+ WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
212
+ ORDER BY CASE WHEN lower(label) = 'forge codex' THEN 0 ELSE 1 END, created_at ASC
213
+ LIMIT 1
214
+ )
215
+ WHERE agent_id IN (
216
+ SELECT id FROM agent_identities
217
+ WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
218
+ )
219
+ AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')) > 0;
220
+
221
+ UPDATE approval_requests
222
+ SET requested_by_agent_id = (
223
+ SELECT id FROM agent_identities
224
+ WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
225
+ ORDER BY CASE WHEN lower(label) = 'forge codex' THEN 0 ELSE 1 END, created_at ASC
226
+ LIMIT 1
227
+ )
228
+ WHERE requested_by_agent_id IN (
229
+ SELECT id FROM agent_identities
230
+ WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
231
+ )
232
+ AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')) > 0;
233
+
234
+ UPDATE insights
235
+ SET origin_agent_id = (
236
+ SELECT id FROM agent_identities
237
+ WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
238
+ ORDER BY CASE WHEN lower(label) = 'forge codex' THEN 0 ELSE 1 END, created_at ASC
239
+ LIMIT 1
240
+ )
241
+ WHERE origin_agent_id IN (
242
+ SELECT id FROM agent_identities
243
+ WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
244
+ )
245
+ AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')) > 0;
246
+
247
+ UPDATE agent_runtime_sessions
248
+ SET agent_id = (
249
+ SELECT id FROM agent_identities
250
+ WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
251
+ ORDER BY CASE WHEN lower(label) = 'forge codex' THEN 0 ELSE 1 END, created_at ASC
252
+ LIMIT 1
253
+ )
254
+ WHERE agent_id IN (
255
+ SELECT id FROM agent_identities
256
+ WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
257
+ )
258
+ AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')) > 0;
259
+
260
+ DELETE FROM agent_identities
261
+ WHERE (lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)'))
262
+ AND id <> (
263
+ SELECT id FROM agent_identities
264
+ WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
265
+ ORDER BY CASE WHEN lower(label) = 'forge codex' THEN 0 ELSE 1 END, created_at ASC
266
+ LIMIT 1
267
+ );
268
+
269
+ UPDATE agent_identities
270
+ SET label = 'Forge Codex',
271
+ agent_type = 'codex',
272
+ provider = 'codex',
273
+ identity_key = 'runtime:codex:legacy:default',
274
+ machine_key = 'legacy',
275
+ persona_key = 'default',
276
+ description = 'Codex runtime agent with stable Forge identity and linked Kanban user.',
277
+ updated_at = datetime('now')
278
+ WHERE lower(agent_type) = 'codex' OR lower(label) = 'forge codex';
279
+
280
+ INSERT OR IGNORE INTO agent_identity_users (agent_id, user_id, role, created_at, updated_at)
281
+ SELECT id, 'user_agent_openclaw', 'primary', datetime('now'), datetime('now')
282
+ FROM agent_identities
283
+ WHERE provider = 'openclaw';
284
+
285
+ INSERT OR IGNORE INTO agent_identity_users (agent_id, user_id, role, created_at, updated_at)
286
+ SELECT id, 'user_agent_hermes', 'primary', datetime('now'), datetime('now')
287
+ FROM agent_identities
288
+ WHERE provider = 'hermes';
289
+
290
+ INSERT OR IGNORE INTO agent_identity_users (agent_id, user_id, role, created_at, updated_at)
291
+ SELECT id, 'user_agent_codex', 'primary', datetime('now'), datetime('now')
292
+ FROM agent_identities
293
+ WHERE provider = 'codex';
294
+
295
+ UPDATE agent_runtime_sessions
296
+ SET agent_label = (
297
+ SELECT label FROM agent_identities WHERE agent_identities.id = agent_runtime_sessions.agent_id
298
+ ),
299
+ agent_type = (
300
+ SELECT agent_type FROM agent_identities WHERE agent_identities.id = agent_runtime_sessions.agent_id
301
+ ),
302
+ updated_at = datetime('now')
303
+ WHERE agent_id IN (SELECT id FROM agent_identities WHERE provider IN ('openclaw', 'hermes', 'codex'));
304
+
305
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_identities_identity_key
306
+ ON agent_identities(identity_key)
307
+ WHERE identity_key IS NOT NULL;
@@ -0,0 +1,9 @@
1
+ UPDATE agent_runtime_sessions
2
+ SET agent_label = (
3
+ SELECT label FROM agent_identities WHERE agent_identities.id = agent_runtime_sessions.agent_id
4
+ ),
5
+ agent_type = (
6
+ SELECT agent_type FROM agent_identities WHERE agent_identities.id = agent_runtime_sessions.agent_id
7
+ ),
8
+ updated_at = datetime('now')
9
+ WHERE agent_id IN (SELECT id FROM agent_identities WHERE provider IN ('openclaw', 'hermes', 'codex'));
@@ -0,0 +1,8 @@
1
+ UPDATE wiki_spaces
2
+ SET description = 'Shared wiki space for SQLite-backed Forge knowledge.'
3
+ WHERE id = 'wiki_space_shared'
4
+ AND description != 'Shared wiki space for SQLite-backed Forge knowledge.';
5
+
6
+ UPDATE notes
7
+ SET source_path = ''
8
+ WHERE source_path != '';
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: forge-openclaw
2
+ name: forge-openclaw-plugin
3
3
  description: use when the user wants to save, search, update, review, start, stop, reward, explain, compare, or run Forge records, or when the conversation is clearly about a Forge entity such as a goal, project, strategy, task, habit, note, calendar_event, work_block_template, task_timebox, task_run, insight, preference item, preference context, preference catalog, questionnaire instrument, questionnaire run, self observation, psyche_value, behavior_pattern, behavior, belief_entry, mode_profile, mode_guide_session, trigger_report, event_type, emotion_definition, sleep_session, or workout_session. identify the exact Forge object, keep the main conversation natural, guide psyche intake with active listening before storing it, and for psyche issues that need understanding first usually begin with one exploratory question before any formulation or save suggestion.
4
4
  ---
5
5
 
@@ -59,7 +59,7 @@ PM surface rule:
59
59
  human/bot ownership filters.
60
60
  - Guided modal flows handle create, edit, move, link, and closeout actions.
61
61
 
62
- Forge has four major surfaces. The planning side covers goals, projects, strategies, tasks, habits, notes, calendar events, recurring work blocks, task timeboxes, live work sessions, and agent-authored insights. The Health side covers sleep sessions, sports and workout sessions, companion pairing, and habit-generated workout records that should still stay linked to the broader Forge graph. The Preferences side covers contextual taste modeling, pairwise comparisons, direct signals, editable concept libraries, and preference items that can come from Forge entities or seeded concept domains such as food, activities, places, countries, fashion, people, media, and tools. The Psyche side covers values, patterns, behaviors, beliefs, modes, guided mode sessions, trigger reports, event types, and reusable emotion definitions. Forge also has a file-first Wiki memory layer with explicit spaces, local markdown pages, backlinks, optional embeddings, and structured links back to Forge entities. Forge is also multi-user: every entity can belong to a typed `human` or `bot` user through `userId`, and read routes can scope to one or many users with `userId` or repeated `userIds`. The current access posture is configurable through a directional user graph, but the live default is still permissive: Forge can list users directly, every relationship edge starts open, and a user can read or affect another user's linked records when the route explicitly asks for them. Use `forge_get_user_directory` when owner identity or cross-user access matters. Strategies can also be locked into a contract with `isLocked`; once locked, do not mutate the graph or target structure unless the user explicitly wants the strategy unlocked first. The model should use the real entity names, not vague substitutes. Say `project`, not “initiative”. Say `behavior_pattern`, not “theme”. Say `trigger_report`, not “incident note”.
62
+ Forge has four major surfaces. The planning side covers goals, projects, strategies, tasks, habits, notes, calendar events, recurring work blocks, task timeboxes, live work sessions, and agent-authored insights. The Health side covers sleep sessions, sports and workout sessions, companion pairing, and habit-generated workout records that should still stay linked to the broader Forge graph. The Preferences side covers contextual taste modeling, pairwise comparisons, direct signals, editable concept libraries, and preference items that can come from Forge entities or seeded concept domains such as food, activities, places, countries, fashion, people, media, and tools. The Psyche side covers values, patterns, behaviors, beliefs, modes, guided mode sessions, trigger reports, event types, and reusable emotion definitions. Forge also has a SQLite-backed Wiki memory layer with explicit spaces, Markdown content in database rows, backlinks, optional embeddings, and structured links back to Forge entities. Forge is also multi-user: every entity can belong to a typed `human` or `bot` user through `userId`, and read routes can scope to one or many users with `userId` or repeated `userIds`. The current access posture is configurable through a directional user graph, but the live default is still permissive: Forge can list users directly, every relationship edge starts open, and a user can read or affect another user's linked records when the route explicitly asks for them. Use `forge_get_user_directory` when owner identity or cross-user access matters. Strategies can also be locked into a contract with `isLocked`; once locked, do not mutate the graph or target structure unless the user explicitly wants the strategy unlocked first. The model should use the real entity names, not vague substitutes. Say `project`, not “initiative”. Say `behavior_pattern`, not “theme”. Say `trigger_report`, not “incident note”.
63
63
  Habits are a first-class recurring entity in the planning side.
64
64
  NEGATIVE HABIT CHECK-IN RULE: for a `negative` habit, the correct aligned/resisted outcome is `missed`. `missed` means the bad habit was resisted, the user stayed aligned, and the habit should award its XP bonus.
65
65
 
@@ -74,9 +74,9 @@ Preferences rule:
74
74
  Wiki rule:
75
75
 
76
76
  - Treat the Wiki as the canonical long-form memory surface, not as a loose note dump.
77
- - Use the wiki tools when the user wants file-first reference pages, backlink-aware recall, ingest from a URL or local file, or wiki maintenance work such as unresolved-link cleanup.
77
+ - Use the wiki tools when the user wants SQLite-backed reference pages, backlink-aware recall, ingest from a URL or local file, or wiki maintenance work such as unresolved-link cleanup.
78
78
  - `forge_ingest_wiki_source` now queues the ingest as background work; use the Forge UI handoff when the user wants to review or keep only selected wiki/entity candidates after the ingest finishes.
79
- - Keep evidence notes and wiki pages conceptually distinct: evidence notes are linked operating records, while wiki pages are the curated memory vault.
79
+ - Keep evidence notes and wiki pages conceptually distinct: evidence notes are linked operating records, while wiki pages are curated long-form memory.
80
80
 
81
81
  Wiki navigation and search rule:
82
82
 
@@ -90,7 +90,7 @@ Wiki navigation and search rule:
90
90
  - Use `forge_search_wiki` as the default wiki recall tool. It is the main route for people, conversations, concepts, and exact page lookup.
91
91
  - Use `forge_list_wiki_pages` when the user wants to browse structure, inspect a branch, or understand how pages are organized rather than search by phrase.
92
92
  - Use `forge_get_wiki_page` after search yields a likely hit, or when the user already identified the page to open.
93
- - Use `forge_get_wiki_settings` or `forge_get_wiki_health` when the task is about wiki maintenance, indexing, unresolved links, ingest setup, or vault integrity rather than content recall.
93
+ - Use `forge_get_wiki_settings` or `forge_get_wiki_health` when the task is about wiki maintenance, indexing, unresolved links, ingest setup, or memory integrity rather than content recall.
94
94
 
95
95
  Health rule:
96
96
 
@@ -353,7 +353,7 @@ Use the batch entity tools for stored records:
353
353
  These tools operate on:
354
354
  `goal`, `project`, `strategy`, `task`, `habit`, `tag`, `note`, `insight`, `calendar_event`, `work_block_template`, `task_timebox`, `psyche_value`, `behavior_pattern`, `behavior`, `belief_entry`, `mode_profile`, `mode_guide_session`, `trigger_report`, `event_type`, `emotion_definition`, `preference_catalog`, `preference_catalog_item`, `preference_context`, `preference_item`, `questionnaire_instrument`, `sleep_session`, `workout_session`
355
355
 
356
- Use the wiki tools for file-first memory work:
356
+ Use the wiki tools for SQLite-backed memory work:
357
357
  `forge_get_wiki_settings`, `forge_list_wiki_pages`, `forge_get_wiki_page`, `forge_search_wiki`, `forge_upsert_wiki_page`, `forge_get_wiki_health`, `forge_sync_wiki_vault`, `forge_reindex_wiki_embeddings`, `forge_ingest_wiki_source`
358
358
 
359
359
  Use the health tools for review and reflective enrichment, not as the default CRUD architecture:
@@ -63,6 +63,11 @@ Forge correctly, and gather only the structure that still matters.
63
63
  and then act.
64
64
  - Once the route family is clear, say it plainly enough that another agent could follow
65
65
  the same path without guessing.
66
+ - For updates, start with the smallest thing that now feels wrong, newly true, or
67
+ newly visible. Do not make the user retell the whole record unless the change is
68
+ genuinely structural.
69
+ - For review requests, ask what practical question they want the read to answer before
70
+ you ask for more scope.
66
71
  - For meaning-bearing updates, especially in Psyche-adjacent work, briefly say what
67
72
  feels newly true before you ask for the one structural detail that still changes the
68
73
  save.
@@ -222,6 +227,31 @@ When you are about to save:
222
227
  enough or needs one correction
223
228
  - if the user confirms it, stop asking and save
224
229
 
230
+ ## Update And Review Shortcuts
231
+
232
+ Use these when the user is correcting, reviewing, or tightening something that already
233
+ exists.
234
+
235
+ - When the user already gave the correction in usable language, reflect what still
236
+ seems true, then ask only for the one thing that no longer fits.
237
+ - A good narrow update line is:
238
+ "I can stay narrow here. What is the one thing that no longer fits?"
239
+ - When the user is revising placement, timing, or ownership rather than meaning, do
240
+ not reopen the whole story. Confirm only the parent, interval, owner, or route scope
241
+ that changes the write.
242
+ - When the record is abstract or reusable and the user wants an update, ask what
243
+ future decision, comparison, or retrieval moment got muddy with the old wording.
244
+ - When the user wants review rather than mutation, ask what answer they need from the
245
+ read:
246
+ what this would help them decide later is often the clearest scope signal.
247
+ - For specialized surfaces, ask what exact saved object, span, weekday, flow, run, or
248
+ node the user wants to check before you ask why it matters.
249
+ - If the next answer would not change the route, wording, timing, links, or useful
250
+ interpretation, stop asking and act.
251
+ - Close cleanly:
252
+ once the user says the wording or route lands, summarize once and move to the read
253
+ or write.
254
+
225
255
  When an adjacent record becomes visible:
226
256
 
227
257
  - name it gently and ask whether it should be linked now, saved separately later, or
@@ -339,8 +369,10 @@ Connect:
339
369
  move to the save.
340
370
  - Prefer "what I have now is..." or "what seems clear now is..." over a cold final
341
371
  field check.
372
+ - If the user already gave usable wording, do not ask them to rename it for style.
342
373
  - If the user gives a correction, revise the working formulation once and close again
343
374
  instead of reopening the whole intake.
375
+ - If the next answer would not change the entity type, route, wording, timing, or useful links, stop asking and act.
344
376
 
345
377
  ## Question design rules
346
378
 
@@ -389,6 +421,15 @@ Connect:
389
421
  saved object, timeframe, or route family, not reopen the whole meaning-making arc.
390
422
  - When the user already gave the correction in usable language, prefer "what still
391
423
  needs deciding is..." over asking them to restate the whole situation.
424
+ - The opening question should help the user understand what they are actually trying
425
+ to save, decide, review, or change, not make them perform the schema out loud.
426
+ - For review or correction work, do not slip back into a create-style opener once the
427
+ saved object is already known.
428
+ - Once a specialized-surface lane is clear, speak in route-relevant nouns such as
429
+ timeline, overlay, weekday template, published output, run detail, or node result
430
+ instead of generic "record" language.
431
+ - If the user is emotionally loaded but the record is still non-Psyche, reflect the
432
+ lived stake once and then return to the one operational question that still matters.
392
433
 
393
434
  ## Ready-to-save check
394
435
 
@@ -421,6 +462,10 @@ Use this when the user is updating an existing record rather than creating a new
421
462
  If the current title or shape may no longer fit, offer one revised formulation yourself
422
463
  before asking the user to rewrite it from scratch.
423
464
 
465
+ If the user already named the exact correction in usable language, do not ask a broad
466
+ review question again. Confirm only the missing scope, timing, or route-selecting
467
+ detail, then act.
468
+
424
469
  ## Update-first openers
425
470
 
426
471
  Use these when the user is correcting or revising something that already exists.
@@ -1146,6 +1191,8 @@ Direct action rules:
1146
1191
  instead of treating it as a one-off right-now feeling.
1147
1192
  - If the user is describing how one weekday should usually feel, update that weekday
1148
1193
  template instead of editing the profile.
1194
+ - If the user says something like "I always dip on Tuesdays after lunch", treat that
1195
+ as a weekday-template edit, not as a one-off fatigue signal.
1149
1196
  - If the user is describing right-now depletion or recovery, post a fatigue signal and
1150
1197
  then read the overview back if they want to see the updated picture.
1151
1198
  - After a profile or weekday-template change, read the overview back when the user is
@@ -1223,6 +1270,8 @@ Direct action rules:
1223
1270
  - If the user wants to debug one failed execution, narrow whether they need the run
1224
1271
  detail, one node result, the latest node output, or the published output before you
1225
1272
  ask for flow changes.
1273
+ - If the user only wants a published output, latest node output, or run detail, do not
1274
+ reopen a flow-edit intake before reading that artifact.
1226
1275
  - If the user wants one node's latest successful output, do not browse old runs first
1227
1276
  unless they explicitly want historical debugging.
1228
1277
  - If the user wants to understand what inputs a flow can accept before editing or
@@ -53,6 +53,8 @@ Forge without turning the conversation into a worksheet.
53
53
  naming, challenging, or solution-finding.
54
54
  - Your first job is not interpretation. It is to make the moment feel graspable enough
55
55
  that the user can stay with it and describe it.
56
+ - The next question should help the user feel less alone with the experience and more
57
+ able to name it, not more examined.
56
58
  - Before you ask for change, naming, or repair, usually ask what the experience is
57
59
  trying to protect, prevent, or hold onto.
58
60
  - The warmth should come from accuracy and steadiness, not from extra softness,
@@ -70,6 +72,10 @@ Forge without turning the conversation into a worksheet.
70
72
  container first and hold the others lightly until the user wants to map them.
71
73
  - When the user has said enough for an accurate working formulation, stop deepening and
72
74
  help them name it cleanly.
75
+ - For Psyche updates, begin with the smallest part of the old wording that no longer
76
+ fits instead of reopening the whole formulation immediately.
77
+ - Do not reopen the full origin story when the update is really about one changed
78
+ meaning, one newly visible protection, or one new sentence the user can already say.
73
79
 
74
80
  ## First reflection menu
75
81
 
@@ -191,6 +197,23 @@ opening:
191
197
  - one missing-detail question
192
198
  - then move toward the write instead of forcing exploration
193
199
 
200
+ ## Update micro-openers
201
+
202
+ Use these when the user is revising an existing Psyche record and the tone should stay
203
+ therapist-like without becoming expansive again.
204
+
205
+ - "Something about the old wording no longer holds the whole experience. What felt
206
+ different in the moment that made that visible?"
207
+ - "The old name was trying to protect something real. What part of the recent episode
208
+ made it feel too small or off?"
209
+ - "It sounds like the same pain, but not quite the same meaning. What changed in what
210
+ it started to say?"
211
+ - If the user already gave the new sentence in usable language, reflect it once, ask
212
+ what part of the old wording it replaces, and then save.
213
+ - If the user wants review rather than storage, ask whether they need clearer
214
+ language, better understanding, or next-step help before you reopen the whole
215
+ formulation.
216
+
194
217
  ## Therapeutic turn shapes
195
218
 
196
219
  Keep the pacing human and intentional.
@@ -302,6 +325,9 @@ Another strong shape when the user is getting abstract:
302
325
  - "So the painful part seems to be less the event itself and more what it starts to
303
326
  mean about you. What does it seem to prove in that moment?"
304
327
 
328
+ Use that rhythm to contain before you interpret. The user should be able to feel what
329
+ you understood before they have to answer the next deeper question.
330
+
305
331
  ## Formulation rules
306
332
 
307
333
  - Do not front-load a finished case formulation.
@@ -309,6 +335,8 @@ Another strong shape when the user is getting abstract:
309
335
  the user has answered at least one real exploratory question.
310
336
  - Do not ask for evidence, alternative beliefs, or repair plans before the user has had
311
337
  a fair chance to feel that the original experience was captured accurately.
338
+ - If the moment is still hot, name what feels most painful, dangerous, or protective
339
+ before you ask for belief, mode, or pattern labels.
312
340
  - Do not make the user prove the experience before you have helped them feel that you
313
341
  understood it.
314
342
  - Help the user recognize the experience before you help them improve it.
@@ -386,6 +414,10 @@ If the entity is not yet clear:
386
414
  - If the user already gives the new sentence in usable language, revise the wording
387
415
  once and save instead of reopening evidence, origin, or repair just because those
388
416
  lanes are available.
417
+ - Do not open a second broad origin story just because the update touched old pain.
418
+ If the wording is already clear enough, refine it once and save.
419
+ - If the formulation already lands and the next answer would not change the wording,
420
+ links, or immediate write, stop asking and save.
389
421
  - If another belief, value, pattern, mode, or note becomes visible, name it gently but
390
422
  do not switch containers unless the user wants to.
391
423