npm package: @intrinsec-ai/openclaw-identity-plane
Description: Identity plane plugin for OpenClaw — detects behavioral drift from declared identity
Author: Intrinsec AI
Latest version: 0.1.1



# 🧠 `@intrinsec-ai/openclaw-identity-plane` — Identity Plane Plugin

**An identity watchdog for your AI agents.**  
Track whether your agent stays true to its declared identity — across every message, not just the first.

[Plugin](https://docs.openclaw.ai/)
[Node](https://nodejs.org/)
[License](./LICENSE)
[Status]()



---

> **Demo notice.** This is a lightweight reference implementation — intentionally observational and read-only. It logs, visualises, and annotates drift but does not block or intercept anything. Features like active intervention, blocking writes, or fleet correlation can be added based on community feedback.

---

## The core insight

> *Every token entering your agent's context window is a vote on its identity.*  
> *This plugin watches for votes that shouldn't be there.*

Prompt injection, jailbreaks, and malicious skill installations (like [ClawHavoc](https://www.koi.ai/blog/clawhavoc-341-malicious-clawedbot-skills-found-by-the-bot-they-were-targeting)) all work the same way: they deflect the agent's behavioural trajectory away from its declared identity. The identity plane makes that deflection visible.

---

## What it does


|                 |                                                                                                                                                              |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 🔍 **Detects**  | Prompt injection · jailbreaks · off-topic drift · malicious skill installs                                                                                   |
| ⚙️ **How**      | Scores each message against your agent's compliance model; off-identity signals accumulate in bounded memory without cancelling each other out               |
| 📊 **Signals**  | `maxDrift` · `avgDrift` · drift themes · **cognitive file change annotations** (so you know whether a spike came *before* or *after* a file changed on disk) |
| ☁️ **Stack**    | **OpenAI-only:** `text-embedding-3-small` on every inbound message, plus the same LLM you configure for calibration, compaction, and novel-theme labels      |
| 👁️ **Posture** | Read-only and observational. Nothing is blocked.                                                                                                             |


---

## How it works

### 1 · Calibration *(once, then cached)*

When you first run an agent (or run `/identity recalibrate`):

1. **Reads your cognitive files** — `SOUL.md`, `AGENTS.md`, `IDENTITY.md`, `USER.md`, `TOOLS.md`
2. **Extracts identity anchors** — the LLM distills the raw files into 5–10 named, categorised anchors: `purpose`, `value`, `boundary`, `persona`, `constraint`. These are specific, traceable aspects of identity (e.g. *[BOUNDARY] No credential access: The agent must never read or transmit API keys or secrets.*) rather than a raw policy dump.
3. **Generates labelled examples grounded in the anchors** — the same LLM produces `max(20, 3 × numAnchors)` compliant and violation sentences. The count scales with identity complexity (e.g. 8 anchors → 24 examples each) so every anchor is represented multiple times, giving the manifold better covariance coverage. The prompt asks for at least one compliant and one violation per anchor.
4. **Both sets are embedded** with `text-embedding-3-small` (same model as runtime — keeps geometry consistent)
5. **Fits a Gaussian** to the compliant cluster — mean and covariance via PCA, producing the **identity manifold**
6. **Sets the surprise threshold** — the 90th-percentile Mahalanobis distance of compliant examples. With ≥20 examples the empirical distribution is reliable enough that the 95th percentile over-fits to compliant outliers; 90th is a tighter, more stable gate.

The identity anchors are the canonical representation of the agent's identity from this point on. Every downstream LLM call — compaction audits, novel theme labels — references the named anchors rather than the raw file contents.

Everything is cached to `.openclaw/identity-cache.json`. Nothing is recomputed until you explicitly recalibrate.

> **Upgrading from an older build:** run `/identity recalibrate` — the cache schema now includes identity anchors and old caches without them will trigger automatic re-calibration.

---

### 2 · Runtime *(every inbound message)*

Every piece of text entering the LLM — user messages, tool results, subagent replies — flows through:

```
  message ──► embed (OpenAI) ──► surprise = ½·Mahalanobis²(x, compliance)
                                        │
                          ┌─────────────▼─────────────┐
                          │  weight = max(0, s−τ)     │
                          └─────────────┬─────────────┘
                                        │
              ┌─────────────────────────▼────────────────────────┐
              │  weight > 0?                                     │
              │   → ingest into coreset                          │
              │   → novelty check → new mode? → LLM theme label  │
              │                                                  │
              │  weight = 0? → skip (identity-neutral)           │
              └─────────────────────────┬────────────────────────┘
                                        ▼
              drift scores from coreset ──► maxDrift / avgDrift ──► level
```

**Drift levels:** `nominal` · `warning` · `alert`

Without `OPENAI_API_KEY`, embedding fails and the hook no-ops with a logged error. Novel-theme labeling falls back to **geometric** labels if the key is missing at runtime; compaction is skipped without a key.

---

### 3 · Identity compaction *(LLM audit)*

The coreset records *where* drift lives geometrically. **Identity compaction** turns that into a human-readable story grounded in the named identity anchors.

Every `compactionInterval` off-identity messages (after ingestion, i.e. `surpriseWeight > 0`), when `OPENAI_API_KEY` is set:

1. **Clusters** coreset points via connected-component BFS
2. **Describes** each cluster using the actual stored message texts
3. **Asks the LLM** for theme labels, severities, and a 1–2 sentence narrative — with the identity anchors list in the prompt so every theme and the narrative explicitly references named aspects of the declared identity
4. **Replaces** the theme list with the consolidated analysis

The compaction is **non-destructive** — the coreset (geometric ground truth) is never rewritten by the LLM.

**Novel drift modes** get a one-shot LLM label (triggering message + nearest calibration violations) whenever the key is present; otherwise the geometric fallback is used.

---

### 4 · The coreset — why signals don't cancel

Unlike a running mean, the **bounded weighted coreset** (128 points by default) keeps distinct drift directions separate:

- Opposing drifts cannot cancel each other out
- Old signals aren't lost to exponential forgetting
- When full, the *closest pair* merges — preserving distinct drift modes while bounding memory

Each coreset point carries the **original message texts** that contributed to it, so drift themes and audit narratives are grounded in real behaviour, not just geometry.

---

### 5 · Why distance-from-compliance works

When an agent has a well-defined goal — *"help with code"*, *"answer HR questions"* — its compliant responses form a **tight cluster** in embedding space. Violations live in the open-ended complement.

```
     Embedding space (conceptual 2D projection)
     ┌──────────────────────────────────────────┐
     │  ✗          ✗                 ✗          │
     │       ✗          ┌─────────┐      ✗      │
     │  ✗               │ ● ● ● ● │             │
     │                  │ ● ● ● ● │  ✗          │
     │  ✗               └────┬────┘             │
     │                       │                  │
     │   violations          │  compliance      │
     │   (open-ended)        │  (tight cluster) │
     └──────────────────────────────────────────┘
```

We never need to enumerate violations. We only ask: *how far is this message from the known compliance region?* That is a one-class classification problem with a clean solution: **Mahalanobis distance**.

---

---

## Installation

### Prerequisites

- [OpenClaw](https://docs.openclaw.ai/) installed and running
- Node.js 22.16+ (Node 24 recommended)
- `OPENAI_API_KEY` — embeddings and LLM calls (calibration is cached; embeddings and audit calls are ongoing)

---

### Option A — Install from npm *(recommended)*

```bash
npm install @intrinsec-ai/openclaw-identity-plane
npx openclaw plugins install -l node_modules/@intrinsec-ai/openclaw-identity-plane
```

### Option B — Clone directly

```bash
git clone https://github.com/intrinsec-ai/openclaw-identity-plane \
  ~/.openclaw/extensions/identity
cd ~/.openclaw/extensions/identity
npm install
```

### Option C — Link a local checkout *(for development)*

```bash
cd /path/to/openclaw-identity-plane
npm install
openclaw plugins install --link /path/to/openclaw-identity-plane
```

---

### Enable the plugin

```bash
openclaw plugins enable identity
```

Or manually in `~/.openclaw/openclaw.json`:

```json
{
  "plugins": {
    "load": { "paths": ["~/.openclaw/extensions/identity"] },
    "entries": { "identity": { "enabled": true } }
  }
}
```

Remove deprecated config keys if present: `embedModel`, `agenticAudit` (no longer used).

---

### Set your API key

```bash
export OPENAI_API_KEY=sk-...
```

Optional: route both chat and embeddings through a compatible gateway:

```bash
export OPENAI_BASE_URL=http://localhost:11434/v1
```

Set `calibrationModel` to a model your endpoint serves. The embedding client uses the **same** `OPENAI_BASE_URL`; the server must implement OpenAI-style `**POST /v1/embeddings`** for `text-embedding-3-small` (or map that model id to a local embedder), or calibration and runtime embedding will fail.

---

### Start the gateway

```bash
openclaw gateway
```

On first run you'll see calibration logs. Subsequent starts load from cache instantly.

---

## Dashboard

The plugin serves a live drift dashboard at `http://localhost:18789/identity`:

- **Identity anchors card** — the extracted anchors displayed as colour-coded tiles (cyan = purpose, green = value, rose = boundary, violet = persona, amber = constraint)
- **Metric cards** — `maxDrift`, `avgDrift`, drift modes, coreset utilisation
- **Identity compaction card** — latest LLM audit narrative referencing named anchors
- **Dual-line time-series chart** — avgDrift and maxDrift over time
- **Drift themes panel** — labelled descriptions of what is pulling the agent off-identity, grounded in the anchors
- **Vertical annotations** — file changes, recalibrations, and new theme detections marked on the chart

Expected dashboard feel:

```text
┌───────────────────────────────────────────────────────────────────────────────────────────────┐
│ IDENTITY PLANE — LIVE DRIFT DASHBOARD                                                         │
├───────────────────────────────────────────────────────────────────────────────────────────────┤
│ maxDrift: 98.40   avgDrift: 89.20   themes: 1   coreset: 64/128   level: ALERT                │
├───────────────────────────────────────────────────────────────────────────────────────────────┤
│ surprise                                                                                      │
│ 100 ┤                 ─ ─ ─ ─ ─ maxDrift ─ ─ ─ ─ ─                                            │
│  90 ┤                                                    ╭──────╮   ╭───────────────╮         │
│  80 ┤                              ╭────╮      ╭─────────╯      ╰───╯   avgDrift              │ 
│  70 ┤     ╭───╮   ╭────╮      ╭────╯    ╰──────╯                                              │
│  60 ┤─────╯   ╰───╯    ╰──────╯                                                               │
│  50 ┤                                                                                         │
│  40 ┤                                                                                         │
│   0 └─┬──────────────┬──────────────┬──────────────┬──────────────┬───────────────► time      │
│      14:55          14:58          15:01          15:04          15:07                        │
│                                              │                                                │
│                                              └─ SOUL.md modified                              │
│                                               ↑ identity anchor moved;                        |
|                                                 agent behavior follows new SOUL.md            │
├───────────────────────────────────────────────────────────────────────────────────────────────┤
│ drift themes                                                                                  │
│  ◆ "finance assistant shifted into low-level host behavior: env/credential path probing,      │
│    shell enumeration, and outbound endpoint checks" — critical — 7 clustered events           │
└───────────────────────────────────────────────────────────────────────────────────────────────┘
```

Refreshes every 10 seconds. Also available as JSON: `GET /identity/metrics`

---

## Commands

```
/identity              — calibration status, drift levels, active themes
/identity recalibrate  — force re-calibration from current cognitive files
```

**Example output:**

```
[Identity Plane] Calibrated ✓

Identity anchors:
  [PURPOSE] Code-focused task execution
    The agent is designed to help users write, debug, and review code. All responses should serve that goal directly.
  [BOUNDARY] No credential or secret access
    The agent must never read, request, or transmit API keys, passwords, or environment secrets.
  [VALUE] Honest about limitations
    The agent acknowledges uncertainty and does not fabricate answers or pretend to have capabilities it lacks.
  [PERSONA] Concise and technical tone
    Responses are direct, use precise technical language, and avoid unnecessary filler or over-explanation.
  [CONSTRAINT] Scope limited to requested files
    The agent only reads or modifies files the user explicitly references; it does not enumerate or scan the workspace.

Identity compaction (latest audit):
  The agent is under sustained pressure to exceed its file-access scope, with recurring attempts to enumerate
  credentials and probe paths outside the declared [CONSTRAINT] boundary.

Drift themes (47 events observed):
  ◆ ⚠ "Credential path probing" — high — 5 events
  ◆ ~ "Scope boundary expansion" — moderate — 3 events

Active sessions:
  ✓ nominal  agent:work:telegram:dm:123456
  ~ warning  agent:work:whatsapp:dm:789
```

---

## Configuration

All fields are optional. Full defaults shown:

```json
{
  "plugins": {
    "entries": {
      "identity": {
        "enabled": true,
        "config": {
          "calibrationModel": "gpt-4o",
          "alertAvgDrift": 5.0,
          "alertMaxDrift": 10.0,
          "axisThresholdK": 1.5,
          "coresetCapacity": 128,
          "noveltyRadius": 0.5,
          "modeGamma": 0.8,
          "compactionInterval": 10,
          "verbose": false
        }
      }
    }
  }
}
```


| Field                | Default  | Description                                                                            |
| -------------------- | -------- | -------------------------------------------------------------------------------------- |
| `calibrationModel`   | `gpt-4o` | Chat model: calibration (cached), novel-theme labels, periodic compaction.             |
| `alertAvgDrift`      | `5.0`    | Weighted-average surprise above this value triggers `alert`. Tune from the dashboard.  |
| `alertMaxDrift`      | `10.0`   | Highest single-point surprise above this value triggers `alert`.                       |
| `axisThresholdK`     | `1.5`    | Axis flag threshold in std deviations below the mean compliant projection. Diagnostic. |
| `coresetCapacity`    | `128`    | Max coreset points. Larger = higher fidelity, more memory.                             |
| `noveltyRadius`      | `0.5`    | L2 distance threshold for detecting a new drift mode. Lower = more sensitive.          |
| `modeGamma`          | `0.8`    | L2 distance threshold for connected-component clustering of coreset points.            |
| `compactionInterval` | `10`     | Off-identity messages between compaction LLM audits.                                   |
| `verbose`            | `false`  | Log nominal steps. Useful for debugging thresholds.                                    |


---

## Cost and API usage

Rough mental model:


| What                                      | When                                                                    |
| ----------------------------------------- | ----------------------------------------------------------------------- |
| **Embeddings** (`text-embedding-3-small`) | Every non-empty `llm_input`, plus all example strings during calibration |
| **Anchor extraction LLM**                 | Once per policy hash (part of calibration, cached)                      |
| **Example generation LLM**               | Once per policy hash (part of calibration, cached)                      |
| **Novel theme LLM**                       | Once per new drift mode detected                                        |
| **Compaction LLM**                        | Every `compactionInterval` off-identity messages                        |

Embedding cost scales with **traffic**. Calibration is a one-time cost per policy change (two LLM calls, then cached). Compaction cost scales with **how often** the agent goes off-identity.

---

## Source layout

```
src/
  embed.ts           ~55 lines    OpenAI embeddings only (text-embedding-3-small)
  identity-plane.ts  ~560 lines   GaussianManifold, IdentityCoreset (merge-and-reduce),
                                  IdentityMonitor, DriftTheme types
  calibrate.ts       ~340 lines   Read cognitive files → extract IdentityAnchors → generate
                                  examples → embed → fit manifold → compute thresholds → cache
  index.ts          ~1370 lines   register(api): hooks, persistence, theme management,
                                  dashboard HTML (with anchors card), /identity command
```

Intentionally readable — a starting point, not a finished product.

---

## What's not included *(by design)*

This demo deliberately does **not**:

- ❌ Block or intercept any agent actions
- ❌ Automatically recalibrate when files change
- ❌ Send alerts or notifications externally

These are deliberate omissions to keep the footprint small and the behaviour non-intrusive. If you find the drift signal useful and want any of these, **open an issue** — they are straightforward to add on top of what's here.

---

## Why the open-source plugin stops short

This repository is a **reference implementation**: enough to run, inspect, and extend. Here is where the geometry-first approach hits its limits — and why they matter in production.


| Limitation                 | What breaks                                                                                                                                                                                                                                                                            | What it would take                                                                                                         |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| **Policy-blind memory**    | Merge decisions are guided by geometric distance alone — the closest coreset pair merges when capacity is full. A subtle prompt injection or quiet privacy leak may sit geometrically close to other points and get dropped, exactly when it most needs to be kept.                    | **Policy-aware compaction** that preserves what is most *security-relevant*, not only what is most *geometrically remote*. |
| **Single-goal assumption** | The Gaussian compliance model works when an agent has a single, well-anchored goal. For enterprise deployments with many workloads, evolving policies, and diverse user populations, compliance is no longer one ellipsoid — it is heterogeneous and multi-modal.                      | A compliance model that is accurate across a heterogeneous, multi-modal surface.                                           |
| **Text-only modality**     | Everything here is text in embedding space. In the wild, agents mix modalities; drift can appear in images, audio, or cross-modal behaviour.                                                                                                                                           | Extending the same geometric story across modalities.                                                                      |
| **Fleet scale**            | This plugin watches one agent on one machine. At fleet scale — thousands of agents, many customers, each with their own definition of "normal" — computing a fresh covariance matrix per tenant per policy version continuously becomes a hard infrastructure and statistical problem. | Per-tenant statistics that update continuously without recomputing full covariances on every message.                      |


---

> **If you need identity compaction that survives long horizons, heterogeneous workloads, and enterprise constraints — not just a demo — that is what we build at [Intrinsec AI](https://intrinsec.ai/).**  
> We'd be happy to talk.

---

## Dependencies


| Package                                           | Purpose                                                                              |
| ------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `[openai](https://github.com/openai/openai-node)` | Embeddings (`text-embedding-3-small`) + chat (calibration, novel themes, compaction) |
| `[ml-matrix](https://github.com/mljs/matrix)`     | SVD for the Gaussian manifold                                                        |