Rules for trusted NanoClaw groups. Shared memory, session bootstrap, cross-group memory updates. Loaded for trusted and main containers only.
77
96%
Does it follow best practices?
Impact
—
No eval scenarios have been run
Risky
Do not use without reviewing
State written by scripts/register-session.py per jbaruch/coding-policy: stateful-artifacts. Owner skill is tessl__trusted-memory. Reader skills — jbaruch/nanoclaw-admin: tessl__heartbeat and jbaruch/nanoclaw-admin: tessl__check-email — MUST treat any unrecognised shape as "no usable prior state" and let the next owner-skill run rewrite it.
/workspace/group/session-state.jsonMutable JSON object. Per-group, not shared across containers.
{
"schema_version": 1,
"sessions": {
"<NANOCLAW_SESSION_NAME>": {
"started": "<ISO-8601 UTC, e.g. 2026-04-27T15:00:00Z>",
"epoch": <int unix seconds>,
"session_id": "<sqlite session_id from /workspace/store/messages.db, or null>",
"last_seen": "<ISO-8601 UTC>"
}
},
"session_id": "<top-level mirror of the active session_id, back-compat>",
"pending_response": null,
"seen_email_ids": [],
"muted_threads": {}
}| Field | Writers | Readers | Notes |
|---|---|---|---|
schema_version | register-session.py (owner) | All readers gate on this | See Schema versioning below |
sessions.<name>.* | register-session.py (owner) — own session's subtree | All readers may inspect any session | last_seen may be stamped by tessl__heartbeat for maintenance |
session_id (top-level) | register-session.py — both sessions on bootstrap | Legacy readers only | Back-compat; last-writer-wins is accepted |
pending_response | default session writes on inbound start; default clears on send; maintenance heartbeat clears stale entries | All trusted/main sessions | The pending-response-tracking rule governs the protocol |
seen_email_ids | tessl__check-email, tessl__heartbeat, tessl__morning-brief, tessl__nightly (all maintenance) | tessl__check-email for de-dup | Append-only within a window |
muted_threads | default session | default + maintenance | Per-thread mute map |
Back-compat note (legacy migration, ex–reference_session-state-migration.md): the top-level session_id field is the pre-PR jbaruch/nanoclaw#55 shape, when only one session existed per group. It is still written so readers that haven't moved to the per-session subtree continue to work. New readers SHOULD use sessions.<name>.session_id. Old single-session files are accepted on read — register-session.py adds the sessions subtree without dropping the top-level field, so the migration is in-place and idempotent.
Other writers on this file must take fcntl.LOCK_EX on /workspace/group/session-state.json.lock for the duration of their read-modify-write cycle. Current participants: jbaruch/nanoclaw-admin: tessl__heartbeat (writes last_seen, clears stale pending_response) and jbaruch/nanoclaw-admin: tessl__check-email (writes seen_email_ids, pending_response, muted_threads). Without the shared lock, concurrent updates clobber each other.
/tmp/session_bootstrappedPlain-text sentinel. One line: the value of $CLAUDE_SESSION_ID from the run that completed bootstrap.
needs-bootstrap.py compares this file's contents to the current $CLAUDE_SESSION_ID. Mismatch (or missing file) → bootstrap is needed. register-session.py REFUSES to write an empty sentinel because an empty value would match an empty env var on the next run and permanently suppress bootstrap.
session-state.json carries schema_version: 1 at the top level. v1 is the current canonical shape: schema_version + sessions.<name> subtree + back-compat top-level session_id. Files written before this field existed are read-tolerated by register-session.py (the owner skill) and silently upgraded to v1 on the next write — owner-skill migration per jbaruch/coding-policy: stateful-artifacts.
Reader skills (jbaruch/nanoclaw-admin: tessl__heartbeat, jbaruch/nanoclaw-admin: tessl__check-email) MUST treat an unknown future version (schema_version > 1) as "no usable prior state" and let the next register-session.py run perform the upgrade — never migrate from a reader.
/tmp/session_bootstrapped is a single-line plain-text sentinel; it has no envelope shape to version. The only behavioral contract is "non-empty content = bootstrap was completed for this $CLAUDE_SESSION_ID", and that contract is stable.
rules
skills
system-status