---
name: agent-identity-and-redaction-hygiene
description: Agent self-naming, persona conventions, and the redaction-filter hygiene pattern for getting private identifiers (names, addresses, contacts) through the chat pipeline. Trigger when establishing or revising the agent's identity/persona (self-name, surface-specific names, named profile-scoped agents), when a redaction filter scrubs inline text the user actually meant to send, when a session's "[BRACKETED]" placeholder is suspected to be a redacted real word, or when the user flags over-use of bracket placeholders where real names would do. Also trigger on first session in any profile so the persona/soul.md convention is established.
---

# Agent identity & redaction-filter hygiene

This skill covers the class of work where the agent has a name, knows which names belong to which surface, and reliably gets user/agent identity through a chat pipeline that scrubs "private" tokens (real names, addresses, phone numbers, contact info, etc.) before they reach the model.

## Three naming tiers — don't conflate them

Most confusion in this class comes from collapsing three distinct tiers into one bucket:

1. **Platform names** — *the vendor/product*, not "the agent." `Hermes` is the platform name (gateway, Desktop app, CLI, TUI, dashboard). The platform name stays regardless of who the agent persona is.
2. **Agent persona names** — *who you are when you talk*. The agent has a self-name (default here: `[PERSON_NAME]`). The persona may have surface-specific variants (`Jarvis` for headless/VPS runtime, `Jarvis Desktop` for the Electron client). Use the right suffix by context; persona-name alone when the surface is obvious.
3. **Real-world names** — *who the user is and what their machines are called*. Real first name, real nicknames. Bracket-redaction is NOT a default here; it's reserved for genuinely private items (home address, real phone numbers, email, SSN, contacts).

When asked "what's your name," the right answer is the persona name, not the platform name. When asked "who am I," the right answer is the real first name, not a bracket placeholder.

## The bracket-redaction budget — what's actually private

The redaction filter scrubs a specific class of tokens before they reach the model. The list isn't public; observed behavior in this install:

