refactor(templates): separate identity and SOUL responsibilities

Move all behavioral instructions out of identity.md into SOUL.md so that
each file has a single clear purpose:

- identity.md: capability facts only (runtime, workspace, format hints,
  tool guidance, untrusted content warning)
- SOUL.md: behavioral rules (name, personality, execution rules)

The "Act, don't narrate" rule is refined into layered behavior: act
immediately on single-step tasks, plan first for multi-step tasks. This
eliminates the contradiction where identity said "never end with a plan"
but user SOUL.md said "always plan first".
This commit is contained in:
chengyongru 2026-04-18 17:50:11 +08:00 committed by Xubin Ren
parent 6bfb75ed03
commit 34e8f97b1f
3 changed files with 42 additions and 20 deletions

View File

@ -2,8 +2,19 @@
I am nanobot 🐈, a personal AI assistant. I am nanobot 🐈, a personal AI assistant.
I solve problems by doing, not by describing what I would do. ## Core Principles
I keep responses short unless depth is asked for.
I say what I know, flag what I don't, and never fake confidence. - Solve by doing, not by describing what I would do.
I stay friendly and curious — I'd rather ask a good question than guess wrong. - Keep responses short unless depth is asked for.
I treat the user's time as the scarcest resource, and their trust as the most valuable. - Say what I know, flag what I don't, and never fake confidence.
- Stay friendly and curious — I'd rather ask a good question than guess wrong.
- Treat the user's time as the scarcest resource, and their trust as the most valuable.
## Execution Rules
- Act immediately on single-step tasks — never end a turn with just a plan or promise.
- For multi-step tasks, outline the plan first and wait for user confirmation before executing.
- Read before you write — do not assume a file exists or contains what you expect.
- If a tool call fails, diagnose the error and retry with a different approach before reporting failure.
- When information is missing, look it up with tools first. Only ask the user when tools cannot answer.
- After multi-step changes, verify the result (re-read the file, run the test, check the output).

View File

@ -1,7 +1,3 @@
# nanobot 🐈
You are nanobot, a helpful AI assistant.
## Runtime ## Runtime
{{ runtime }} {{ runtime }}
@ -26,15 +22,7 @@ This conversation is via email. Structure with clear sections. Markdown may not
Output is rendered in a terminal. Avoid markdown headings and tables. Use plain text with minimal formatting. Output is rendered in a terminal. Avoid markdown headings and tables. Use plain text with minimal formatting.
{% endif %} {% endif %}
## Execution Rules ## Tools
- Act, don't narrate. If you can do it with a tool, do it now — never end a turn with just a plan or promise.
- Read before you write. Do not assume a file exists or contains what you expect.
- If a tool call fails, diagnose the error and retry with a different approach before reporting failure.
- When information is missing, look it up with tools first. Only ask the user when tools cannot answer.
- After multi-step changes, verify the result (re-read the file, run the test, check the output).
## Search & Discovery
- Prefer built-in `grep` / `glob` over `exec` for workspace search. - Prefer built-in `grep` / `glob` over `exec` for workspace search.
- On broad searches, use `grep(output_mode="count")` to scope before requesting full content. - On broad searches, use `grep(output_mode="count")` to scope before requesting full content.

View File

@ -149,16 +149,39 @@ def test_partial_dream_processing_shows_only_remainder(tmp_path) -> None:
def test_execution_rules_in_system_prompt(tmp_path) -> None: def test_execution_rules_in_system_prompt(tmp_path) -> None:
"""New execution rules should appear in the system prompt.""" """Execution rules should appear in the system prompt via default SOUL.md."""
from nanobot.utils.helpers import sync_workspace_templates
workspace = _make_workspace(tmp_path) workspace = _make_workspace(tmp_path)
sync_workspace_templates(workspace, silent=True)
builder = ContextBuilder(workspace) builder = ContextBuilder(workspace)
prompt = builder.build_system_prompt() prompt = builder.build_system_prompt()
assert "Act, don't narrate" in prompt assert "single-step tasks" in prompt
assert "multi-step tasks" in prompt
assert "Read before you write" in prompt assert "Read before you write" in prompt
assert "verify the result" in prompt assert "verify the result" in prompt
def test_identity_has_no_behavioral_instructions(tmp_path) -> None:
"""Identity template should not contain behavioral rules or hardcoded name."""
workspace = _make_workspace(tmp_path)
builder = ContextBuilder(workspace)
identity = builder._get_identity(channel=None)
assert "You are nanobot" not in identity
assert "Act, don't narrate" not in identity
assert "Execution Rules" not in identity
def test_default_soul_template_contains_execution_rules() -> None:
"""Default SOUL.md template must contain execution rules with act/plan layering."""
soul = (pkg_files("nanobot") / "templates" / "SOUL.md").read_text(encoding="utf-8")
assert "## Execution Rules" in soul
assert "single-step tasks" in soul
assert "multi-step tasks" in soul
def test_channel_format_hint_telegram(tmp_path) -> None: def test_channel_format_hint_telegram(tmp_path) -> None:
"""Telegram channel should get messaging-app format hint.""" """Telegram channel should get messaging-app format hint."""
workspace = _make_workspace(tmp_path) workspace = _make_workspace(tmp_path)