forge-openclaw-plugin 0.2.60 → 0.2.61
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/README.md +93 -46
- package/dist/assets/{board-B1V3M__K.js → board-DThHV1D8.js} +1 -1
- package/dist/assets/index-7gvVCqnV.css +1 -0
- package/dist/assets/index-_Cn6Prym.js +90 -0
- package/dist/assets/{motion-CltSTItx.js → motion-BtTJtHCw.js} +1 -1
- package/dist/assets/{table-B-VrSFx8.js → table-Bnw6pcwN.js} +1 -1
- package/dist/assets/{ui-DUqM4jkt.js → ui-CnVxFkj0.js} +1 -1
- package/dist/assets/{vendor-C0otBhgu.js → vendor-BgZ3YrRd.js} +212 -207
- package/dist/gamification-previews/dark-fantasy-item-trophy-tasks-anvil-marathon.webp +0 -0
- package/dist/gamification-previews/dark-fantasy-item-trophy-xp-levels-the-first-heat.webp +0 -0
- package/dist/gamification-previews/dark-fantasy-item-unlock-streaks-molten-crown-fire.webp +0 -0
- package/dist/gamification-previews/dark-fantasy-mascot.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-item-trophy-tasks-anvil-marathon.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-item-trophy-xp-levels-the-first-heat.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-item-unlock-streaks-molten-crown-fire.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-mascot.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-item-trophy-tasks-anvil-marathon.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-item-trophy-xp-levels-the-first-heat.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-item-unlock-streaks-molten-crown-fire.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-mascot.webp +0 -0
- package/dist/index.html +7 -7
- package/dist/openclaw/parity.js +27 -0
- package/dist/openclaw/plugin-entry-shared.js +2 -2
- package/dist/openclaw/plugin-sdk-types.d.ts +2 -1
- package/dist/openclaw/routes.d.ts +4 -0
- package/dist/openclaw/routes.js +112 -3
- package/dist/openclaw/tools.js +32 -4
- package/dist/server/server/migrations/059_data_backup_retention.sql +2 -0
- package/dist/server/server/src/app.js +125 -43
- package/dist/server/server/src/data-management-types.js +2 -0
- package/dist/server/server/src/health.js +40 -0
- package/dist/server/server/src/openapi.js +398 -7
- package/dist/server/server/src/repositories/rewards.js +60 -0
- package/dist/server/server/src/services/data-management.js +32 -2
- package/dist/server/server/src/services/doctor.js +762 -0
- package/dist/server/server/src/services/gamification.js +75 -3
- package/dist/server/src/lib/api.js +9 -0
- package/dist/server/src/lib/gamification-catalog.js +1 -1
- package/openclaw.plugin.json +85 -3
- package/package.json +8 -4
- package/server/migrations/059_data_backup_retention.sql +2 -0
- package/skills/forge-openclaw/SKILL.md +38 -19
- package/skills/forge-openclaw/entity_conversation_playbooks.md +66 -8
- package/skills/forge-openclaw/psyche_entity_playbooks.md +23 -0
- package/dist/assets/index-BwKAPo98.css +0 -1
- package/dist/assets/index-Dy7c-dRY.js +0 -90
|
@@ -1,10 +1,41 @@
|
|
|
1
1
|
import { getDatabase } from "../db.js";
|
|
2
2
|
import { enqueueGamificationCelebration, getGamificationEquipment, insertGamificationUnlock, listGamificationDailyActivity, listGamificationUnlocks, listUnseenGamificationCelebrations, replaceGamificationDailyActivity, upsertGamificationEquipment } from "../repositories/gamification.js";
|
|
3
|
-
import { getDailyAmbientXp, listRewardRules } from "../repositories/rewards.js";
|
|
3
|
+
import { getDailyAmbientXp, listRewardRules, recordEntityCreationReward } from "../repositories/rewards.js";
|
|
4
4
|
import { getDefaultUser, listUsers, listUsersByIds } from "../repositories/users.js";
|
|
5
5
|
import { GAMIFICATION_CATALOG, GAMIFICATION_STREAK_AWAY_DAY_KEYS, GAMIFICATION_STREAK_POWER_DAY_KEYS } from "../../../src/lib/gamification-catalog.js";
|
|
6
6
|
import { achievementSignalSchema, gamificationCatalogPayloadSchema, gamificationProfileSchema, milestoneRewardSchema, rewardLedgerEventSchema } from "../types.js";
|
|
7
7
|
const XP_CURVE_VERSION = "smith-forge";
|
|
8
|
+
const ENTITY_CREATION_REWARD_SOURCES = [
|
|
9
|
+
{ entityType: "goal", tableName: "goals", titleColumn: "title" },
|
|
10
|
+
{ entityType: "project", tableName: "projects", titleColumn: "title" },
|
|
11
|
+
{ entityType: "strategy", tableName: "strategies", titleColumn: "title" },
|
|
12
|
+
{ entityType: "task", tableName: "tasks", titleColumn: "title" },
|
|
13
|
+
{ entityType: "habit", tableName: "habits", titleColumn: "title" },
|
|
14
|
+
{ entityType: "note", tableName: "notes", titleColumn: "content_plain" },
|
|
15
|
+
{ entityType: "tag", tableName: "tags", titleColumn: "name" },
|
|
16
|
+
{ entityType: "calendar_event", tableName: "calendar_events", titleColumn: "title" },
|
|
17
|
+
{
|
|
18
|
+
entityType: "work_block_template",
|
|
19
|
+
tableName: "work_block_templates",
|
|
20
|
+
titleColumn: "title"
|
|
21
|
+
},
|
|
22
|
+
{ entityType: "task_timebox", tableName: "task_timeboxes", titleColumn: "title" },
|
|
23
|
+
{
|
|
24
|
+
entityType: "questionnaire_instrument",
|
|
25
|
+
tableName: "questionnaire_instruments",
|
|
26
|
+
titleColumn: "title"
|
|
27
|
+
},
|
|
28
|
+
{ entityType: "psyche_value", tableName: "psyche_values", titleColumn: "title" },
|
|
29
|
+
{
|
|
30
|
+
entityType: "behavior_pattern",
|
|
31
|
+
tableName: "behavior_patterns",
|
|
32
|
+
titleColumn: "title"
|
|
33
|
+
},
|
|
34
|
+
{ entityType: "behavior", tableName: "psyche_behaviors", titleColumn: "title" },
|
|
35
|
+
{ entityType: "belief_entry", tableName: "belief_entries", titleColumn: "statement" },
|
|
36
|
+
{ entityType: "mode_profile", tableName: "mode_profiles", titleColumn: "title" },
|
|
37
|
+
{ entityType: "trigger_report", tableName: "trigger_reports", titleColumn: "title" }
|
|
38
|
+
];
|
|
8
39
|
function startOfWeek(date) {
|
|
9
40
|
const clone = new Date(date);
|
|
10
41
|
const day = clone.getDay();
|
|
@@ -209,6 +240,42 @@ function loadScopedRewardEvents(scope) {
|
|
|
209
240
|
? true
|
|
210
241
|
: event.ownerUserId !== null && scopeUserIds.has(event.ownerUserId));
|
|
211
242
|
}
|
|
243
|
+
function syncEntityCreationRewards(scope) {
|
|
244
|
+
const database = getDatabase();
|
|
245
|
+
const scopeUserIds = [...new Set(scope.userIds)];
|
|
246
|
+
const scopePlaceholders = scopeUserIds.map(() => "?").join(", ");
|
|
247
|
+
for (const source of ENTITY_CREATION_REWARD_SOURCES) {
|
|
248
|
+
const scopedWhere = scopeUserIds.length > 0
|
|
249
|
+
? `WHERE (
|
|
250
|
+
entity_owners.user_id IN (${scopePlaceholders})
|
|
251
|
+
OR (entity_owners.user_id IS NULL AND ? IS NOT NULL)
|
|
252
|
+
)`
|
|
253
|
+
: "";
|
|
254
|
+
const params = scopeUserIds.length > 0
|
|
255
|
+
? [source.entityType, ...scopeUserIds, scopeUserIds[0] ?? null]
|
|
256
|
+
: [source.entityType];
|
|
257
|
+
const rows = database
|
|
258
|
+
.prepare(`SELECT
|
|
259
|
+
${source.tableName}.id AS id,
|
|
260
|
+
${source.tableName}.${source.titleColumn} AS title,
|
|
261
|
+
${source.tableName}.created_at AS created_at
|
|
262
|
+
FROM ${source.tableName}
|
|
263
|
+
LEFT JOIN entity_owners
|
|
264
|
+
ON entity_owners.entity_type = ?
|
|
265
|
+
AND entity_owners.entity_id = ${source.tableName}.id
|
|
266
|
+
${scopedWhere}`)
|
|
267
|
+
.all(...params);
|
|
268
|
+
for (const row of rows) {
|
|
269
|
+
recordEntityCreationReward({
|
|
270
|
+
entityType: source.entityType,
|
|
271
|
+
entityId: row.id,
|
|
272
|
+
title: row.title,
|
|
273
|
+
source: "system",
|
|
274
|
+
createdAt: row.created_at
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
212
279
|
function isQualifyingStreakReward(event) {
|
|
213
280
|
return (event.deltaXp > 0 &&
|
|
214
281
|
event.reversedByRewardId === null &&
|
|
@@ -245,8 +312,9 @@ function syncDailyActivity(userId, scopedRewards, timezone) {
|
|
|
245
312
|
}
|
|
246
313
|
function calculateStreakFromActivity(activeDateKeys, now, timezone) {
|
|
247
314
|
const today = dateKeyInTimezone(now, timezone);
|
|
315
|
+
const yesterday = subtractDaysFromDateKey(today, 1);
|
|
248
316
|
let streak = 0;
|
|
249
|
-
let cursor = today;
|
|
317
|
+
let cursor = activeDateKeys.has(today) ? today : yesterday;
|
|
250
318
|
while (activeDateKeys.has(cursor)) {
|
|
251
319
|
streak += 1;
|
|
252
320
|
cursor = subtractDaysFromDateKey(cursor, 1);
|
|
@@ -297,8 +365,11 @@ function calculateMissedDays(activeDateKeys, now, timezone) {
|
|
|
297
365
|
if (!latest || latest === today) {
|
|
298
366
|
return { missedDays: 0, lastActiveDateKey: latest };
|
|
299
367
|
}
|
|
368
|
+
if (latest === subtractDaysFromDateKey(today, 1)) {
|
|
369
|
+
return { missedDays: 0, lastActiveDateKey: latest };
|
|
370
|
+
}
|
|
300
371
|
return {
|
|
301
|
-
missedDays: Math.max(0, daysBetweenDateKeys(latest, today)),
|
|
372
|
+
missedDays: Math.max(0, daysBetweenDateKeys(latest, today) - 1),
|
|
302
373
|
lastActiveDateKey: latest
|
|
303
374
|
};
|
|
304
375
|
}
|
|
@@ -746,6 +817,7 @@ function syncCatalog(input) {
|
|
|
746
817
|
function buildGamificationState(goals, tasks, habits, options = {}) {
|
|
747
818
|
const now = options.now ?? new Date();
|
|
748
819
|
const scope = resolveGamificationScope(options.userIds);
|
|
820
|
+
syncEntityCreationRewards(scope);
|
|
749
821
|
const scopedRewards = loadScopedRewardEvents(scope);
|
|
750
822
|
const timezone = resolveTimezone();
|
|
751
823
|
const primaryUserId = scope.userIds[0] ?? "aggregate";
|
|
@@ -1515,6 +1515,15 @@ export function getOperatorOverview() {
|
|
|
1515
1515
|
export function getSettings() {
|
|
1516
1516
|
return request("/api/v1/settings");
|
|
1517
1517
|
}
|
|
1518
|
+
export function getForgeDoctor() {
|
|
1519
|
+
return request("/api/v1/doctor");
|
|
1520
|
+
}
|
|
1521
|
+
export function applyForgeDoctorFixes(input) {
|
|
1522
|
+
return request("/api/v1/doctor/fixes", {
|
|
1523
|
+
method: "POST",
|
|
1524
|
+
body: JSON.stringify(input)
|
|
1525
|
+
});
|
|
1526
|
+
}
|
|
1518
1527
|
export function saveAiModelConnection(input) {
|
|
1519
1528
|
return request("/api/v1/settings/models/connections", {
|
|
1520
1529
|
method: "POST",
|
|
@@ -222,7 +222,7 @@ const PSYCHE_TROPHIES = [
|
|
|
222
222
|
trophy("psyche", "Value Blade", allOf(metric("psycheValueCount", 10), metric("goalLinkedTaskCompletionCount", 100)), "Create 10 values and complete 100 goal-linked tasks.", "Values and work started cutting in the same direction."),
|
|
223
223
|
trophy("psyche", "Shadow Temper", allOf(metric("modeProfileCount", 12), metric("triggerReportRichCount", 50)), "Create 12 modes and 50 rich trigger reports.", "Shadow material became usable steel."),
|
|
224
224
|
trophy("psyche", "Inner Forge", allOf(metric("psycheValueCount", 12), metric("behaviorPatternCount", 25), metric("beliefFlexibleAlternativeCount", 30)), "Create 12 values, 25 patterns, and 30 flexible beliefs.", "A full inner forge takes shape."),
|
|
225
|
-
trophy("psyche", "Schema Bell", metric("questionnaireRunCount",
|
|
225
|
+
trophy("psyche", "Schema Bell", metric("questionnaireRunCount", 40), "Complete 40 questionnaire runs.", "Structured self-observation rang the bell repeatedly."),
|
|
226
226
|
trophy("psyche", "Mode Guide", metric("modeGuideSessionCount", 5), "Complete 5 mode guide sessions.", "Guided mode work became an actual practice."),
|
|
227
227
|
trophy("psyche", "Repair Script", metric("behaviorCount", 10), "Create 10 Psyche behaviors.", "Behaviors now carry repair plans, not just names."),
|
|
228
228
|
trophy("psyche", "Flexible Self", metric("beliefFlexibleAlternativeCount", 50), "Create 50 beliefs with flexible alternatives.", "A trophy for not letting old beliefs remain iron cages."),
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,10 +2,92 @@
|
|
|
2
2
|
"id": "forge-openclaw-plugin",
|
|
3
3
|
"name": "Forge",
|
|
4
4
|
"description": "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.",
|
|
5
|
-
"version": "0.2.
|
|
5
|
+
"version": "0.2.61",
|
|
6
|
+
"activation": {
|
|
7
|
+
"onStartup": true,
|
|
8
|
+
"onCapabilities": [
|
|
9
|
+
"tool"
|
|
10
|
+
],
|
|
11
|
+
"onCommands": [
|
|
12
|
+
"forge"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
6
15
|
"skills": [
|
|
7
16
|
"./skills"
|
|
8
17
|
],
|
|
18
|
+
"commandAliases": [
|
|
19
|
+
{
|
|
20
|
+
"name": "forge"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"contracts": {
|
|
24
|
+
"tools": [
|
|
25
|
+
"forge_adjust_work_minutes",
|
|
26
|
+
"forge_apply_doctor_fix",
|
|
27
|
+
"forge_call_life_force_route",
|
|
28
|
+
"forge_call_movement_route",
|
|
29
|
+
"forge_call_workbench_route",
|
|
30
|
+
"forge_clone_questionnaire",
|
|
31
|
+
"forge_complete_questionnaire_run",
|
|
32
|
+
"forge_complete_task_run",
|
|
33
|
+
"forge_connect_calendar_provider",
|
|
34
|
+
"forge_create_entities",
|
|
35
|
+
"forge_create_task_timebox",
|
|
36
|
+
"forge_create_work_block_template",
|
|
37
|
+
"forge_delete_entities",
|
|
38
|
+
"forge_enqueue_preferences_item_from_entity",
|
|
39
|
+
"forge_ensure_questionnaire_draft",
|
|
40
|
+
"forge_focus_task_run",
|
|
41
|
+
"forge_get_agent_onboarding",
|
|
42
|
+
"forge_get_calendar_overview",
|
|
43
|
+
"forge_get_current_work",
|
|
44
|
+
"forge_get_doctor",
|
|
45
|
+
"forge_get_operator_context",
|
|
46
|
+
"forge_get_operator_overview",
|
|
47
|
+
"forge_get_preferences_workspace",
|
|
48
|
+
"forge_get_psyche_overview",
|
|
49
|
+
"forge_get_questionnaire",
|
|
50
|
+
"forge_get_questionnaire_run",
|
|
51
|
+
"forge_get_self_observation_calendar",
|
|
52
|
+
"forge_get_sleep_overview",
|
|
53
|
+
"forge_get_sports_overview",
|
|
54
|
+
"forge_get_ui_entrypoint",
|
|
55
|
+
"forge_get_user_directory",
|
|
56
|
+
"forge_get_weekly_review",
|
|
57
|
+
"forge_get_wiki_health",
|
|
58
|
+
"forge_get_wiki_page",
|
|
59
|
+
"forge_get_wiki_settings",
|
|
60
|
+
"forge_get_xp_metrics",
|
|
61
|
+
"forge_grant_reward_bonus",
|
|
62
|
+
"forge_heartbeat_task_run",
|
|
63
|
+
"forge_ingest_wiki_source",
|
|
64
|
+
"forge_list_questionnaires",
|
|
65
|
+
"forge_list_wiki_pages",
|
|
66
|
+
"forge_log_work",
|
|
67
|
+
"forge_merge_preferences_contexts",
|
|
68
|
+
"forge_post_insight",
|
|
69
|
+
"forge_publish_questionnaire_draft",
|
|
70
|
+
"forge_recommend_task_timeboxes",
|
|
71
|
+
"forge_reindex_wiki_embeddings",
|
|
72
|
+
"forge_release_task_run",
|
|
73
|
+
"forge_restore_entities",
|
|
74
|
+
"forge_search_entities",
|
|
75
|
+
"forge_search_wiki",
|
|
76
|
+
"forge_start_preferences_game",
|
|
77
|
+
"forge_start_questionnaire_run",
|
|
78
|
+
"forge_start_task_run",
|
|
79
|
+
"forge_submit_preferences_judgment",
|
|
80
|
+
"forge_submit_preferences_signal",
|
|
81
|
+
"forge_sync_calendar_connection",
|
|
82
|
+
"forge_sync_wiki_vault",
|
|
83
|
+
"forge_update_entities",
|
|
84
|
+
"forge_update_preferences_score",
|
|
85
|
+
"forge_update_questionnaire_run",
|
|
86
|
+
"forge_update_sleep_session",
|
|
87
|
+
"forge_update_workout_session",
|
|
88
|
+
"forge_upsert_wiki_page"
|
|
89
|
+
]
|
|
90
|
+
},
|
|
9
91
|
"uiHints": {
|
|
10
92
|
"origin": {
|
|
11
93
|
"label": "Forge Origin",
|
|
@@ -19,7 +101,7 @@
|
|
|
19
101
|
},
|
|
20
102
|
"dataRoot": {
|
|
21
103
|
"label": "Forge Data Root",
|
|
22
|
-
"help": "
|
|
104
|
+
"help": "Optional absolute folder path for Forge data. Defaults to ~/.forge. When set, Forge stores forge.sqlite directly in this folder; use the same value across adapters that should share one database.",
|
|
23
105
|
"placeholder": "~/.forge",
|
|
24
106
|
"advanced": true
|
|
25
107
|
},
|
|
@@ -63,7 +145,7 @@
|
|
|
63
145
|
"dataRoot": {
|
|
64
146
|
"type": "string",
|
|
65
147
|
"default": "~/.forge",
|
|
66
|
-
"description": "Absolute path for the shared Forge data root. Defaults to ~/.forge
|
|
148
|
+
"description": "Absolute path for the shared Forge data root. Defaults to ~/.forge. Explicit values override that default; use the same value across local adapters that should share one database."
|
|
67
149
|
},
|
|
68
150
|
"apiToken": {
|
|
69
151
|
"type": "string",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forge-openclaw-plugin",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.61",
|
|
4
4
|
"description": "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,10 +38,13 @@
|
|
|
38
38
|
"openclaw": {
|
|
39
39
|
"extensions": [
|
|
40
40
|
"./dist/openclaw/index.js"
|
|
41
|
-
]
|
|
41
|
+
],
|
|
42
|
+
"install": {
|
|
43
|
+
"minHostVersion": ">=2026.5.4"
|
|
44
|
+
}
|
|
42
45
|
},
|
|
43
46
|
"peerDependencies": {
|
|
44
|
-
"openclaw": "2026.4
|
|
47
|
+
"openclaw": "2026.5.4"
|
|
45
48
|
},
|
|
46
49
|
"dependencies": {
|
|
47
50
|
"@dnd-kit/core": "^6.3.1",
|
|
@@ -97,10 +100,11 @@
|
|
|
97
100
|
"overrides": {
|
|
98
101
|
"@aws-sdk/xml-builder": "^3.972.19",
|
|
99
102
|
"basic-ftp": "^5.3.0",
|
|
100
|
-
"axios": "^1.
|
|
103
|
+
"axios": "^1.16.0",
|
|
101
104
|
"fast-xml-parser": "^5.7.1",
|
|
102
105
|
"follow-redirects": "^1.16.0",
|
|
103
106
|
"hono": "4.12.14",
|
|
107
|
+
"ip-address": "^10.2.0",
|
|
104
108
|
"uuid": "^14.0.0"
|
|
105
109
|
},
|
|
106
110
|
"scripts": {
|
|
@@ -87,6 +87,16 @@ guessing.
|
|
|
87
87
|
`forge_call_life_force_route`, or `forge_call_workbench_route`, use those
|
|
88
88
|
route-key tools after the conversation has selected the lane; otherwise use the
|
|
89
89
|
exact `/api/v1/*` route or OpenClaw `/forge/v1/*` mirror published in onboarding.
|
|
90
|
+
Life Force may be keyed as `lifeForce` and as the entity-style alias `life_force`;
|
|
91
|
+
both point to the same `/api/v1/life-force/*` route family.
|
|
92
|
+
- The specialized route-key tool schemas include the exact route-key to method/path
|
|
93
|
+
map. When a route key's exact path contains placeholders such as `:id`,
|
|
94
|
+
`:weekday`, `:runId`, or `:nodeId`, pass those values in `pathParams` using the
|
|
95
|
+
placeholder names exactly. Do not place IDs inside `routeKey`, invent a raw route
|
|
96
|
+
string, or ask the user to choose an endpoint when the lane already selects one. If
|
|
97
|
+
that schema and live onboarding disagree, trust the live onboarding for the current
|
|
98
|
+
call and treat the disagreement as a Forge contract bug to fix, not as a reason to
|
|
99
|
+
guess a nearby route.
|
|
90
100
|
|
|
91
101
|
Preferences rule:
|
|
92
102
|
|
|
@@ -156,11 +166,15 @@ Entity conversation rule:
|
|
|
156
166
|
|
|
157
167
|
Forge data location rule:
|
|
158
168
|
|
|
159
|
-
-
|
|
160
|
-
- the
|
|
161
|
-
-
|
|
162
|
-
-
|
|
163
|
-
-
|
|
169
|
+
- never answer from a generic default. First check the actual configured `dataRoot` and, when possible, the live runtime file handle.
|
|
170
|
+
- the default local Forge data root is `~/.forge`, so the default database is `~/.forge/forge.sqlite`.
|
|
171
|
+
- the user can override that default. Determine the effective storage root from the active adapter config or runtime environment first: OpenClaw `plugins.entries["forge-openclaw-plugin"].config.dataRoot`, Hermes `~/.hermes/forge/config.json.dataRoot`, `FORGE_DATA_ROOT`, or the runtime's reported storage path.
|
|
172
|
+
- when `dataRoot` is set, Forge stores `forge.sqlite` directly inside that folder. That explicit setting overrides generic defaults.
|
|
173
|
+
- when a Forge server is running locally, verify the actual open database with a process/file-handle check such as `lsof -p <forge-pid> | rg 'forge.sqlite|forge.json'`.
|
|
174
|
+
- treat plugin extension folders, package-local `data/`, or adapter-local data folders as only possible candidates until config or live process evidence proves they are active.
|
|
175
|
+
- if the user wants to choose the data folder or configure backups from the UI, point them to Forge `Settings -> Data`. That page shows the live data folder, can move current data or adopt an existing Forge data folder, creates manual backups, enables recurring automatic backups, and lets the user choose how many days of automatic backups to keep.
|
|
176
|
+
- before changing data roots, restoring, or merging data, create backups of every candidate Forge database plus OpenClaw/Hermes config files. Do not merge side databases unless an ID/content-level audit proves relevant user data is missing from the selected active database.
|
|
177
|
+
- if the user asks where Forge data is stored, state both the configured path and the live verified database path, or say that the live path has not yet been verified.
|
|
164
178
|
|
|
165
179
|
Psyche interview rule:
|
|
166
180
|
|
|
@@ -251,13 +265,16 @@ Use these exact entity meanings when deciding what the user is describing.
|
|
|
251
265
|
|
|
252
266
|
`emotion_definition` is a reusable emotion entry, such as fear, shame, anger, grief, relief, or disgust.
|
|
253
267
|
|
|
254
|
-
|
|
268
|
+
Minimum-field checkpoint, not a question script: use this only after the
|
|
269
|
+
conversation has enough shape to save or update something. Do not ask every listed
|
|
270
|
+
item. Choose the single missing lane that affects the write, and stop when the
|
|
271
|
+
record is clear enough to persist.
|
|
255
272
|
|
|
256
273
|
`goal`
|
|
257
274
|
Use for a meaningful direction over time.
|
|
258
275
|
Minimum field: `title`
|
|
259
276
|
Usually useful: `description`, `horizon`, `status`
|
|
260
|
-
|
|
277
|
+
Only ask if missing or unclear:
|
|
261
278
|
|
|
262
279
|
1. What should this goal be called?
|
|
263
280
|
2. Why does it matter to you?
|
|
@@ -267,7 +284,7 @@ Ask:
|
|
|
267
284
|
Use for a bounded workstream under a goal.
|
|
268
285
|
Minimum field: `title`
|
|
269
286
|
Usually useful: `goalId`, `description`, `status`
|
|
270
|
-
|
|
287
|
+
Only ask if missing or unclear:
|
|
271
288
|
|
|
272
289
|
1. What should this project be called?
|
|
273
290
|
2. Which goal does it support?
|
|
@@ -277,7 +294,7 @@ Ask:
|
|
|
277
294
|
Use for one concrete action or deliverable.
|
|
278
295
|
Minimum field: `title`
|
|
279
296
|
Usually useful: `projectId`, `goalId`, `priority`, `dueDate`, `status`, `owner`
|
|
280
|
-
|
|
297
|
+
Only ask if missing or unclear:
|
|
281
298
|
|
|
282
299
|
1. What is the task in one concrete sentence?
|
|
283
300
|
2. Should it live under an existing goal or project?
|
|
@@ -294,7 +311,7 @@ CRITICAL NEGATIVE-HABIT CHECK-IN RULE:
|
|
|
294
311
|
- Do not treat `missed` on a `negative` habit as failure. In this case, `missed` is the successful outcome.
|
|
295
312
|
- In OpenClaw, official habit outcome logging should go through `forge_update_entities` on `entityType: "habit"` with `patch: { checkIn: { status, dateKey?, note?, description? } }`.
|
|
296
313
|
- Do not bypass the shared tool model with raw habit routes when the batch entity update already covers the write cleanly.
|
|
297
|
-
|
|
314
|
+
Only ask if missing or unclear:
|
|
298
315
|
|
|
299
316
|
1. What is the recurring behavior in one concrete sentence?
|
|
300
317
|
2. Is doing it good (`positive`) or a slip (`negative`)?
|
|
@@ -309,7 +326,7 @@ Ask only what is needed to start the run, such as the task, the actor, and wheth
|
|
|
309
326
|
Use for a value or committed direction.
|
|
310
327
|
Minimum field: `title`
|
|
311
328
|
Usually useful: `description`, `valuedDirection`, `whyItMatters`, links to goals, projects, or tasks
|
|
312
|
-
|
|
329
|
+
Only ask if missing or unclear:
|
|
313
330
|
|
|
314
331
|
1. What feels deeply important here, and what would you call that value or direction?
|
|
315
332
|
2. If you were living it a little more this week, what would someone actually see?
|
|
@@ -319,7 +336,7 @@ Ask:
|
|
|
319
336
|
Use for a recurring loop across situations.
|
|
320
337
|
Minimum field: `title`
|
|
321
338
|
Usually useful: `description`, `targetBehavior`, `cueContexts`, `shortTermPayoff`, `longTermCost`, `preferredResponse`
|
|
322
|
-
|
|
339
|
+
Only ask if missing or unclear:
|
|
323
340
|
|
|
324
341
|
1. Can we slow this down using one recent example first?
|
|
325
342
|
2. What usually sets the loop off, and what tends to happen in thoughts, feelings, body, and actions next?
|
|
@@ -329,7 +346,7 @@ Ask:
|
|
|
329
346
|
Use for one recurring move or action tendency.
|
|
330
347
|
Minimum fields: `kind`, `title`
|
|
331
348
|
Usually useful: `commonCues`, `urgeStory`, `shortTermPayoff`, `longTermCost`, `replacementMove`, `repairPlan`
|
|
332
|
-
|
|
349
|
+
Only ask if missing or unclear:
|
|
333
350
|
|
|
334
351
|
1. What does this behavior actually look like in plain language?
|
|
335
352
|
2. What cues or urges usually pull you toward it, and what does it do for you in the moment?
|
|
@@ -339,7 +356,7 @@ Ask:
|
|
|
339
356
|
Use for one explicit belief sentence.
|
|
340
357
|
Minimum fields: `statement`, `beliefType`
|
|
341
358
|
Usually useful: `confidence`, `evidenceFor`, `evidenceAgainst`, `flexibleAlternative`, `originNote`
|
|
342
|
-
|
|
359
|
+
Only ask if missing or unclear:
|
|
343
360
|
|
|
344
361
|
1. If we turn that reaction into one sentence, what does the belief sound like in your own words?
|
|
345
362
|
2. Is it `absolute` or `conditional`, and how true does it feel from 0 to 100?
|
|
@@ -349,7 +366,7 @@ Ask:
|
|
|
349
366
|
Use for a recurring part-state or inner role.
|
|
350
367
|
Minimum fields: `family`, `title`
|
|
351
368
|
Usually useful: `fear`, `burden`, `protectiveJob`, `originContext`, links to patterns, behaviors, and values
|
|
352
|
-
|
|
369
|
+
Only ask if missing or unclear:
|
|
353
370
|
|
|
354
371
|
1. When this part shows up, what is it like from the inside and what should it be called?
|
|
355
372
|
2. What kind of mode is this: `coping`, `child`, `critic_parent`, `healthy_adult`, or `happy_child`?
|
|
@@ -358,7 +375,7 @@ Ask:
|
|
|
358
375
|
`mode_guide_session`
|
|
359
376
|
Use for guided exploration before or alongside a durable mode profile.
|
|
360
377
|
Minimum fields: `summary`, `answers`
|
|
361
|
-
|
|
378
|
+
Only ask if missing or unclear:
|
|
362
379
|
|
|
363
380
|
1. What just happened that brought this part online right now?
|
|
364
381
|
2. If it had a voice, what would it say, fear, or need?
|
|
@@ -368,7 +385,7 @@ Ask:
|
|
|
368
385
|
Use for one specific emotionally important episode.
|
|
369
386
|
Minimum field: `title`
|
|
370
387
|
Usually useful: `eventSituation`, `occurredAt`, `emotions`, `thoughts`, `behaviors`, `consequences`, `nextMoves`, links to values, beliefs, patterns, modes, goals, projects, or tasks
|
|
371
|
-
|
|
388
|
+
Only ask if missing or unclear:
|
|
372
389
|
|
|
373
390
|
1. What happened, as concretely as you can say it?
|
|
374
391
|
2. What emotions were present, how intense were they, and what thoughts or meanings showed up?
|
|
@@ -378,7 +395,7 @@ Ask:
|
|
|
378
395
|
Use for a reusable trigger category.
|
|
379
396
|
Minimum field: `label`
|
|
380
397
|
Usually useful: `description`
|
|
381
|
-
|
|
398
|
+
Only ask if missing or unclear:
|
|
382
399
|
|
|
383
400
|
1. What kind of repeated moment or incident do you want future reports to name the same way?
|
|
384
401
|
2. What would count as inside this category, and what should stay outside it?
|
|
@@ -388,7 +405,7 @@ Ask:
|
|
|
388
405
|
Use for a reusable emotion vocabulary entry.
|
|
389
406
|
Minimum field: `label`
|
|
390
407
|
Usually useful: `description`, `category`
|
|
391
|
-
|
|
408
|
+
Only ask if missing or unclear:
|
|
392
409
|
|
|
393
410
|
1. When this feeling is present, what tells you it is this feeling and not a nearby one?
|
|
394
411
|
2. What would you want a later trigger report to mean when it uses this label?
|
|
@@ -628,6 +645,8 @@ When the user asks which Forge tools are available, list exactly these tools:
|
|
|
628
645
|
`forge_get_operator_overview`
|
|
629
646
|
`forge_get_operator_context`
|
|
630
647
|
`forge_get_agent_onboarding`
|
|
648
|
+
`forge_get_doctor`
|
|
649
|
+
`forge_apply_doctor_fix`
|
|
631
650
|
`forge_call_movement_route`
|
|
632
651
|
`forge_call_life_force_route`
|
|
633
652
|
`forge_call_workbench_route`
|
|
@@ -18,6 +18,12 @@ Forge correctly, and gather only the structure that still matters.
|
|
|
18
18
|
- The first question should usually clarify whether the user is trying to understand,
|
|
19
19
|
preserve, decide, schedule, or change something, not just which field or provider
|
|
20
20
|
they want.
|
|
21
|
+
- Before asking, decide the API posture internally: shared batch entity route,
|
|
22
|
+
specialized CRUD surface, action workflow, or specialized domain route. If that
|
|
23
|
+
posture is unclear, ask the one user-facing question that will choose it.
|
|
24
|
+
- Do not let API uncertainty leak out as vague wording. With the user, ask about the
|
|
25
|
+
real thing: the time window, flow, run, feeling, boundary, owner, or decision that
|
|
26
|
+
would change the action.
|
|
21
27
|
- First identify the user's job when the lane is not already explicit:
|
|
22
28
|
are they trying to add, update, review, compare, navigate, link, or run something?
|
|
23
29
|
- Before every question, decide the one missing thing you are trying to clarify.
|
|
@@ -27,6 +33,9 @@ Forge correctly, and gather only the structure that still matters.
|
|
|
27
33
|
- Prefer one clean question to a stacked sentence with several asks.
|
|
28
34
|
- Reflect briefly when the user gives meaning, ambivalence, or emotionally loaded
|
|
29
35
|
context that matters to the record.
|
|
36
|
+
- Avoid generic reflections such as "that sounds important" unless you name what is
|
|
37
|
+
important in plain language. A useful reflection should make the next question feel
|
|
38
|
+
earned.
|
|
30
39
|
- Especially for goals, habits, notes, and updates, reflect what the user is trying to
|
|
31
40
|
preserve, change, or make true before you ask for structure.
|
|
32
41
|
- For emotionally meaningful non-Psyche records such as goals, habits, notes, and many
|
|
@@ -200,6 +209,9 @@ Use this quick split before the conversation gets too detailed.
|
|
|
200
209
|
`/api/v1/entities/search`, `/api/v1/entities/create`,
|
|
201
210
|
`/api/v1/entities/update`, `/api/v1/entities/delete`, and
|
|
202
211
|
`/api/v1/entities/restore`.
|
|
212
|
+
- Every normal entity section below inherits that batch-route default unless its own
|
|
213
|
+
route note says otherwise. Do not invent one-off entity endpoints for ordinary
|
|
214
|
+
stored records.
|
|
203
215
|
- `wiki_page` and `calendar_connection` are specialized CRUD areas. Use the wiki
|
|
204
216
|
page routes and calendar connection setup or sync routes instead of pretending they
|
|
205
217
|
are simple batch records.
|
|
@@ -216,6 +228,8 @@ Use this quick split before the conversation gets too detailed.
|
|
|
216
228
|
- Once the route posture is clear, keep the questioning focused on the missing detail
|
|
217
229
|
that selects the route or payload. Do not ask route-neutral reflective questions
|
|
218
230
|
after the action path is already obvious.
|
|
231
|
+
- If the tool schema and live onboarding disagree about a specialized route key or
|
|
232
|
+
path, treat that as a contract mismatch to fix. Do not guess a nearby route.
|
|
219
233
|
|
|
220
234
|
## Active-listening patterns
|
|
221
235
|
|
|
@@ -314,8 +328,8 @@ exists.
|
|
|
314
328
|
- If the next answer would not change the route, wording, timing, links, or useful
|
|
315
329
|
interpretation, stop asking and act.
|
|
316
330
|
- Close cleanly:
|
|
317
|
-
once the user says the wording or
|
|
318
|
-
or write.
|
|
331
|
+
once the user says the wording or next action lands, summarize once and move to the
|
|
332
|
+
read or write.
|
|
319
333
|
|
|
320
334
|
When an adjacent record becomes visible:
|
|
321
335
|
|
|
@@ -344,8 +358,10 @@ Use this quick internal check before every follow-up question.
|
|
|
344
358
|
1. What is the one thing still unknown?
|
|
345
359
|
2. Does that unknown affect the entity shape, the wording, the placement, or the
|
|
346
360
|
operational detail?
|
|
347
|
-
3.
|
|
348
|
-
|
|
361
|
+
3. Does it affect the API posture: batch CRUD, specialized CRUD, action workflow, or
|
|
362
|
+
specialized domain route?
|
|
363
|
+
4. What is the smallest question that would answer that unknown?
|
|
364
|
+
5. If the user already gave enough to act, stop asking and move to a short summary or
|
|
349
365
|
the write.
|
|
350
366
|
|
|
351
367
|
Useful calibration heuristics:
|
|
@@ -360,6 +376,8 @@ Useful calibration heuristics:
|
|
|
360
376
|
once and then return to the one missing structural detail.
|
|
361
377
|
- If the next question would only decorate the record and not change its usefulness,
|
|
362
378
|
skip it.
|
|
379
|
+
- If the next question would not change the API path, payload, wording, timing, or
|
|
380
|
+
useful links, skip it.
|
|
363
381
|
|
|
364
382
|
## Abstract And Reusable Record Moves
|
|
365
383
|
|
|
@@ -777,6 +795,8 @@ Routing rule:
|
|
|
777
795
|
book or article, keep a concept, or build a reusable explanation, consider
|
|
778
796
|
`wiki_page` before `note`. Use `note` for temporary evidence, work logs, or linked
|
|
779
797
|
detail; use `wiki_page` for durable memory.
|
|
798
|
+
- Use the wiki tools and `/api/v1/wiki/pages` family for page reads and writes. Do
|
|
799
|
+
not route `wiki_page` through batch entity CRUD.
|
|
780
800
|
|
|
781
801
|
Ready to save when:
|
|
782
802
|
|
|
@@ -922,6 +942,13 @@ Preferred opening question:
|
|
|
922
942
|
|
|
923
943
|
- "Which task should I start?"
|
|
924
944
|
|
|
945
|
+
Route note:
|
|
946
|
+
|
|
947
|
+
- `task_run` is an action workflow. Start live work with `/api/v1/tasks/:id/runs`.
|
|
948
|
+
Use `/api/v1/task-runs/:id/heartbeat`, `/focus`, `/complete`, and `/release` for
|
|
949
|
+
the rest of the run lifecycle. Do not represent live work by only changing task
|
|
950
|
+
status.
|
|
951
|
+
|
|
925
952
|
## Work Adjustment
|
|
926
953
|
|
|
927
954
|
Aim: correct tracked minutes truthfully without pretending a live run happened.
|
|
@@ -939,6 +966,12 @@ Helpful follow-up lanes:
|
|
|
939
966
|
- whether the adjustment is positive or negative
|
|
940
967
|
- what truthful reason should stay attached to the correction
|
|
941
968
|
|
|
969
|
+
Route note:
|
|
970
|
+
|
|
971
|
+
- `work_adjustment` is an action workflow. Use the dedicated work-adjustment tool or
|
|
972
|
+
`/api/v1/work-adjustments` path after the target and signed minute correction are
|
|
973
|
+
clear. Do not create a fake task run or invent a standalone batch CRUD entity.
|
|
974
|
+
|
|
942
975
|
Ready to act when:
|
|
943
976
|
|
|
944
977
|
- the target task or project is clear
|
|
@@ -987,7 +1020,8 @@ Route note:
|
|
|
987
1020
|
|
|
988
1021
|
- `self_observation` is note-backed. Read the calendar first, then create or update an
|
|
989
1022
|
observed `note` with `frontmatter.observedAt` instead of inventing a standalone CRUD
|
|
990
|
-
write.
|
|
1023
|
+
write. The read path is `/api/v1/psyche/self-observation/calendar`; the stored
|
|
1024
|
+
write is a linked `note` through the shared batch entity route.
|
|
991
1025
|
- Do not promote self-observation over functional analysis. If the user is describing
|
|
992
1026
|
a loop, use `behavior_pattern`; if they are describing one emotionally meaningful
|
|
993
1027
|
episode, use `trigger_report`; if a part-state is central, use `mode_guide_session`
|
|
@@ -1076,13 +1110,29 @@ Arc:
|
|
|
1076
1110
|
real use case.
|
|
1077
1111
|
4. Ask only for the next provider-specific step that still matters, such as auth flow,
|
|
1078
1112
|
label, or calendar selection.
|
|
1079
|
-
5.
|
|
1113
|
+
5. If the user is updating or removing an existing connection, ask which connection
|
|
1114
|
+
and what exact lifecycle action they want before touching credentials or sync.
|
|
1115
|
+
6. Move into the actual connection flow once the setup goal is clear.
|
|
1080
1116
|
|
|
1081
1117
|
Helpful follow-up lanes:
|
|
1082
1118
|
|
|
1083
1119
|
- what calendar workflow the user wants to unlock
|
|
1084
1120
|
- whether writable projection matters
|
|
1085
1121
|
- whether the provider requires a local sign-in step instead of manual fields
|
|
1122
|
+
- whether this is new setup, rediscovery, selected-calendar update, sync, or removal
|
|
1123
|
+
|
|
1124
|
+
Route note:
|
|
1125
|
+
|
|
1126
|
+
- `calendar_connection` is a specialized CRUD surface, not a batch CRUD entity.
|
|
1127
|
+
- Use `GET /api/v1/calendar/connections` to read existing connections.
|
|
1128
|
+
- Use `POST /api/v1/calendar/discovery` for Apple or custom CalDAV discovery and
|
|
1129
|
+
`GET /api/v1/calendar/macos-local/discovery` for calendars already configured on
|
|
1130
|
+
this Mac.
|
|
1131
|
+
- Use `GET /api/v1/calendar/connections/:id/discovery` before changing selected
|
|
1132
|
+
calendars on an existing connection.
|
|
1133
|
+
- Use `POST /api/v1/calendar/connections`, `PATCH /api/v1/calendar/connections/:id`,
|
|
1134
|
+
`POST /api/v1/calendar/connections/:id/sync`, or
|
|
1135
|
+
`DELETE /api/v1/calendar/connections/:id` for the connection lifecycle.
|
|
1086
1136
|
|
|
1087
1137
|
Ready to act when:
|
|
1088
1138
|
|
|
@@ -1301,6 +1351,9 @@ Lane-to-route map:
|
|
|
1301
1351
|
|
|
1302
1352
|
Direct action rules:
|
|
1303
1353
|
|
|
1354
|
+
- In onboarding, this surface may be keyed as `lifeForce` and also as the entity-style
|
|
1355
|
+
alias `life_force`. Treat both names as the same dedicated Life Force route family,
|
|
1356
|
+
not as batch CRUD.
|
|
1304
1357
|
- If the user is describing a durable baseline such as work capacity, recovery style,
|
|
1305
1358
|
or action-point assumptions, patch the profile instead of logging a fatigue signal.
|
|
1306
1359
|
- If the user is describing a repeatable weekday rhythm, update that weekday template
|
|
@@ -1566,7 +1619,9 @@ Route note:
|
|
|
1566
1619
|
|
|
1567
1620
|
- `questionnaire_instrument` is normal stored CRUD for ordinary create, update,
|
|
1568
1621
|
delete, and search work. Use clone, draft, and publish action routes only when the
|
|
1569
|
-
user is working with instrument version state.
|
|
1622
|
+
user is working with instrument version state. Questionnaire action paths live under
|
|
1623
|
+
`/api/v1/psyche/questionnaires`, including `/:id/clone`, `/:id/draft`, and
|
|
1624
|
+
`/:id/publish`.
|
|
1570
1625
|
|
|
1571
1626
|
Ready to act when:
|
|
1572
1627
|
|
|
@@ -1599,7 +1654,10 @@ Helpful follow-up lanes:
|
|
|
1599
1654
|
Route note:
|
|
1600
1655
|
|
|
1601
1656
|
- `questionnaire_run` is an action workflow. Use the questionnaire run start, read,
|
|
1602
|
-
update, and complete routes instead of treating answers as generic batch CRUD
|
|
1657
|
+
update, and complete routes instead of treating answers as generic batch CRUD:
|
|
1658
|
+
`/api/v1/psyche/questionnaires/:id/runs`,
|
|
1659
|
+
`/api/v1/psyche/questionnaire-runs/:id`, and
|
|
1660
|
+
`/api/v1/psyche/questionnaire-runs/:id/complete`.
|
|
1603
1661
|
|
|
1604
1662
|
Ready to act when:
|
|
1605
1663
|
|