openclaw-ai-passport
v0.1.0
Published
AI Passport memory for OpenClaw: owner-approved Passport memories as an additive memory corpus and per-turn context.
Downloads
162
Maintainers
Readme
openclaw-ai-passport
AI Passport as an OpenClaw memory backend: the owner's approved Passport
memories reach the agent as per-turn context and as a searchable corpus, over
the agent-backend plane (POST /agent/prefetch, issue #425).
Installing this plugin grants no read access by itself. Rows come back only for
governed categories the owner already approved a pass for; everything else
comes back as a skip that tells the model to escalate through the MCP recall
tool, which is the surface that can actually request approval.
What it registers
| Surface | OpenClaw seam | When it runs |
| --- | --- | --- |
| Per-turn context | before_prompt_build hook | every agent turn |
| Memory corpus | api.registerMemoryCorpusSupplement | memory_search / memory_get with corpus: "all" |
| Tool-call audit | before_tool_call hook | every tool call |
Corpus supplements are consulted only when the model passes corpus: "all" (or
"wiki"); they are not part of a default memory_search. That is why the
ambient path is the prompt hook and not the corpus: the corpus is for when the
agent goes looking, the hook is for every turn.
The plugin never claims the memory slot (plugins.slots.memory), so
memory-core, MEMORY.md, daily notes, and dreaming keep working exactly as
before. Passport is additive.
Writes are not this plugin's job. Saves keep flowing through the MCP tools
(remember / propose_memory) into the owner's review inbox.
The tool-call policy surface has two postures, decided by the owner per app:
- Audit (the default): the hook reports each tool call's NAME plus a
sha256 digest of its arguments (never the arguments) to
POST /agent/policy/check, which is what puts tool activity on the owner's AI Passport activity page. It fires and forgets, never awaits the network, never rewrites params, and never blocks. Identical calls are deduped for the answer's TTL so a tool-calling loop costs one report a minute. - Enforce: the hook awaits the verdict. A denied tool blocks with the rule
that denied it. A tool needing approval blocks the call while the owner is
asked (their AI Passport inbox gets the wait, their phone gets a push) and
the hook polls the decision for up to
policy.approvalWaitMs; allow-once runs the tool, allow-always also writes a standing rule server-side, deny and expiry block with an honest reason. If the Passport stops answering, the LAST KNOWN rules are evaluated locally: fail closed exactly for the tools the owner constrained, fail open for everything else.
Either way, OpenClaw's own exec approvals stay untouched: this plane can only tighten, never grant.
Install
openclaw plugins install openclaw-ai-passport
openclaw plugins enable ai-passportThe plugin id is ai-passport; the npm package is openclaw-ai-passport. If
your openclaw.json sets plugins.allow, add ai-passport there too, or the
loader will fail closed and never run it.
Credentials come from the connect-code install at
ego.ist/openclaw, which writes
~/.openclaw/ai-passport-refresh.json (mode 600) with token_url,
client_id, and refresh_token. The plugin reads that file, refreshes the
access token when it is within five minutes of expiry, persists the rotated
refresh token back, and reconciles the ai-passport MCP server entry's bearer
header on every read. The plugin must be the install's only refresher. Reusing
a spent token after the five-minute recovery window revokes only that token
family. The server returns the exact prior response for a same-transport replay
inside the window.
Configuration
Everything is optional.
{
plugins: {
entries: {
"ai-passport": {
enabled: true,
config: {
categories: ["preference", "fact", "project", "instruction"],
context: { enabled: true, limit: 6, maxChars: 2000, timeoutMs: 1500, sendPromptAsQuery: true },
search: { enabled: true, limit: 10, timeoutMs: 5000 },
policy: { enabled: true, timeoutMs: 2000 },
cacheTtlMs: 60000,
},
},
},
},
}| Key | Default | Notes |
| --- | --- | --- |
| credentialsPath | $OPENCLAW_CONFIG_DIR/ai-passport-refresh.json | written by the install guide |
| baseUrl | origin of token_url | only needed to point at a non-paired host |
| mcpServerName | ai-passport | which MCP entry to keep in sync |
| syncMcpEntry | true | set false to leave the MCP bearer to the agent |
| categories | preference, fact, project, instruction | governed vocabulary only |
| cacheTtlMs | 60000 | one backend call per minute per distinct query |
| context.sendPromptAsQuery | true | false sends no query and gets most-recent rows |
| context.includeRecent | true | also read the most recent rows and merge them behind the query matches |
| context.maxChars | 2000 | hard cap on the injected block |
| context.timeoutMs | 1500 | ambient reads sit on the turn's critical path |
| search.timeoutMs | 5000 | memory_search's own deadline is 15s |
| policy.enabled | true | report tool-call names (never arguments) to the owner's activity feed |
| policy.timeoutMs | 2000 | budget per policy request; audit mode never awaits it |
| policy.approvalWaitMs | 120000 | how long an enforce-mode call waits on the owner before blocking with the approval link |
To turn off prompt injection without touching plugin config, set
plugins.entries.ai-passport.hooks.allowPromptInjection: false; core then
blocks before_prompt_build and only the corpus surface remains.
Failure behavior
The plugin fails open for memory. It never throws into OpenClaw: a rejected
corpus supplement fails the agent's entire memory_search, and a rejected
prompt hook costs the turn.
| Condition | Behavior |
| --- | --- |
| Passport unreachable, timeout | serve the last good answer, else nothing |
| 429 rate_limited | back off 60s, serve cached |
| 403 (plane closed, or not an agent-backend client) | back off 5 min, warn once |
| 401 | one forced refresh and one retry, then back off 60s |
| refresh token spent (400 invalid_grant) | stop calling, tell the owner to reinstall with a new connect code |
| credentials file missing | stop calling, report not installed |
Warnings are emitted once per backoff window, not once per turn.
Development
npm testThe tests are plain node --test with no dependencies; src/index.js is a
shim holding the only import that needs OpenClaw resolvable, so everything else
is covered without vendoring the host.
fixtures/agent-prefetch-response.json is the shared response contract:
scripts/agent_backend_smoke.mjs in the passport repo asserts the backend
still produces that shape, and the plugin tests assert this client still parses
it.
The npm name openclaw-ai-passport is confirmed (2026-08-11); the package is
not published yet. The packaged shape is proven the way the OpenClaw docs ask
for, because a path install does not exercise the same dependency resolution:
npm pack --pack-destination /tmp
openclaw plugins install npm-pack:/tmp/openclaw-ai-passport-0.1.0.tgz --force
openclaw ai-passport statusPublishing also means flipping NEXT_PUBLIC_PASSPORT_OPENCLAW_PLUGIN on the
marketing deploy, which is what puts the plugin steps into the public install
guide at ego.ist/openclaw.
Pinned against OpenClaw 2026.7.1-2. OpenClaw ships several releases a week and
publishes a deprecation calendar; re-verify registerMemoryCorpusSupplement
and the before_prompt_build result fields on every minor.
