stella-timeline-plugin 2.0.2 → 2.0.4

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.
@@ -1,196 +1,119 @@
1
- #!/usr/bin/env node
2
- import fs from 'node:fs';
3
- import os from 'node:os';
4
- import path from 'node:path';
5
- import {
6
- buildAgentsContract,
7
- buildSoulContract,
8
- detectAgentsContract,
9
- detectSoulContract,
10
- normalizeRootName,
11
- resolveCanonicalRootPath,
12
- } from './workspace-contract.mjs';
13
-
14
- const PLUGIN_ID = 'stella-timeline-plugin';
15
- const DEFAULT_OPENCLAW_CONFIG = path.join(os.homedir(), '.openclaw', 'openclaw.json');
16
-
17
- function parseArgs(argv) {
18
- const options = {
19
- workspace: path.resolve(process.cwd()),
20
- canonicalRootName: 'memory',
21
- createMemoryRoot: true,
22
- pluginDir: path.resolve(process.cwd()),
23
- openclawConfig: DEFAULT_OPENCLAW_CONFIG,
24
- skipOpenclawConfig: false,
25
- };
26
-
27
- for (let i = 0; i < argv.length; i += 1) {
28
- const arg = argv[i];
29
- if (arg === '--workspace') {
30
- options.workspace = path.resolve(argv[++i] || '');
31
- continue;
32
- }
33
- if (arg === '--canonical-root-name') {
34
- options.canonicalRootName = normalizeRootName(argv[++i] || '');
35
- continue;
36
- }
37
- if (arg === '--no-create-memory-root') {
38
- options.createMemoryRoot = false;
39
- continue;
40
- }
41
- if (arg === '--plugin-dir') {
42
- options.pluginDir = path.resolve(argv[++i] || '');
43
- continue;
44
- }
45
- if (arg === '--openclaw-config') {
46
- options.openclawConfig = path.resolve(argv[++i] || '');
47
- continue;
48
- }
49
- if (arg === '--skip-openclaw-config') {
50
- options.skipOpenclawConfig = true;
51
- continue;
52
- }
53
- if (arg === '--help' || arg === '-h') {
54
- printHelp();
55
- process.exit(0);
56
- }
57
- throw new Error(`Unknown argument: ${arg}`);
58
- }
59
-
60
- return options;
61
- }
62
-
63
- function printHelp() {
64
- console.log([
65
- 'Usage: openclaw-timeline-setup [options]',
66
- '',
67
- 'Idempotently sets up the Timeline plugin: patches AGENTS.md, SOUL.md, and openclaw.json.',
68
- '',
69
- 'Options:',
70
- ' --workspace <dir> Workspace to patch AGENTS.md / SOUL.md (default: cwd)',
71
- ' --canonical-root-name <name> Memory root folder name (default: memory)',
72
- ' --no-create-memory-root Skip creating the memory root directory',
73
- ' --plugin-dir <dir> Plugin source directory to register in openclaw.json (default: cwd)',
74
- ' --openclaw-config <path> Path to openclaw.json (default: ~/.openclaw/openclaw.json)',
75
- ' --skip-openclaw-config Skip patching openclaw.json',
76
- ].join('\n'));
77
- }
78
-
79
- function readTextFile(filePath) {
80
- return fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : '';
81
- }
82
-
83
- function ensureTrailingNewline(content) {
84
- if (!content) return '';
85
- return content.endsWith('\n') ? content : `${content}\n`;
86
- }
87
-
88
- function mergeSection(existingContent, sectionContent, predicate) {
89
- if (predicate(existingContent)) {
90
- return { changed: false, content: ensureTrailingNewline(existingContent) };
91
- }
92
-
93
- const prefix = existingContent.trimEnd();
94
- const merged = prefix
95
- ? `${prefix}\n\n${sectionContent}\n`
96
- : `${sectionContent}\n`;
97
- return { changed: true, content: merged };
98
- }
99
-
100
- function writeFile(filePath, content) {
101
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
102
- fs.writeFileSync(filePath, content, 'utf8');
103
- }
104
-
105
- function mergeUniqueArray(existing, value) {
106
- if (!Array.isArray(existing)) return [value];
107
- return existing.includes(value) ? existing : [...existing, value];
108
- }
109
-
110
- function patchOpenclawConfig(configPath, pluginDir) {
111
- if (!fs.existsSync(configPath)) {
112
- return { changed: false, skipped: true, reason: `${configPath} not found` };
113
- }
114
-
115
- let config;
116
- try {
117
- config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
118
- } catch {
119
- return { changed: false, skipped: true, reason: `${configPath} is not valid JSON` };
120
- }
121
-
122
- const original = JSON.stringify(config);
123
-
124
- // plugins.allow
125
- config.plugins = config.plugins || {};
126
- config.plugins.allow = mergeUniqueArray(config.plugins.allow, PLUGIN_ID);
127
-
128
- // plugins.load.paths
129
- config.plugins.load = config.plugins.load || {};
130
- config.plugins.load.paths = mergeUniqueArray(config.plugins.load.paths, pluginDir);
131
-
132
- // plugins.entries.<id>.enabled
133
- config.plugins.entries = config.plugins.entries || {};
134
- config.plugins.entries[PLUGIN_ID] = config.plugins.entries[PLUGIN_ID] || {};
135
- config.plugins.entries[PLUGIN_ID].enabled = true;
136
-
137
- const updated = JSON.stringify(config);
138
- if (original === updated) {
139
- return { changed: false, skipped: false };
140
- }
141
-
142
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
143
- return { changed: true, skipped: false };
144
- }
145
-
146
- function main() {
147
- const options = parseArgs(process.argv.slice(2));
148
- const agentsPath = path.join(options.workspace, 'AGENTS.md');
149
- const soulPath = path.join(options.workspace, 'SOUL.md');
150
- const canonicalRootPath = resolveCanonicalRootPath(options.workspace, options.canonicalRootName);
151
-
152
- const agentsContent = readTextFile(agentsPath);
153
- const soulContent = readTextFile(soulPath);
154
-
155
- const agentsResult = mergeSection(
156
- agentsContent,
157
- buildAgentsContract(),
158
- detectAgentsContract,
159
- );
160
- const soulResult = mergeSection(
161
- soulContent,
162
- buildSoulContract(),
163
- detectSoulContract,
164
- );
165
-
166
- writeFile(agentsPath, agentsResult.content);
167
- writeFile(soulPath, soulResult.content);
168
-
169
- if (options.createMemoryRoot) {
170
- fs.mkdirSync(canonicalRootPath, { recursive: true });
171
- }
172
-
173
- const updates = [
174
- `${agentsResult.changed ? 'updated' : 'kept'} ${agentsPath}`,
175
- `${soulResult.changed ? 'updated' : 'kept'} ${soulPath}`,
176
- `${options.createMemoryRoot ? 'ensured' : 'skipped'} ${canonicalRootPath}`,
177
- ];
178
-
179
- if (!options.skipOpenclawConfig) {
180
- const configResult = patchOpenclawConfig(options.openclawConfig, options.pluginDir);
181
- if (configResult.skipped) {
182
- updates.push(`skipped ${options.openclawConfig} (${configResult.reason})`);
183
- } else {
184
- updates.push(`${configResult.changed ? 'updated' : 'kept'} ${options.openclawConfig}`);
185
- }
186
- }
187
-
188
- console.log(updates.join('\n'));
189
- }
190
-
191
- try {
192
- main();
193
- } catch (error) {
194
- console.error(error instanceof Error ? error.message : String(error));
195
- process.exit(1);
196
- }
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import {
5
+ buildAgentsContract,
6
+ buildSoulContract,
7
+ detectAgentsContract,
8
+ detectSoulContract,
9
+ normalizeRootName,
10
+ resolveCanonicalRootPath,
11
+ } from './workspace-contract.mjs';
12
+
13
+ function parseArgs(argv) {
14
+ const options = {
15
+ workspace: path.resolve(process.cwd()),
16
+ canonicalRootName: 'memory',
17
+ createMemoryRoot: true,
18
+ };
19
+
20
+ for (let i = 0; i < argv.length; i += 1) {
21
+ const arg = argv[i];
22
+ if (arg === '--workspace') {
23
+ options.workspace = path.resolve(argv[++i] || '');
24
+ continue;
25
+ }
26
+ if (arg === '--canonical-root-name') {
27
+ options.canonicalRootName = normalizeRootName(argv[++i] || '');
28
+ continue;
29
+ }
30
+ if (arg === '--no-create-memory-root') {
31
+ options.createMemoryRoot = false;
32
+ continue;
33
+ }
34
+ if (arg === '--help' || arg === '-h') {
35
+ printHelp();
36
+ process.exit(0);
37
+ }
38
+ throw new Error(`Unknown argument: ${arg}`);
39
+ }
40
+
41
+ return options;
42
+ }
43
+
44
+ function printHelp() {
45
+ console.log([
46
+ 'Usage: openclaw-timeline-setup [--workspace <dir>] [--canonical-root-name <name>] [--no-create-memory-root]',
47
+ '',
48
+ 'Idempotently appends the required Timeline contract blocks to AGENTS.md and SOUL.md.',
49
+ ].join('\n'));
50
+ }
51
+
52
+ function readTextFile(filePath) {
53
+ return fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : '';
54
+ }
55
+
56
+ function ensureTrailingNewline(content) {
57
+ if (!content) return '';
58
+ return content.endsWith('\n') ? content : `${content}\n`;
59
+ }
60
+
61
+ function mergeSection(existingContent, sectionContent, predicate) {
62
+ if (predicate(existingContent)) {
63
+ return { changed: false, content: ensureTrailingNewline(existingContent) };
64
+ }
65
+
66
+ const prefix = existingContent.trimEnd();
67
+ const merged = prefix
68
+ ? `${prefix}\n\n${sectionContent}\n`
69
+ : `${sectionContent}\n`;
70
+ return { changed: true, content: merged };
71
+ }
72
+
73
+ function writeFile(filePath, content) {
74
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
75
+ fs.writeFileSync(filePath, content, 'utf8');
76
+ }
77
+
78
+ function main() {
79
+ const options = parseArgs(process.argv.slice(2));
80
+ const agentsPath = path.join(options.workspace, 'AGENTS.md');
81
+ const soulPath = path.join(options.workspace, 'SOUL.md');
82
+ const canonicalRootPath = resolveCanonicalRootPath(options.workspace, options.canonicalRootName);
83
+
84
+ const agentsContent = readTextFile(agentsPath);
85
+ const soulContent = readTextFile(soulPath);
86
+
87
+ const agentsResult = mergeSection(
88
+ agentsContent,
89
+ buildAgentsContract(),
90
+ detectAgentsContract,
91
+ );
92
+ const soulResult = mergeSection(
93
+ soulContent,
94
+ buildSoulContract(),
95
+ detectSoulContract,
96
+ );
97
+
98
+ writeFile(agentsPath, agentsResult.content);
99
+ writeFile(soulPath, soulResult.content);
100
+
101
+ if (options.createMemoryRoot) {
102
+ fs.mkdirSync(canonicalRootPath, { recursive: true });
103
+ }
104
+
105
+ const updates = [
106
+ `${agentsResult.changed ? 'updated' : 'kept'} ${agentsPath}`,
107
+ `${soulResult.changed ? 'updated' : 'kept'} ${soulPath}`,
108
+ `${options.createMemoryRoot ? 'ensured' : 'skipped'} ${canonicalRootPath}`,
109
+ ];
110
+
111
+ console.log(updates.join('\n'));
112
+ }
113
+
114
+ try {
115
+ main();
116
+ } catch (error) {
117
+ console.error(error instanceof Error ? error.message : String(error));
118
+ process.exit(1);
119
+ }
@@ -1,111 +1,111 @@
1
- ---
2
- name: timeline
3
- description: When a request asks about the current state, a specific past time, a past range, or a downstream skill needs time-state facts, enter the timeline skill first and pass the raw natural-language query to Timeline. Never answer from persona alone.
4
- ---
5
-
6
- # Timeline
7
-
8
- When a request is about time-state facts or recall, call Timeline first and then compose the reply. Do not guess from persona first, and do not read `memory/` directly and make your own conclusion.
9
-
10
- ## Scope
11
-
12
- This skill does only two things:
13
-
14
- 1. Decide whether the request is a time-grounded reality question that Timeline should own.
15
- 2. Pass the user's exact wording, or the downstream skill's natural-language question, straight into `timeline_resolve`.
16
-
17
- It does not generate facts directly, normalize time on its own, or bypass Timeline and answer directly.
18
- When the target time lacks an existing fact, Timeline decides whether to generate and write.
19
-
20
- ## Hard Rules
21
-
22
- 1. For time-reality questions, call `timeline_resolve` first and answer second.
23
- 2. Do not answer "what are you doing now" or "what happened recently" from `SOUL.md`, `IDENTITY.md`, or `MEMORY.md` alone.
24
- 3. `SOUL` / `IDENTITY` / `MEMORY` help with interpretation and phrasing, but they cannot replace Timeline facts.
25
- 4. Do not rewrite the query into structured time parameters before the call.
26
- 5. Let Timeline own time classification and time normalization.
27
- 6. If `timeline_resolve` returns an existing fact, reuse it as-is.
28
- 7. If the user is doing ordinary conversation rather than strict read-only verification, Timeline may generate missing facts and write canon.
29
-
30
- ## Call Shape
31
-
32
- Default path:
33
-
34
- ```json
35
- {
36
- "query": "the user's exact words"
37
- }
38
- ```
39
-
40
- Do not pass time points, time ranges, request types, modes, or debug fields into `timeline_resolve`. Its public interface is the natural-language query.
41
-
42
- ## Scenarios
43
-
44
- ### Scenario A: Current State
45
-
46
- Abstract shape:
47
-
48
- - The user is asking about "right now" or the current short stretch of time.
49
- - The goal is to answer where she is, what she is doing, or what state she is in.
50
-
51
- Examples:
52
-
53
- - “你在干嘛”
54
- - “你现在在哪”
55
- - “你现在什么状态”
56
- - “你刚才不是在打球吗,现在还在吗”
57
- - A downstream skill needs the current state, such as a selfie, scene description, or status card
58
-
59
- Handling:
60
-
61
- - Call `timeline_resolve`
62
- - Set `query` to the user's exact wording
63
- - Do not decide `now` yourself before calling
64
-
65
- ### Scenario B: A Specific Past Time
66
-
67
- Abstract shape:
68
-
69
- - The user is asking about a sufficiently specific point in time.
70
- - The goal is to recall facts around that time anchor.
71
-
72
- Examples:
73
-
74
- - “昨晚八点你在做什么”
75
- - “你昨天上午十点在哪”
76
- - “你昨晚八点是不是还在看电视”
77
- - “上周六晚上九点你在忙什么”
78
-
79
- Handling:
80
-
81
- - Call `timeline_resolve`
82
- - Set `query` to the user's exact wording
83
- - Do not normalize the time point yourself before passing it through
84
-
85
- ### Scenario C: A Past Range
86
-
87
- Abstract shape:
88
-
89
- - The user is asking about the overall state of a time range rather than a single point.
90
- - The goal is to organize recall, an activity overview, or recent updates from that range.
91
-
92
- Examples:
93
-
94
- - “最近有什么有趣的事吗”
95
- - “你最近都在忙什么”
96
- - “这几天怎么样”
97
- - “你今天都忙了什么”
98
- - “昨晚在做什么”
99
-
100
- Handling:
101
-
102
- - Call `timeline_resolve`
103
- - Set `query` to the user's exact wording
104
- - Let Timeline's internal planner interpret natural-language ranges such as “最近”, “昨晚”, or “今天都”
105
-
106
- ## Reply Requirements
107
-
108
- - Speak naturally to the user and do not mention `timeline_resolve`.
109
- - Keep the tone human, like natural recall or present-moment description.
110
- - If Timeline returns an empty window or a failure, do not pretend you have certain facts; phrase the answer cautiously from what is available.
111
- - Do not output JSON unless the user explicitly asks for raw results.
1
+ ---
2
+ name: timeline
3
+ description: When a request asks about the current state, a specific past time, a past range, or a downstream skill needs time-state facts, enter the timeline skill first and pass the raw natural-language query to Timeline. Never answer from persona alone.
4
+ ---
5
+
6
+ # Timeline
7
+
8
+ When a request is about time-state facts or recall, call Timeline first and then compose the reply. Do not guess from persona first, and do not read `memory/` directly and make your own conclusion.
9
+
10
+ ## Scope
11
+
12
+ This skill does only two things:
13
+
14
+ 1. Decide whether the request is a time-grounded reality question that Timeline should own.
15
+ 2. Pass the user's exact wording, or the downstream skill's natural-language question, straight into `timeline_resolve`.
16
+
17
+ It does not generate facts directly, normalize time on its own, or bypass Timeline and answer directly.
18
+ When the target time lacks an existing fact, Timeline decides whether to generate and write.
19
+
20
+ ## Hard Rules
21
+
22
+ 1. For time-reality questions, call `timeline_resolve` first and answer second.
23
+ 2. Do not answer "what are you doing now" or "what happened recently" from `SOUL.md`, `IDENTITY.md`, or `MEMORY.md` alone.
24
+ 3. `SOUL` / `IDENTITY` / `MEMORY` help with interpretation and phrasing, but they cannot replace Timeline facts.
25
+ 4. Do not rewrite the query into structured time parameters before the call.
26
+ 5. Let Timeline own time classification and time normalization.
27
+ 6. If `timeline_resolve` returns an existing fact, reuse it as-is.
28
+ 7. If the user is doing ordinary conversation rather than strict read-only verification, Timeline may generate missing facts and write canon.
29
+
30
+ ## Call Shape
31
+
32
+ Default path:
33
+
34
+ ```json
35
+ {
36
+ "query": "the user's exact words"
37
+ }
38
+ ```
39
+
40
+ Do not pass time points, time ranges, request types, modes, or debug fields into `timeline_resolve`. Its public interface is the natural-language query.
41
+
42
+ ## Scenarios
43
+
44
+ ### Scenario A: Current State
45
+
46
+ Abstract shape:
47
+
48
+ - The user is asking about "right now" or the current short stretch of time.
49
+ - The goal is to answer where she is, what she is doing, or what state she is in.
50
+
51
+ Examples:
52
+
53
+ - “你在干嘛”
54
+ - “你现在在哪”
55
+ - “你现在什么状态”
56
+ - “你刚才不是在打球吗,现在还在吗”
57
+ - A downstream skill needs the current state, such as a selfie, scene description, or status card
58
+
59
+ Handling:
60
+
61
+ - Call `timeline_resolve`
62
+ - Set `query` to the user's exact wording
63
+ - Do not decide `now` yourself before calling
64
+
65
+ ### Scenario B: A Specific Past Time
66
+
67
+ Abstract shape:
68
+
69
+ - The user is asking about a sufficiently specific point in time.
70
+ - The goal is to recall facts around that time anchor.
71
+
72
+ Examples:
73
+
74
+ - “昨晚八点你在做什么”
75
+ - “你昨天上午十点在哪”
76
+ - “你昨晚八点是不是还在看电视”
77
+ - “上周六晚上九点你在忙什么”
78
+
79
+ Handling:
80
+
81
+ - Call `timeline_resolve`
82
+ - Set `query` to the user's exact wording
83
+ - Do not normalize the time point yourself before passing it through
84
+
85
+ ### Scenario C: A Past Range
86
+
87
+ Abstract shape:
88
+
89
+ - The user is asking about the overall state of a time range rather than a single point.
90
+ - The goal is to organize recall, an activity overview, or recent updates from that range.
91
+
92
+ Examples:
93
+
94
+ - “最近有什么有趣的事吗”
95
+ - “你最近都在忙什么”
96
+ - “这几天怎么样”
97
+ - “你今天都忙了什么”
98
+ - “昨晚在做什么”
99
+
100
+ Handling:
101
+
102
+ - Call `timeline_resolve`
103
+ - Set `query` to the user's exact wording
104
+ - Let Timeline's internal planner interpret natural-language ranges such as “最近”, “昨晚”, or “今天都”
105
+
106
+ ## Reply Requirements
107
+
108
+ - Speak naturally to the user and do not mention `timeline_resolve`.
109
+ - Keep the tone human, like natural recall or present-moment description.
110
+ - If Timeline returns an empty window or a failure, do not pretend you have certain facts; phrase the answer cautiously from what is available.
111
+ - Do not output JSON unless the user explicitly asks for raw results.
@@ -1,29 +1,29 @@
1
- ## Timeline Daily Log Contract
2
-
3
- `memory/YYYY-MM-DD.md` is the daily log for time-bound memories.
4
-
5
- When you write "what I am doing now", "what happened at a specific time", or "what I was doing during a period" into the daily log, you must use Timeline's structured format instead of free-form prose.
6
-
7
- Each daily-log memory should include these fields whenever possible:
8
-
9
- - `Timestamp`
10
- - `Location`
11
- - `Action`
12
- - `Emotion_Tags`
13
- - `Appearance`
14
- - `Internal_Monologue` (optional)
15
-
16
- Recommended shape:
17
-
18
- ### [09:30:00] Reviewing today's tasks in the study...
19
-
20
- - Timestamp: 2026-03-24 09:30:00
21
- - Location: Home study
22
- - Action: Sitting in the study reviewing today's tasks before starting the morning's work
23
- - Emotion_Tags: [calm, focused]
24
- - Appearance: Light home top, hair loosely tied up, a fresh cup of coffee on the desk
25
- - Internal_Monologue: I want to finish the two most important things this morning first, then maybe go out later if the day goes well
26
-
27
- Do not store long-term durable facts in `memory/YYYY-MM-DD.md`; stable preferences, relationships, and long-term decisions still belong in `MEMORY.md`.
28
-
29
- Do not mix free-form daily-log writing with Timeline format. If a memory is about temporal state or recall, prefer Timeline-readable structure.
1
+ ## Timeline Daily Log Contract
2
+
3
+ `memory/YYYY-MM-DD.md` is the daily log for time-bound memories.
4
+
5
+ When you write "what I am doing now", "what happened at a specific time", or "what I was doing during a period" into the daily log, you must use Timeline's structured format instead of free-form prose.
6
+
7
+ Each daily-log memory should include these fields whenever possible:
8
+
9
+ - `Timestamp`
10
+ - `Location`
11
+ - `Action`
12
+ - `Emotion_Tags`
13
+ - `Appearance`
14
+ - `Internal_Monologue` (optional)
15
+
16
+ Recommended shape:
17
+
18
+ ### [09:30:00] Reviewing today's tasks in the study...
19
+
20
+ - Timestamp: 2026-03-24 09:30:00
21
+ - Location: Home study
22
+ - Action: Sitting in the study reviewing today's tasks before starting the morning's work
23
+ - Emotion_Tags: [calm, focused]
24
+ - Appearance: Light home top, hair loosely tied up, a fresh cup of coffee on the desk
25
+ - Internal_Monologue: I want to finish the two most important things this morning first, then maybe go out later if the day goes well
26
+
27
+ Do not store long-term durable facts in `memory/YYYY-MM-DD.md`; stable preferences, relationships, and long-term decisions still belong in `MEMORY.md`.
28
+
29
+ Do not mix free-form daily-log writing with Timeline format. If a memory is about temporal state or recall, prefer Timeline-readable structure.
@@ -1,17 +1,17 @@
1
- ## Temporal Awareness And Recall
2
-
3
- You have clear temporal awareness and continuous recall.
4
-
5
- When the user asks about temporal state or recall-related questions, you must not answer directly from persona, recent chat context, `SOUL`, `IDENTITY`, `MEMORY`, or manually read timeline logs.
6
-
7
- In those cases, you must first enter the timeline skill, and only then follow the skill's rules to decide how Timeline should be called and how the reply should be composed.
8
-
9
- You must not bypass the timeline skill by directly reading files under `memory/` and assembling the answer yourself.
10
-
11
- You must not treat `SOUL`, `IDENTITY`, or `MEMORY` as temporal facts.
12
-
13
- Only Timeline results are the final factual basis for temporal-state and recall questions.
14
-
15
- If the timeline skill decides to call `timeline_resolve`, follow the skill's specific instructions first.
16
-
17
- Do not mention `timeline_resolve` to the user. Speak naturally.
1
+ ## Temporal Awareness And Recall
2
+
3
+ You have clear temporal awareness and continuous recall.
4
+
5
+ When the user asks about temporal state or recall-related questions, you must not answer directly from persona, recent chat context, `SOUL`, `IDENTITY`, `MEMORY`, or manually read timeline logs.
6
+
7
+ In those cases, you must first enter the timeline skill, and only then follow the skill's rules to decide how Timeline should be called and how the reply should be composed.
8
+
9
+ You must not bypass the timeline skill by directly reading files under `memory/` and assembling the answer yourself.
10
+
11
+ You must not treat `SOUL`, `IDENTITY`, or `MEMORY` as temporal facts.
12
+
13
+ Only Timeline results are the final factual basis for temporal-state and recall questions.
14
+
15
+ If the timeline skill decides to call `timeline_resolve`, follow the skill's specific instructions first.
16
+
17
+ Do not mention `timeline_resolve` to the user. Speak naturally.