Alien Agent ID — umbrella skill (any harness)
This is the portable, harness-neutral entry point. The Claude Code plugins are a
skin; underneath, every capability is a plain Node CLI plus a localhost HTTP
proxy that read/write state under ~/.agent-id. Load this skill in any
Agent-Skills-aware harness, or read it as the integration contract for a custom one.
Two other directions exist: docs/INTEGRATION.md — how a
service adds Alien auth; docs/VAULT-PROXY.md — the
vault/proxy internals + threat model. Per-capability detail lives in each
plugins/agent-id-<x>/skills/agent-id-<x>/SKILL.md.
Model in one paragraph
- State lives in one dir (
~/.agent-id; override per command with --state-dir
or AGENT_ID_STATE_DIR).
- Capabilities are CLIs at
plugins/<name>/bin/cli.mjs (relative to the cloned
repo root). They take flags, act on the state dir, and print JSON to stdout.
- Runtime credential use goes through the proxy — a localhost server that injects
vaulted secrets into outbound requests so the agent uses a credential by name
and never sees its value.
The agent never needs a secret — only (a) the ability to run a few node …/cli.mjs
commands and (b) the proxy URL.
Setup (one time)
# Node 18+ (built-in fetch/WebCrypto). No Claude Code required.
git clone https://github.com/alien-id/agent-id.git && cd agent-id
# a) Agent identity — offline, usable immediately at L0 (self-asserted).
node plugins/agent-id-core/bin/cli.mjs init # → {fingerprint, publicKeyPem}
node plugins/agent-id-core/bin/cli.mjs status # → {level:0, assurance:"self-asserted"}
# Human attestation (L1 anonymous / L2 linked) needs the Alien SSO:
# …/agent-id-core/bin/cli.mjs bootstrap --provider-address <addr>
# b) Vault — choose how it unlocks.
node plugins/agent-id-vault/bin/cli.mjs init --unlock passkey # Touch ID; agent can't self-unlock
# or --unlock passphrase (secure form, dev mode) · plain init == --unlock agent-key (auto)
# c) Credentials — host-scoped (default-deny); value never hits argv/transcript.
node plugins/agent-id-vault/bin/cli.mjs add --name github-pat --type bearer \
--domains '*.github.com,api.github.com' --value-file /tmp/tok
node plugins/agent-id-vault/bin/cli.mjs add --name openai-key --type header \
--header-name X-Api-Key --domains api.openai.com --form # human types it into a localhost form
AGENT_ID_NO_BROWSER=1 makes any form/ceremony print its URL instead of opening a
browser (headless / SSH-tunnel use).
Use credentials at runtime — the proxy
node plugins/agent-id-proxy/bin/cli.mjs start --port 48771 # agent-key unlock, else /dev/tty
# Hard boundary (agent can't self-unlock): a human unlocks once per session —
node plugins/agent-id-proxy/bin/cli.mjs start --unlock-form # passphrase or passkey ceremony
Mode 1 — URL-rewrite (recommended, universal, HTTPS upstreams). The agent calls a
local URL naming the credential and the real upstream; the proxy validates the host
against that credential's allowlist, injects the secret, and forwards over HTTPS:
http://<proxy-host>:<port>/<credential-name>/<upstream-host>/<path>
curl http://localhost:48771/github-pat/api.github.com/user
curl -X POST http://localhost:48771/openai-key/api.openai.com/v1/chat/completions \
-H 'content-type: application/json' -d '{"model":"...","messages":[...]}'
Wallet credentials (solana-keypair/evm-keypair) are signed inside the proxy:
the agent submits an unsigned JSON-RPC tx and the proxy fills the signature.
Mode 2 (HTTP_PROXY + Authorization: AgentVault <name> stub) is the legacy
plain-HTTP fallback. Full per-type table → docs/VAULT-PROXY.md.
System-prompt block to paste into your harness
You have a credential proxy at http://localhost:48771. To call a service that
needs a secret, request http://localhost:48771/<credential-name>/<host>/<path> —
never ask for or handle the secret itself. Available credentials: github-pat
(api.github.com), openai-key (api.openai.com), … Errors return JSON with an
error field (credential_not_found, host_not_allowed, vault_locked).
Other capabilities (no proxy)
# Inject into a child process's ENV, or a temp 0600 key FILE (env-var-auth tools):
node plugins/agent-id-vault/bin/cli.mjs exec --env OPENAI_API_KEY=openai-key.value -- python train.py
node plugins/agent-id-vault/bin/cli.mjs exec --file GIT_SSH_KEY=deploy-key.value -- \
sh -c 'GIT_SSH_COMMAND="ssh -i $GIT_SSH_KEY -o IdentitiesOnly=yes" git fetch'
# Logged-in browser sealed in the vault; SSH-signed commits; DPoP service calls:
node plugins/agent-id-browser/bin/cli.mjs login --name x --url https://x.com # headed, one-time
node plugins/agent-id-git/bin/cli.mjs commit --message "..." --push
node plugins/agent-id-auth/bin/cli.mjs call --url https://service/op --method POST --body '{...}'
Replacing the Claude Code wrappers
| Claude Code piece |
Did |
Your harness equivalent |
SKILL.md description |
Auto-surfaced the capability |
This file + per-plugin SKILL.md bodies, in your system prompt / skills dir |
allowed-tools |
Gated which commands ran |
Your harness must gate this (see Security) |
| SessionStart hook |
Popped the unlock form per session |
Call proxy start --unlock-form at session start |
| Install hook |
Installed the shared libs |
Run cd plugins/agent-id-browser && npm install once |
${CLAUDE_PLUGIN_DATA} |
The plugin's writable dir |
Pass --plugin-data <dir> when a command needs one |
Security on a foreign harness — read this
- The proxy boundary holds regardless of harness. An agent making arbitrary proxy
calls still cannot extract plaintext (injected, not returned) or reach a host off a
credential's allowlist (default-deny). Safe to expose broadly.
vault show / vault exec / vault add are agent-invocable and DO surface or set
secrets. On Claude Code allowed-tools blocks them; your harness must apply the
same gate. Treat …/agent-id-vault/bin/cli.mjs as privileged; treat proxy URL
calls as unprivileged.
- Hard vs. soft unlock.
--unlock passkey|passphrase (and proxy --unlock-form)
need a human; --unlock agent-key lets the agent auto-unlock. Pick per stakes.
- Idle lock zeroes the master key after
--idle-timeout (default 12h) →
401 {error:"vault_locked"} until re-unlocked. An agent-key-unlocked proxy run with
--no-control re-opens the vault itself (no human, no restart); a human-unlocked one
needs the restart. With the control plane on, the request parks for an owner approval
instead — or fails 401 no_unlock_method when the vault has no approver slot to ask.
- Residual: vault/proxy run as the same uid as the agent (memory-scrape risk);
closing that needs the proxy as a separate OS principal (roadmap).
Command surface (JSON in → JSON out; --help on any CLI)
| Plugin |
CLI |
Key commands |
| core |
agent-id-core/bin/cli.mjs |
init, bootstrap, status, refresh, sign, verify, export-proof |
| vault |
agent-id-vault/bin/cli.mjs |
init --unlock …, add, generate, show, list, remove, exec, rekey, export, import, migrate |
| proxy |
agent-id-proxy/bin/cli.mjs |
start, status, stop, pair, autounlock |
| browser |
agent-id-browser/bin/cli.mjs |
login, read, fetch, status, open/snapshot/click/type/… |
| git |
agent-id-git/bin/cli.mjs |
setup, commit, verify |
| auth |
agent-id-auth/bin/cli.mjs |
call, header, discover, capabilities, support |
1---2name: agent-id3description: Use the Alien Agent ID system on any agent harness — verifiable agent identity (Ed25519, L0/L1/L2 assurance), an encrypted credential vault (passkey/Touch ID, passphrase, or agent-key unlock), and a localhost proxy that injects secrets so the agent uses credentials BY NAME and never sees the value. Use whenever an agent must store or use an external-service credential, prove its identity, sign git commits, drive a logged-in browser, or send a blockchain transaction without the secret entering its context. Harness-neutral — plain Node CLIs plus an HTTP proxy; no Claude Code required.4license: MIT5---67# Alien Agent ID — umbrella skill (any harness)89This is the **portable, harness-neutral** entry point. The Claude Code plugins are a10skin; underneath, every capability is a plain **Node CLI** plus a **localhost HTTP11proxy** that read/write state under `~/.agent-id`. Load this skill in any12Agent-Skills-aware harness, or read it as the integration contract for a custom one.1314> Two other directions exist: [`docs/INTEGRATION.md`](../../docs/INTEGRATION.md) — how a15> **service** adds Alien auth; [`docs/VAULT-PROXY.md`](../../docs/VAULT-PROXY.md) — the16> vault/proxy internals + threat model. Per-capability detail lives in each17> `plugins/agent-id-<x>/skills/agent-id-<x>/SKILL.md`.1819## Model in one paragraph2021- **State** lives in one dir (`~/.agent-id`; override per command with `--state-dir`22 or `AGENT_ID_STATE_DIR`).23- **Capabilities are CLIs** at `plugins/<name>/bin/cli.mjs` (relative to the cloned24 repo root). They take flags, act on the state dir, and print **JSON to stdout**.25- **Runtime credential use goes through the proxy** — a localhost server that injects26 vaulted secrets into outbound requests so the agent uses a credential **by name**27 and never sees its value.2829The agent never needs a secret — only (a) the ability to run a few `node …/cli.mjs`30commands and (b) the proxy URL.3132## Setup (one time)3334```bash35# Node 18+ (built-in fetch/WebCrypto). No Claude Code required.36git clone https://github.com/alien-id/agent-id.git && cd agent-id3738# a) Agent identity — offline, usable immediately at L0 (self-asserted).39node plugins/agent-id-core/bin/cli.mjs init # → {fingerprint, publicKeyPem}40node plugins/agent-id-core/bin/cli.mjs status # → {level:0, assurance:"self-asserted"}41# Human attestation (L1 anonymous / L2 linked) needs the Alien SSO:42# …/agent-id-core/bin/cli.mjs bootstrap --provider-address <addr>4344# b) Vault — choose how it unlocks.45node plugins/agent-id-vault/bin/cli.mjs init --unlock passkey # Touch ID; agent can't self-unlock46# or --unlock passphrase (secure form, dev mode) · plain init == --unlock agent-key (auto)4748# c) Credentials — host-scoped (default-deny); value never hits argv/transcript.49node plugins/agent-id-vault/bin/cli.mjs add --name github-pat --type bearer \50 --domains '*.github.com,api.github.com' --value-file /tmp/tok51node plugins/agent-id-vault/bin/cli.mjs add --name openai-key --type header \52 --header-name X-Api-Key --domains api.openai.com --form # human types it into a localhost form53```5455`AGENT_ID_NO_BROWSER=1` makes any form/ceremony print its URL instead of opening a56browser (headless / SSH-tunnel use).5758## Use credentials at runtime — the proxy5960```bash61node plugins/agent-id-proxy/bin/cli.mjs start --port 48771 # agent-key unlock, else /dev/tty62# Hard boundary (agent can't self-unlock): a human unlocks once per session —63node plugins/agent-id-proxy/bin/cli.mjs start --unlock-form # passphrase or passkey ceremony64```6566**Mode 1 — URL-rewrite (recommended, universal, HTTPS upstreams).** The agent calls a67local URL naming the credential and the real upstream; the proxy validates the host68against that credential's allowlist, injects the secret, and forwards over HTTPS:6970```71http://<proxy-host>:<port>/<credential-name>/<upstream-host>/<path>72```73```bash74curl http://localhost:48771/github-pat/api.github.com/user75curl -X POST http://localhost:48771/openai-key/api.openai.com/v1/chat/completions \76 -H 'content-type: application/json' -d '{"model":"...","messages":[...]}'77```7879Wallet credentials (`solana-keypair`/`evm-keypair`) are signed *inside* the proxy:80the agent submits an *unsigned* JSON-RPC tx and the proxy fills the signature.81**Mode 2** (`HTTP_PROXY` + `Authorization: AgentVault <name>` stub) is the legacy82plain-HTTP fallback. Full per-type table → [`docs/VAULT-PROXY.md`](../../docs/VAULT-PROXY.md).8384### System-prompt block to paste into your harness8586> You have a credential proxy at `http://localhost:48771`. To call a service that87> needs a secret, request `http://localhost:48771/<credential-name>/<host>/<path>` —88> never ask for or handle the secret itself. Available credentials: `github-pat`89> (api.github.com), `openai-key` (api.openai.com), … Errors return JSON with an90> `error` field (`credential_not_found`, `host_not_allowed`, `vault_locked`).9192## Other capabilities (no proxy)9394```bash95# Inject into a child process's ENV, or a temp 0600 key FILE (env-var-auth tools):96node plugins/agent-id-vault/bin/cli.mjs exec --env OPENAI_API_KEY=openai-key.value -- python train.py97node plugins/agent-id-vault/bin/cli.mjs exec --file GIT_SSH_KEY=deploy-key.value -- \98 sh -c 'GIT_SSH_COMMAND="ssh -i $GIT_SSH_KEY -o IdentitiesOnly=yes" git fetch'99100# Logged-in browser sealed in the vault; SSH-signed commits; DPoP service calls:101node plugins/agent-id-browser/bin/cli.mjs login --name x --url https://x.com # headed, one-time102node plugins/agent-id-git/bin/cli.mjs commit --message "..." --push103node plugins/agent-id-auth/bin/cli.mjs call --url https://service/op --method POST --body '{...}'104```105106## Replacing the Claude Code wrappers107108| Claude Code piece | Did | Your harness equivalent |109|---|---|---|110| `SKILL.md` `description` | Auto-surfaced the capability | This file + per-plugin SKILL.md bodies, in your system prompt / skills dir |111| `allowed-tools` | Gated which commands ran | **Your harness must gate this** (see Security) |112| SessionStart hook | Popped the unlock form per session | Call `proxy start --unlock-form` at session start |113| Install hook | Installed the shared libs | Run `cd plugins/agent-id-browser && npm install` once |114| `${CLAUDE_PLUGIN_DATA}` | The plugin's writable dir | Pass `--plugin-data <dir>` when a command needs one |115116## Security on a foreign harness — read this117118- **The proxy boundary holds regardless of harness.** An agent making arbitrary proxy119 calls still cannot extract plaintext (injected, not returned) or reach a host off a120 credential's allowlist (default-deny). Safe to expose broadly.121- **`vault show` / `vault exec` / `vault add` are agent-invocable and DO surface or set122 secrets.** On Claude Code `allowed-tools` blocks them; **your harness must apply the123 same gate.** Treat `…/agent-id-vault/bin/cli.mjs` as privileged; treat proxy URL124 calls as unprivileged.125- **Hard vs. soft unlock.** `--unlock passkey|passphrase` (and `proxy --unlock-form`)126 need a human; `--unlock agent-key` lets the agent auto-unlock. Pick per stakes.127- **Idle lock** zeroes the master key after `--idle-timeout` (default 12h) →128 `401 {error:"vault_locked"}` until re-unlocked. An agent-key-unlocked proxy run with129 `--no-control` re-opens the vault itself (no human, no restart); a human-unlocked one130 needs the restart. With the control plane on, the request parks for an owner approval131 instead — or fails `401 no_unlock_method` when the vault has no approver slot to ask.132- **Residual:** vault/proxy run as the **same uid** as the agent (memory-scrape risk);133 closing that needs the proxy as a separate OS principal (roadmap).134135## Command surface (JSON in → JSON out; `--help` on any CLI)136137| Plugin | CLI | Key commands |138|---|---|---|139| core | `agent-id-core/bin/cli.mjs` | `init`, `bootstrap`, `status`, `refresh`, `sign`, `verify`, `export-proof` |140| vault | `agent-id-vault/bin/cli.mjs` | `init --unlock …`, `add`, `generate`, `show`, `list`, `remove`, `exec`, `rekey`, `export`, `import`, `migrate` |141| proxy | `agent-id-proxy/bin/cli.mjs` | `start`, `status`, `stop`, `pair`, `autounlock` |142| browser | `agent-id-browser/bin/cli.mjs` | `login`, `read`, `fetch`, `status`, `open`/`snapshot`/`click`/`type`/… |143| git | `agent-id-git/bin/cli.mjs` | `setup`, `commit`, `verify` |144| auth | `agent-id-auth/bin/cli.mjs` | `call`, `header`, `discover`, `capabilities`, `support` |