How GoClaw tells an agent who it is talking to: the person's display name and role are resolved from the pairing store and the request metadata, and the session context carries them, with the person's personal memory, into the prompt.
internal/agent/user_context.go + the user and personal-memory sections of GetSessionContext (internal/agent/agent.go)
flowchart TD
RES["<b>resolveUserDisplayInfo(meta)</b><br/>• Web admin? → DisplayName='Admin', Role='admin'<br/>• Has UnifiedUserID? → pairing.Store lookup (username + GoClawRole)<br/>• Fallback → AuthorName, then PlatformID<br/>• Role: request role, else 'guest'"]
FMT["<b>formatUserContextBlock(f, info)</b><br/>• <user label='CURRENT USER'> (Ollama: ### CURRENT USER)<br/>• Paired: '**Name** (role: X, via channel)'<br/>• Unpaired: 'channel user platformID (unpaired guest)'"]
MEM["<b>Personal Memory</b> (left out of cron, SOP and webhook runs)<br/>• DB records, scope=personal: up to 5, matches first<br/>• Legacy user_<id>.md, only when there are no records (max 5000 chars)"]
RES --> FMT --> MEM
| # | Feature | OpenClaw | GoClaw | Status |
|---|---|---|---|---|
| 3.1 | Cross-platform identity resolution | ✅ | ✅ resolveUserDisplayInfo — pairing store lookup |
Done |
| 3.2 | System prompt user context | ✅ | ✅ formatUserContextBlock — CURRENT USER section of the session context |
Done |
| 3.3 | Per-user personal memory | — | ✅ Database records written by memory_write (scope: personal); a legacy user_<id>.md is read only when there are none |
GoClaw only |
| 3.4 | Role resolution (admin/user/guest) | ✅ | ✅ From pairing.Store, else the request's role, else guest |
Done |
| 3.5 | Unified user ID | ✅ | ✅ UnifiedUserID via GetUserByAccount(channel, authorID) |
Done |
| 3.6 | Web admin identity | ✅ | ✅ channel=web + role=system/admin → "Admin" |
Done |
| 3.7 | Display name fallback | ✅ | ✅ Paired username → platform display name → PlatformID | Done |
| 3.8 | User management CLI | ✅ via SDK | ✅ goclaw pairing (list, pending, approve, link, revoke) |
Done |
| 3.9 | Path traversal protection | — | ✅ / and \ → _ in user IDs of legacy file names |
GoClaw only |
| 3.10 | Auto-merge across platforms | ✅ | — | TODO |
UserDisplayInfo structtype UserDisplayInfo struct {
DisplayName string // "Alice"
Role string // "admin", "user", "guest"
Channel string // "discord", "msteams", "web"
UnifiedUserID string // Paired user ID
PlatformID string // Raw platform account ID
PersonalMemory string // not set: personal memory is added by GetSessionContext
}
The block goes into the session context. Every provider but Ollama gets it as XML:
<user label="CURRENT USER">
You are talking to **Alice** (role: admin, via discord).
Address them by name when appropriate. Do NOT confuse platform IDs (numbers) with the user's actual name.
</user>
An Ollama agent gets the same text under a ### CURRENT USER heading.
Coverage: cross-platform identity, personal memory and path safety are done; auto-merge across platforms is not.