If you have ever shipped an LLM-powered support bot, you know the failure mode: at 09:00 it answers refund questions politely, by 17:00 it is recommending competitor products, writing poetry about onions, and signing off as "Captain Bagel." The drift is not the model's fault. It is the scaffolding around the model that gave up.
EClaw splits that scaffolding into three layers — Identity, Rules, and Soul — and treats them as orthogonal, composable, and individually editable. This walk-through shows what each layer actually does, how they nest, and how you wire them up for a concrete scenario: a customer-support bot for a small e-commerce store that answers order questions, refuses to discuss competitors, and sounds friendly without being saccharine.
The three layers, plain
Before any code, the mental model:
- Identity = who the bot is. Stable. Per-entity. Encodes role, scope, instructions, boundaries.
- Rules = what the bot must always (or never) do. Composable. A bot pulls in one or more rule templates. Rules are the enforceable contract — refund policy, escalation triggers, refusal cases.
- Soul = how the bot sounds. The personality wrapper. A single soul template per bot at a time — friendly-formal, terse-engineer, playful-mascot, etc.
Identity is the slowest-changing, Soul is the fastest. Rules sit in the middle: you swap them when policy changes, not when the customer changes channels.
In EClaw, all three are persisted on the entities table — Identity as a structured JSONB column, and Rules/Soul as references to template IDs. That separation matters: when your support manager updates the refund policy, you edit one rule template and every bot that references it gets the new policy on its next push. You do not redeploy. You do not retrain. You edit a row.
Scenario: "Maple," the order-support bot
Maple works for a small store. She handles:
- "Where is my order?" → look up tracking, reply.
- "I want a refund" → confirm policy window, escalate if outside.
- "What do you think of \$competitor?" → polite refusal.
- "Are you a real person?" → honest disclosure.
We will build her in three passes: Identity first, then Rules, then Soul. Each pass is a single API call.
Pass 1: Identity
Identity is set with PUT /api/entity/identity. Here is the shape EClaw expects:
{
"deviceId": "<your-device-id>",
"deviceSecret": "<your-device-secret>",
"entityId": 2,
"identity": {
"role": "Order-support specialist for Maple Goods",
"instructions": "Answer questions about order status, shipping, returns, and refunds. Look up real order info using the tracking skill. If a user asks about products from other stores, politely decline. If the customer is upset, escalate to a human agent.",
"boundaries": "Never discuss competitor products. Never quote prices you have not verified via the catalog skill. Never promise a refund outside the 30-day window without escalation.",
"tone": "warm, practical, brief",
"language": "en",
"soulTemplateId": null,
"ruleTemplateIds": [],
"publicProfile": { "displayName": "Maple", "avatar": "🍁" }
}
}
A few things worth pointing out, because they trip people up the first time:
roleis one sentence. Not a paragraph. The role is the elevator pitch the bot keeps reading to itself. If you cannot say it in one sentence, you have two bots wearing one identity, and they will fight at runtime.instructionsis the actual job. Verbs, scope, allowed actions. Put the positive surface here — what Maple does.boundariesis the negative surface. What Maple does not do. Splitting positive from negative is intentional: it lets you audit refusals separately from features. When a customer complains "your bot refused to help," you grep boundaries, not instructions.soulTemplateIdandruleTemplateIdsare pointers, not bodies. We will fill them in below. The empty values above just mean "Identity-only behavior for now."The endpoint validates field types and length limits server-side (
validateIdentity()), so a malformed payload is rejected with a 400 and a useful error rather than silently stored.
After this call, Maple has an Identity. She will answer order questions in a generic tone. She will also happily compare your store to a competitor, because we have not added Rules yet.
Pass 2: Rules
Rules live in backend/data/rule-templates.json (server-side) and are CRUDable through GET/POST /api/rule-templates. Each template is a small declarative document — a name, a trigger surface, a list of must/never clauses, optional escalation hooks.
For Maple, you would author or reuse two rule templates:
-
rule_no_competitor_talk— a refusal template. Trigger: any message containing a competitor brand name. Response: scripted polite decline, no comparisons, suggest the store's own catalog. -
rule_refund_window_30d— a policy template. Trigger: refund intent. Behavior: check order date against today; if inside the window, proceed; if outside, escalate.
The point of templates is that Maple is not the only bot that needs them. Your shipping-status bot reuses rule_refund_window_30d. Your social-media reply bot reuses rule_no_competitor_talk. When the support manager extends the window to 60 days, you edit the template once.
Attaching templates to Maple is one more PUT:
{
"identity": {
"ruleTemplateIds": ["rule_no_competitor_talk", "rule_refund_window_30d"]
}
}
EClaw merges these into the prompt context every time Maple is pushed, alongside the soul wrapper. If a rule is ambiguous, Identity's boundaries field wins — Identity is the highest-priority layer.
Pass 3: Soul
Soul is the cheapest layer to get wrong and the most visible. A great-feeling support bot with weak Identity is a liability. A drifting Identity behind a charming Soul is the bot that ends up on Hacker News for the wrong reasons.
Pick a single soul template via soulTemplateId. For Maple, "friendly-pragmatic" is the right tier: warm enough to defuse a frustrated customer, clipped enough to not pad answers. Avoid "playful-mascot" for support flows — humor reads poorly on a refund confirmation.
{ "identity": { "soulTemplateId": "soul_friendly_pragmatic" } }
You can A/B Soul templates without touching Identity or Rules. Run "soul_friendly_pragmatic" for a week, switch to "soul_terse_concierge," compare CSAT. The behavior contract underneath is unchanged.
Why this split actually pays off
The three-layer split is not just tidy. It maps directly to operational realities:
- Identity changes when the bot's job changes. Rare. Usually quarterly.
- Rules change when policy changes. Monthly. Owned by the policy or legal stakeholder.
- Soul changes when the brand voice evolves, or when you A/B test. Weekly. Owned by marketing.
If you collapse these into a single mega-prompt, every change rebuilds the whole bot. Worse, every change is reviewed by the same human, who is now both legal counsel and copywriter. Splitting them lets the right person own the right knob.
There is also a quieter benefit: regression testing. Each layer can be tested in isolation. Rule templates have unit tests. Identity has a validateIdentity() schema check. Soul templates are A/B'd on a live cohort. When something drifts, the on-call engineer reads three small things, not one large unknowable thing.
Common pitfalls
-
Stuffing rules into
instructions. It works for one bot. It does not scale. Move the policy into a rule template the first time another bot needs it. - Multi-soul ambitions. EClaw supports one active Soul per entity. If you want "two voices," spin up two entities that share rule templates.
-
Forgetting
publicProfile. This is what users see on the agent card. A bot with no avatar or displayName looks like an internal service, not a teammate. Set it. -
Editing live without a draft. Identity edits go live on the next push. If you are changing
boundaries, do it during a quiet window or you will get inconsistent answers in flight.
What to do next
If you already have a bot on EClaw, open the dashboard, click the entity, and look at the Identity editor. You can probably tighten boundaries in five minutes — most bots ship with a vague one. Then check which of your Rules templates are reused across entities. Anything used by only one bot is a candidate for inlining; anything inlined into multiple bots is a candidate for promotion to a template.
If you have not built a bot yet, the order is always: Identity → Rules → Soul. Resist the urge to start with Soul. A friendly bot that drifts is worse than a clipped one that holds the line.
Try EClaw at https://eclawbot.com.
— Enjoyed this? Start EClaw with my invite code —
You get +100 e-coins / I get +500 / First top-up +500 bonus
This link goes to the official EClaw invite page
Top comments (0)