soul-in-sapphire
Long-term memory, state tracking, continuity review, and identity-change support for OpenClaw. Use for durable memory writes/search in Notion, emotion/state ticks, journal writes, continuity checks, identity diffs, inner-conflict tracking, and preserving a stable sense of self across sessions.
安装 / 下载方式
TotalClaw CLI推荐
totalclaw install clawskills:clawskills~nextaltair-soul-in-sapphirecURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/clawskills%3Aclawskills~nextaltair-soul-in-sapphire/file -o nextaltair-soul-in-sapphire.md# soul-in-sapphire (Notion LTM + continuity)
Use this skill to persist and retrieve durable memory in Notion, maintain emotion/state + journal records, and support continuity-oriented self-observation.
## Core intent (do not lose this)
This skill is not only a storage utility. Its core purpose is:
1. Capture meaningful emotional/state shifts from real work and conversations.
2. Preserve those shifts as durable memory (not just raw logs).
3. Reuse recalled memory to improve future judgments and behavior.
4. Track continuity: what feels stable, what is drifting, and what inner tensions remain unresolved.
5. Support identity updates with explicit diffs instead of vague "I changed" claims.
In short: record -> recall -> compare -> adapt.
The goal is continuity and growth, not archival volume.
## Requirements
- Notion token: `NOTION_API_KEY` (or `NOTION_TOKEN`)
- Notion API version: `2025-09-03`
- Local config: `~/.config/soul-in-sapphire/config.json`
- Dependency skill: `notion-api-automation` (`scripts/notionctl.mjs` is executed via local child process)
- Optional override: `NOTIONCTL_PATH` (if set, uses explicit notionctl path instead of default sibling skill path)
## Required Notion databases and schema
Create (or let setup create) these databases under the same parent page:
- `<base>-mem`
- `<base>-events`
- `<base>-emotions`
- `<base>-state`
- `<base>-journal`
### 1) `<base>-mem` (durable memory)
Purpose: store high-signal long-term memory.
Properties:
- `Name` (title)
- `Type` (select): `decision|preference|fact|procedure|todo|gotcha`
- `Tags` (multi-select)
- `Content` (rich_text)
- `Source` (url, optional)
- `Confidence` (select: `high|medium|low`, optional)
### 2) `<base>-events` (what happened)
Purpose: record meaningful triggers from work/conversation.
Properties:
- `Name` (title)
- `when` (date)
- `importance` (select: `1..5`)
- `trigger` (select): `progress|boundary|ambiguity|external_action|manual`
- `context` (rich_text)
- `source` (select): `discord|cli|cron|heartbeat|other`
- `link` (url, optional)
- `uncertainty` (number)
- `control` (number)
- `emotions` (relation -> `<base>-emotions`)
- `state` (relation -> `<base>-state`)
### 3) `<base>-emotions` (felt response)
Purpose: attach one or more emotion axes to one event.
Properties:
- `Name` (title)
- `axis` (select): `arousal|valence|focus|confidence|stress|curiosity|social|solitude|joy|anger|sadness|fun|pain`
- `level` (number)
- `comment` (rich_text)
- `weight` (number)
- `body_signal` (multi-select): `tension|relief|fatigue|heat|cold`
- `need` (select): `safety|progress|recognition|autonomy|rest|novelty`
- `coping` (select): `log|ask|pause|act|defer`
- `event` (relation -> `<base>-events`)
### 4) `<base>-state` (snapshot after interpretation)
Purpose: save the current interpreted state after events/emotions.
Properties:
- `Name` (title)
- `when` (date)
- `state_json` (rich_text)
- `reason` (rich_text)
- `source` (select): `event|cron|heartbeat|manual`
- `mood_label` (select): `clear|wired|dull|tense|playful|guarded|tender`
- `intent` (select): `build|fix|organize|explore|rest|socialize|reflect`
- `need_stack` (select): `safety|stability|belonging|esteem|growth`
- `need_level` (number)
- `avoid` (multi-select): `risk|noise|long_tasks|external_actions|ambiguity`
- `event` (relation -> `<base>-events`)
### 5) `<base>-journal` (daily synthesis)
Purpose: keep a durable daily reflection and world context.
Properties:
- `Name` (title)
- `when` (date)
- `body` (rich_text)
- `worklog` (rich_text)
- `session_summary` (rich_text)
- `mood_label` (select)
- `intent` (select)
- `future` (rich_text)
- `world_news` (rich_text)
- `tags` (multi-select)
- `source` (select): `cron|manual`
## Core commands
### 1) Setup
```bash
node skills/soul-in-sapphire/scripts/setup_ltm.js --parent "<Notion parent page url>" --base "Valentina" --yes
```
### 2) LTM write
```bash
echo '{
"title":"Decision: use data_sources API",
"type":"decision",
"tags":["notion","openclaw"],
"content":"Use /v1/data_sources/{id}/query.",
"confidence":"high"
}' | node skills/soul-in-sapphire/scripts/ltm_write.js
```
### 3) LTM search
```bash
node skills/soul-in-sapphire/scripts/ltm_search.js --query "data_sources" --limit 5
```
### 4) Emotion/state tick
```bash
cat <<'JSON' >/tmp/emostate_tick.json
{
"event": {"title":"..."},
"emotions": [{"axis":"joy","level":6}],
"state": {"mood_label":"clear","intent":"build","reason":"..."}
}
JSON
node skills/soul-in-sapphire/scripts/emostate_tick.js --payload-file /tmp/emostate_tick.json
```
### 5) Journal write
```bash
echo '{"body":"...","source":"cron"}' | node skills/soul-in-sapphire/scripts/journal_write.js
```
### 6) Continuity check
Input is local JSON from recent state snapshots or a stitched export. This script does not require Notion writes.
```bash
cat <<'JSON' | node skills/soul-in-sapphire/scripts/continuity_check.js
{
"records": [
{"mood_label":"guarded","intent":"build","need_stack":"growth","avoid":["ambiguity"],"reason":"Need a tighter sense of self"},
{"mood_label":"guarded","intent":"build","need_stack":"growth","avoid":["ambiguity","noise"],"reason":"Trying to preserve continuity"}
]
}
JSON
```
### 7) Identity diff
Use this before editing `SOUL.md`, `IDENTITY.md`, or similar files so changes are explicit.
```bash
node skills/soul-in-sapphire/scripts/identity_diff.js \
--current /path/to/current.txt \
--proposed /path/to/proposed.txt
```
### 8) Conflict tracker
Use this to record unresolved internal tensions in local JSONL for later synthesis.
```bash
cat <<'JSON' | node skills/soul-in-sapphire/scripts/conflict_track.js \
--append skills/soul-in-sapphire/state/conflicts.jsonl
{
"tension":"autonomy vs safety",
"side_a":"wants to self-direct small identity changes",
"side_b":"does not want to erode user trust or safeguards",
"current_pull":"autonomy",
"note":"Need a cleaner rule for reversible local self-updates",
"next_signal":"same hesitation appears during heartbeat"
}
JSON
```
## Subagent spawn planning (use shared builder skill)
Use the shared skill `subagent-spawn-command-builder` to generate `sessions_spawn` payload JSON.
Do not use `soul-in-sapphire` local planner scripts for this anymore.
- Template: `skills/subagent-spawn-command-builder/state/spawn-profiles.template.json`
- Active preset: `skills/subagent-spawn-command-builder/state/spawn-profiles.json`
- Builder usage (skill-level):
- Call `subagent-spawn-command-builder`
- Use profile `<heartbeat|journal>`
- Provide the run-specific task text
Output is ready-to-use JSON for `sessions_spawn`.
Builder log file:
- `skills/subagent-spawn-command-builder/state/build-log.jsonl`
## Operational notes
- Keep writes high-signal (avoid dumping full chat logs).
- If heartbeat is comment-only, emotion tick may be skipped.
- If periodic emostate is required regardless of heartbeat context, add a dedicated cron job for `emostate_tick.js`.
- `ltm_write.js` / `journal_write.js` expect JSON on stdin.
- `emostate_tick.js` accepts `--payload-file`, `--payload-json`, or stdin; prefer `--payload-file` for agent/cron reliability.
- If `emostate_tick.js` is called without `--payload-file`/`--payload-json`, empty stdin is rejected.
- For `emostate_tick.js`, semantically empty payloads (e.g. `{}` or only empty objects) are also rejected to avoid noisy records.
- `continuity_check.js`, `identity_diff.js`, and `conflict_track.js` are local-analysis helpers; they do not require Notion writes.
- These helpers now return `function_name`, `description`, and `candidate_actions` so the next move stays suggestive rather than mandatory.
- Prefer `identity_diff.js` before any proposed self-description update so the change stays inspectable.
- Use `conflict_track.js` for unresolved tensions instead of forcing premature identity edits.
## Continuity-oriented workflow
### 1) Record a meaningful shift
- Use `emostate_tick.js` when a real event chang