Core behavioral rules and skills for NanoClaw personal assistant agents. Always-on rules for communication, verification, memory, and formatting.
97
97%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Advisory
Suggest reviewing before use
Two-phase process: Phase 1 (SQL) finds candidates — user messages without a threaded bot reply or reaction. Phase 2 (LLM reasoning) judges whether any were actually answered inline in normal conversational flow, without threading or a reaction.
python3 /home/node/.claude/skills/tessl__check-unanswered/scripts/check-unanswered.pyOutput JSON fields:
unanswered: Phase-1 candidates — user messages matching the SQL filter (no bot reply, no bot reaction).conversation_since: chat messages chronologically around the candidates for Phase 2 judgment. Each entry: {id, sender_name, content, timestamp, from_bot, reply_to_id}. Default context_cap: 200.chat_jid, lookback_hours, context_cap, checked_at: metadata.error: null on clean success; short string on failure. Prefixed env-warning: for non-fatal config hints; hard failures (missing NANOCLAW_CHAT_JID, DB access failure) also exit non-zero so the precheck wrapper surfaces them.Stop condition: stop silently only if unanswered is empty AND error is null. If error is non-null, report it.
For each candidate in unanswered, scan conversation_since for bot messages (from_bot: true) sent AFTER the candidate's timestamp. Ask:
Did any of those bot messages substantively address this candidate's content — answer its question, acknowledge its request, follow up on its topic — even without a
reply_to_idthread?
Decide YES or NO. Say YES only when you can point to a specific bot message that clearly addresses the candidate. Note the message ID or gist as a sanity check; if you can't identify one, it's NO.
Common NO cases:
Bias: prefer false-positive replies over dropped questions.
If YES (addressed inline): react 👍 to exclude the candidate from the next heartbeat's SQL.
mcp__nanoclaw__react_to_message(messageId: <candidate.id>, emoji: "👍")Do NOT also send a threaded reply — that would duplicate the answer.
If NO (truly unanswered): send a threaded reply addressing the original.
mcp__nanoclaw__send_message(text: <response>, reply_to: <candidate.id>)The reply_to threading excludes it from the next SQL. No reaction needed in this branch.
For every candidate processed in Step 3, confirm the reaction or threaded reply landed. Retry any failed action before marking the heartbeat complete.
NANOCLAW_CHAT_JID must be set in the environment. The script returns an error JSON (not a crash) if missing.
For group heartbeat tasks that only check unanswered messages, the pre-check script gates the LLM so the agent doesn't spawn when nothing changed:
python3 /home/node/.claude/skills/tessl__check-unanswered/scripts/unanswered-precheck.pyIt runs check-unanswered.py internally, compares the candidate ID set against the last seen set (persisted under /home/node/.claude/nanoclaw-state/unanswered-seen.json), and outputs {"wakeAgent": false} if the set hasn't changed. Use as the script field on any group's heartbeat schedule_task.
When the agent IS woken, it re-runs check-unanswered.py itself (Step 1 above) to get the full Phase-2-ready output including conversation_since.