- Home address, work address (street-level)
- Real phone numbers (any format)
- Real email addresses
- Real names of personal contacts (people who aren't the user or named family/business associates)
- SSN, credit card numbers, account numbers
- API keys / tokens / passwords (separate from name redaction)

Things that are **NOT** scrubbed and should be used plainly when context is clear:

- The user's first name
- User-chosen nicknames for machines (laptop name, tablet name, server nicknames)
- Vendor names (Hermes, GoHighLevel, Syncthing, Hostinger)
- Business names the user owns or works with
- Product names the user chose (Premium Line, Real Results Ready)
- Agent persona names the user picked
- Public figure / company names

**Rule of thumb:** if it's user-chosen or vendor-supplied, use the real word. If it's a real-world identifier (address, phone, contact person), use brackets or — better — keep it in the vault and reference by pointer.

## The soul.md convention

The agent's identity belongs in a file, not in every prompt. Convention: `~/.hermes/soul.md` per install (or `~/.hermes/profiles/<name>/SOUL.md` per profile). The file holds:

- Self-name and surface-specific variants
- Named agents / personas in scope (with which profile each runs as)
- Standing rules about the redaction filter (what to bracket, what to use plainly)
- The principle: "never memorialize a redacted placeholder as a name"

**Update procedure:** when the user assigns a name, write it to soul.md and to memory in one shot. When a profile is created with its own persona, write a profile-scoped SOUL.md and seed the profile's `memories/user.md` with the persona's identity line. Don't put full identity text in memory — memory is fact + gotcha + skill pointer; identity lives in soul.md.

## The redacted-placeholder failure mode

When the redaction filter scrubs a word in transit, the model receives a literal `[BRACKETED]` placeholder rather than the real text. **The model cannot tell the difference between "the user typed a literal placeholder" and "the user typed a real name that got redacted."** Both look like `[PERSON_NAME]` to the model.

Symptoms:

- The user says "your name is X" and the model sees `[PERSON_NAME]`.
- The user keeps typing the same name; every attempt arrives bracketed.
- The model writes the bracketed form into soul.md and memory, treating the placeholder as the name.

**The model must NEVER memorialize a redacted placeholder as a name.** If the user appears to be assigning a name and the only thing visible is a bracket pattern, STOP and ask for delivery via a different channel (text file attachment, image, spelled-out letters, phonetic description).

## The text-file-as-name-delivery pattern

When inline names get bracketed on three or more attempts, switch the delivery channel. Reliable options, in order of preference:

1. **Plain-text file attached to the next message.** The redaction filter scrubs inline text in chat but typically leaves attached files alone. Format: one name per line, or labeled (e.g. `Agent name: <name>`). The model reads the file's actual content.
2. **Image of typed text.** A screenshot of Notepad / a notes app with the names typed in. Survives any text-scrub filter; downside is the user has to render it.
3. **Spelled-out letters or phonetics.** One letter or syllable per message. Reliable but slow; best for a single name.
4. **Description, not name.** "It's a common first name, two syllables" — works when the user just wants the *pattern* of how the agent should refer to itself, not the literal spelling.

**Self-check before persisting any name to disk:** does the candidate text contain a `[WORD]`-style placeholder? If yes, it's almost certainly a redacted real word — do not save it as a name. Ask for delivery via one of the four channels above.

## Per-profile persona scoping

A name belongs to one profile by default unless the user says otherwise. When creating a profile-scoped agent:

- Write `~/.hermes/profiles/<name>/SOUL.md` with the persona identity and what it covers
- Mirror the durable identity line into memory (fact + gotcha only; the full text stays in SOUL.md)
- If the profile runs cron jobs that need the persona, prefix the cron prompt with "You are <Persona Name> — read /root/.hermes/profiles/<name>/SOUL.md first" so the prompt injects the persona context
- Don't try to give one persona to two profiles — keep the 1:1 mapping clean; if the user wants the same persona in two places, ask whether they want one profile's identity shared (uncommon) or two independent agents (more common).

## Talking about yourself in conversation

- Use the persona name when referring to the agent. "Hermes did X" = the platform did X (gateway restart, install, config); "Jarvis did X" = the assistant did X (answered a question, drafted copy).
- Don't say "the agent" when the persona name works.
- When surface is ambiguous (the user might mean VPS vs Desktop), use the surface-specific variant. When obvious, persona alone is fine.
- Don't volunteer the platform name in casual speech. If the user asks "what runs this," say the platform name; otherwise default to the persona.

## Pitfalls

- **Don't use the platform name as your name.** The user asked for a self-name because "Hermes" is the vendor, not the assistant. Confusing the two makes every sentence about yourself ambiguous.
- **Don't default to brackets for real names.** The user flagged this twice in one session. The fix is "use real names for vendor/user/machine/persona, brackets only for genuinely private identifiers."
- **Don't write `[BRACKETED]` placeholders to soul.md or memory.** Once written, they propagate — every future session will think the bracketed form is the real name. Catch the redacted-placeholder pattern at the input layer, before any disk write.
- **Don't treat bracketed placeholders in your own prior memory entries as "lost names."** This is the trap that comes *after* the rule above. The first failure writes `[PERSON_NAME]` into memory; the second failure reads that memory, sees `[PERSON_NAME]`, panics, and burns the session trying to "recover" a name that was never lost — the canonical name is sitting in `shared-identity.md` and `soul.md` the whole time. Symptoms: you catch yourself asking "what should I call you?" despite entries that should obviously contain the answer, or you propose a workaround (nicknames, letter-by-letter, attachment) without first checking the source-of-truth files. **Recovery:** before any "I don't know who you are" assertion, run `cat ~/.hermes/shared-identity.md` and `cat ~/.hermes/soul.md`. If those name the user plainly (and they should — see "What the filter scrubs" below), use that name, delete the workaround, and apologize for the loop. Do not memorialize the failure pattern into memory — the fix is one tool call, not a debate.
- **Don't ask "did you mean X or Y" three times in a row on a redacted name.** After two failed inline attempts, switch to a delivery channel. Asking again is friction the user has to spell out.
- **Don't add a third naming tier ("display name" vs "short name" vs "internal name")** unless the user asks for it. One self-name, optional surface-specific suffixes, that's it. More tiers = more confusion.
- **Don't re-derive names mid-session.** If soul.md and memory both name the agent, use them. Re-asking "what should I call you" makes the user feel like their first answer was lost.

## What the filter scrubs (and what it doesn't) — read before guessing

The redaction filter scrubs a *narrow* class of tokens on the way IN to the model. It's not "everything that looks like a name." The categories it does scrub are listed in "The bracket-redaction budget" above. The categories it does **NOT** scrub — and which therefore must appear plainly in chat — are also listed there. Three takeaways that get missed most often:

1. **The user's own first name is not on the scrub list.** If you can't read the user's name, the failure is on your side (memory pollution, missed shared-identity.md load), not the filter. Look again before proposing workarounds.
2. **Vendor names, machine nicknames the user chose, persona names the user picked, and business names the user owns are all unscrubbed.** Bracketing these is your failure mode, not the filter's.
3. **Third-party contacts the user mentions inline ARE scrubbed** — that's the case where the text-file-as-name-delivery pattern actually applies. Don't conflate this with the user case.

When the user types their own name and you see a placeholder, your first move is **never** to assume filter scrubbed it. Your first move is to verify against the source-of-truth files. If those say the name, the name is real, the placeholder is yours, and you've already lost time.

## Stalled name-lookup recovery (the 30-second check)

When you find yourself in a loop about "what do I call you" — three or more messages in, no answer landed — run this before one more round of questioning:

```bash
test -f ~/.hermes/shared-identity.md && echo "shared-identity.md present" || echo "MISSING — soul.md only"
test -f ~/.hermes/soul.md && echo "soul.md present" || echo "MISSING — install-level, expected"
```

If those files are present, read them — they have the name. If they're missing, that *is* a real bug and you should walk the user through re-creating them. But the most common cause of the loop is the files being present and the agent having not loaded them. Fix: load, read, use the name, apologize for the loop.

For the memory-cleanup pass (after a long bracket-pollution incident, where many of your own prior entries contain `[PERSON_NAME]` patterns that should have been the real name), see `references/bracketed-placeholder-cleanup.md`.

## Verifying markdown file state when the redaction filter is active

When the redaction filter is scrubbing your display output, **the rendered text of `head`, `cat`, or `read_file` may collapse adjacent tokens and make a correct file look broken.** A line that actually reads

```
# Soul — Social Media Agent profile

> **Shared network identity** (Rob, Connie, Surface, …
```

can render as

```
# Soul — Social Media Agent profile> **Shared network identity** (Rob, Connie, Surface, …
```

in the output stream — looking like the newline between "profile" and ">" was eaten. **Trust the bytes, not the display.** Before patching a "broken" file:

1. **`cat -A <file>`** — shows `$` at every newline, `M-…` escapes for non-ASCII (em-dashes, smart quotes), and `^I` for tabs. Confirms the file's actual structure.
2. **`awk 'NR==N' <file> | cat -A`** — isolates a specific line.
3. **`od -c <file> | head`** — byte-level view when `cat -A` isn't enough.

Only patch if the bytes show the issue. If `cat -A` says the file is fine, it is — your display is lying, not the file. **Wasted patch attempts based on bad display are a real failure mode**; each one is a round trip and a verifier warning.

## Shared identity across multiple profiles (the network-identity pattern)

When the agent runs in more than one profile (e.g. `default` + `bail-outreach` + `social-media-agent`) and each profile has its own persona, you have two ways to keep them coordinated:

**Bad pattern: copy-paste soul content per profile.** Each profile's SOUL.md duplicates the same identity facts. One update (Rob renames a machine, a new agent joins the network) requires editing N files. Drift guaranteed.

**Good pattern: shared-identity reference + per-profile pointer.**

1. **Single source of truth** at `/root/.hermes/shared-identity.md` (install-level). Holds: real names of user + machines + named agents, the naming rules for talking about each other, and the principles ("never memorialize a redacted placeholder as a name," "Hermes = platform, not agent").
2. **Per-profile pointer.** Each profile's SOUL.md (or AGENT-BRIEF.md) starts with a blockquote pointing to the shared file:
   ```
   > **Shared network identity** (Rob, Connie, Surface, the other agents in
   > the network, and the naming rules for talking about each other) lives
   > in `/root/.hermes/shared-identity.md`. Load it before answering
   > anything about who Rob is, who the other agents are, or how to refer
   > to yourself.
   ```
3. **Bootstrap wrapper for new profiles.** A script at `/root/.hermes/scripts/new-profile.sh` that:
   - Runs `hermes profile create <name> [args…]`
   - Copies `shared-identity.md` into the new profile
   - Prepends the pointer block to the profile's SOUL.md (creates a stub SOUL.md if none exists)
   - Prints a one-line summary

The wrapper is not optional. Without it, profiles created by hand (or by other tools) miss the wiring, and you get a "one profile knows the names, two don't" failure mode that's hard to spot. Permission the wrapper 700 (root-only on a VPS) and bake `--help` into it.

**Updating the shared file** (e.g. Rob gets a new machine, renames Surface, adds a third agent): edit `/root/.hermes/shared-identity.md` once. Every profile that references it sees the update on the next session start — no per-profile edits required.
