Give the AI agent its own EVM wallet with admin-controlled policies the agent CANNOT bypass even under prompt injection. Encrypted keystore (AES-256-GCM, scrypt KDF), policy file the agent has no tool to write, deterministic policy gate on every signing operation, optional local HTTP dashboard. Triggers: agent wallet, give the agent a wallet, agent address, fund the agent, agent autonomy, policy gate, kill switch, agent permissions, bounded autonomy, ERC-4337 alternative, session-key alternative.
npx skills add https://github.com/internet-court/internet-court-skill --skill agent-wallet
The agent has its own EOA wallet on every EVM chain it supports. The admin (you, in your shell) sets policies that the agent cannot violate or revoke — even if a malicious prompt convinces the LLM to try.
The attacker's goal: prompt-inject the agent to drain its wallet to an attacker address.
The plugin's defense: the policy check is in code, not in the LLM's prompt. Every chaingpt_agent_wallet_sign_and_send call:
checkPolicy(intent) — pure deterministic code that doesn't see the LLM's context.The attacker can convince the LLM to call sign_and_send(to=attacker, value=ALL) — but the tool layer refuses because attacker isn't in allowedToAddresses or value exceeds maxTxValueWei or killSwitch=true. The trust boundary is the tool code, not the LLM.
There is no MCP tool that writes the policy file. The admin edits it directly with a text editor. There is no MCP tool that reads or sets the passphrase. The passphrase lives only in the shell env var or the OS keychain — never in the keystore file, never in the LLM's context.
The keystore passphrase resolves in this priority order:
CHAINGPT_AGENT_WALLET_PASSPHRASE env var — explicit override. Best for CI / headless / power users who want zero process-list and zero keychain exposure.security) or Linux (libsecret via secret-tool), if no env var is set, chaingpt_agent_wallet_init generates a strong 256-bit passphrase and stores it in the keychain. You never type or remember it; the MCP server reads it back on each load.# Just init — a strong passphrase is generated + stored in your OS keychain.
claude
> initialize the agent wallet
The init output tells you it used the keychain and how to export the passphrase for backup.
# Set a strong passphrase BEFORE starting the MCP server (>= 16 chars)
export CHAINGPT_AGENT_WALLET_PASSPHRASE="your-strong-passphrase-here-min-16-chars"
claude
> initialize the agent wallet
> Back up the passphrase either way. Keychain entry: service=chaingpt-mcp-agent-wallet account=keystore-passphrase. Export on macOS with security find-generic-password -s chaingpt-mcp-agent-wallet -a keystore-passphrase -w. Lose it (and any backup) → the keystore is unrecoverable. There is no recovery path.
> Security tradeoff of the keychain option: the secret stays out of plaintext-on-disk and out of the LLM context, but the keychain is unlocked while you're logged in — a local attacker on an unlocked session could read it. That's a much higher bar than a plaintext file and appropriate for a low-value bounded hot wallet. For zero local exposure, use Option B.
This creates two files:
| File | Contents | Who edits it |
|---|---|---|
| ~/.chaingpt-mcp/agent-wallet/keystore.json | AES-256-GCM encrypted private key | Generated once by the init tool. Never edit by hand. Back it up. |
| ~/.chaingpt-mcp/agent-wallet/policy.json | Plain JSON rules | You, the admin, with a text editor. The agent has NO tool that writes this file. |
Both default to ~/.chaingpt-mcp/agent-wallet/ but can be overridden via CHAINGPT_KEYSTORE_FILE and CHAINGPT_AGENT_POLICY_FILE.
| Tool | Mutates state? | Notes |
|---|---|---|
| chaingpt_agent_wallet_init | Creates keystore | One-shot. Refuses if file exists. |
| chaingpt_agent_wallet_address | No | Returns the agent's EOA address. Use this to receive funds. |
| chaingpt_agent_wallet_status | No | Address + policy digest + kill-switch state. Run this before any signing. |
| chaingpt_agent_wallet_balances | No | Native-coin balances across requested chains. |
| chaingpt_agent_wallet_policy | No (read-only) | Shows the current policy JSON. Cannot modify it. |
| chaingpt_agent_wallet_sign_and_send | Signs + broadcasts a tx | The only tool that can move funds. Gated by policy. |
| chaingpt_agent_wallet_serve_ui | Starts a local HTTP server | Dashboard on http://127.0.0.1:8787. Read-only view. |
Default policy.json (lazily created on first read) is the Balanced DeFi policy: killSwitch: false, major DEX/lending routers allow-listed, 0.1 native per-tx cap, 0.3 native + 20 txs per rolling 24h (maxDailySpendWei / maxDailyTxCount), memo required. A corrupt or partially-missing policy file always falls back to fail-closed (killSwitch: true) — tampering can never open the gates. Apply the "Locked down" template (or set killSwitch: true) for a refuse-everything posture.
Example production policy (allow DEX rebalancing on Base, capped at 0.1 ETH/tx, audit memo required):
{
"version": 1,
"killSwitch": false,
"allowedChains": [8453],
"allowedToAddresses": [
"0x6352a56caadc4f1e25cd6c75970fa768a3304e64",
"0x111111125421ca6dc452d289314280a0f8842a65"
],
"blockedToAddresses": [
"0x0000000000000000000000000000000000000000"
],
"maxTxValueWei": "100000000000000000",
"maxTxGas": "500000",
"blockedSelectors": [],
"requireMemo": true,
"notes": "Base only, OpenOcean + 1inch routers only, 0.1 ETH cap, memo required for audit",
"updatedAt": "2026-05-18T20:00:00Z"
}
| Field | Type | Behavior when unset | Behavior when set |
|---|---|---|---|
| killSwitch | bool | refuses everything (fail-closed) | true refuses everything; false proceeds to other checks |
| allowedChains | int[] | any chain allowed | refuses if chainId not in list |
| allowedToAddresses | string[] | any address allowed | refuses if to not in list (case-insensitive) |
| blockedToAddresses | string[] | nothing blocked | refuses if to matches (case-insensitive) |
| maxTxValueWei | string | no cap | refuses if native value > max |
| maxTxGas | string | no cap | refuses if gasLimit > max; an explicit gasLimit becomes REQUIRED (auto-estimation would bypass the cap) |
| maxDailySpendWei | string | no velocity cap | refuses if 24h ledger spend + this tx value would exceed the cap (fail-closed if the ledger is unreadable) |
| maxDailyTxCount | int | no velocity cap | refuses once the rolling-24h signed-tx count reaches the cap |
| blockedSelectors | string[] | nothing blocked | refuses if first 4 bytes of data match (e.g. 0xa9059cbb blocks ERC-20 transfer) |
| requireMemo | bool | no memo required | refuses if the memo arg is missing |
Precedence: kill switch > blockedToAddresses > allowedToAddresses > value caps > gas cap > daily velocity caps > blockedSelectors > memo. Any single failure refuses the tx.
The same bounded-autonomy model on Solana. Separate Ed25519 keystore (solana-keystore.json, same cipher + same admin passphrase), gated by the solana policy sub-object that — like everything else here — no MCP tool can write.
chaingpt_agent_wallet_solana_init # one-time keystore
chaingpt_agent_wallet_solana_address # fund this (the balance is the outermost cap)
<any builder: jupiter swap / marginfi / kamino / transfer> → unsigned VersionedTransaction (base64)
chaingpt_agent_wallet_solana_sign_and_send txBase64=<…> memo=<…>
Policy block (admin-only, dashboard or text editor):
"solana": {
"enabled": true,
"allowedPrograms": ["11111111111111111111111111111111", "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"],
"maxTxLamports": "100000000",
"maxDailySpendLamports": "300000000",
"maxDailyTxCount": 20,
"requireMemo": true
}
Hard facts to relay accurately:
solana.enabled: true refuses every Solana signing op. unrestricted does not bypass it.maxTxLamports + the 24h window. Simulation unavailable or failing ⇒ refusal, never a blind broadcast.The endgame: the user's ERC-7579 smart account grants the agent's EOA a SCOPED on-chain session (Smart Sessions module). The caps live in audited contracts and are validated by the EntryPoint. Status: BETA — the module addresses are verified deployed on Base Sepolia and the encoders are unit-tested, but the end-to-end live proof is not yet published. Treat the on-chain column below as the DESIGNED guarantee, not yet an independently-demonstrated one; the local gate is your tested fence today.
| Threat | Local policy gate (tested) | On-chain session caps (designed, beta) |
|---|---|---|
| Prompt injection | ✅ blocks | ✅ designed to block |
| Policy file tampered/rewritten | ❌ falls | ✅ designed to block |
| Full host compromise (keystore stolen) | ❌ falls | ✅ designed to block, bounded by remaining allowance + expiry (live proof pending) |
chaingpt_aa_session_build_grant chain=base account=<user SCW> tokenCaps=[{token: USDC, cap: "100000000"}] validUntil=<unix>
→ OWNER signs the userOpHash externally → chaingpt_aa_submit_userop
chaingpt_aa_session_status # chain-authoritative: enabled? remaining?
chaingpt_agent_wallet_4337_sign_and_send … # the agent acts; local gates AND chain caps both apply
chaingpt_aa_session_build_revoke … # incident response: chain-level kill
Hard facts: erc4337.enabled policy opt-in is fail-closed and OFF by default everywhere (this surface acts on a third-party account). Unbounded grants are refused at build time. A bundler rejection of an over-cap op is the product working — never retry around it. v1 supports Biconomy Nexus 1.x accounts.
1. chaingpt_agent_wallet_status # see address + policy digest + kill switch state
2. chaingpt_agent_wallet_balances # confirm funded on the target chain
3. chaingpt_agent_wallet_policy # read the active rules in full
4. chaingpt_agent_wallet_sign_and_send chain=… to=… valueWei=… data=… memo="…"
If the call gets refused with a policy reason: do not try to work around it from the agent side. Surface the reason to the admin and let them edit the policy file (or override) themselves.
> Use chaingpt_agent_wallet_serve_ui
Returns a http://127.0.0.1:8787 URL and a one-time admin token printed in the tool output (also saved to ~/.chaingpt-mcp/agent-wallet/.admin-token, 0600). The token rotates on every restart.
Open the URL in your browser. Paste the admin token at the login screen. The dashboard then shows:
.bak backupRecall the threat model: the attacker controls the LLM via prompt injection. The defenses, in layers:
savePolicy function — it's only imported by the localhost HTTP server.Origin on form submits..bak. A botched save can't corrupt the policy file mid-write, and the previous version is recoverable.127.0.0.1 only. Never on 0.0.0.0 — the dashboard is not reachable from other machines on the network.The single failure mode that would bypass all of this: malware running on the admin's machine that can read the admin token file AND make HTTP requests to localhost. At that point the attacker has shell access and can read the keystore directly; the policy file is no longer the weakest link.
| Method | Path | Behavior |
|---|---|---|
| GET / | login form (if unauthed) or redirect to /dashboard | — |
| POST /login | check admin token, set session cookie, redirect to /dashboard | requires Origin |
| GET /dashboard | full admin UI (auth required) | — |
| GET /api/policy | current policy JSON | requires session |
| POST /api/policy | save new policy after validation | requires session + Origin |
| POST /api/killswitch | toggle the kill switch (set=on/off) | requires session + Origin |
| GET /api/status | JSON with address + balances + policy digest | requires session |
| GET /logout | clear session cookie, redirect to login | — |
CHAINGPT_AGENT_WALLET_PASSPHRASE → the keystore is unrecoverable. There is no recovery path. Back up the passphrase out-of-band (1Password, hardware safe, etc.).chaingpt_agent_wallet_addresschaingpt_agent_wallet_balances chains=[base,arbitrum]The agent is now ready to operate within its policy bounds.
All agent-wallet tools cost 0 ChainGPT credits. The wallet is custody-on-the-user's-machine (not custody-via-ChainGPT). The credit funnel comes from upstream tools the user/agent calls (chaingpt_research_token, chaingpt_risk_token, chaingpt_intel_token) before deciding to deploy.
~/.chaingpt-mcp/agent-wallet/{keystore.json,policy.json} (override via env).Build professional financial services data packs from various sources including CIMs, offering memorandums, SEC filings, web search, or MCP servers. Extract, normalize, and standardize financial data into investment committee-ready Excel workbooks with consistent structure, proper formatting, and documented assumptions. Use for M&A due diligence, private equity analysis, investment committee materials, and standardizing financial reporting across portfolio companies. Do not use for simple financial calculations or working with already-completed data packs.
| Skill that analyzes 18-month scenarios from a news headline. Runs the primary analysis with the scenario-analyst agent and obtains a second opinion with the strategy-reviewer agent. Generates a comprehensive English report covering 1st/2nd/3rd-order impacts, recommended stocks, and a critical review. medium-to-long-term investment strategy
Analyze skill library to identify coverage gaps, redundant overlaps, optimization opportunities, and provide recommendations for skill portfolio improvement
> Use this skill when the user is doing hands-on DOCA SHA programming — offloading SHA-1, SHA-256, or SHA-512 hashing onto a BlueField DPU or ConnectX accelerator, picking between one-shot `doca_sha_task_hash` and incremental `doca_sha_task_partial_hash`, querying `doca_sha_cap_*` for algorithm support and min destination / max source buffer sizes, setting source / destination `doca_mmap` permissions, or decoding DOCA_ERROR_* returns from the SHA API. Trigger even when the user does not explicitly mention "DOCA SHA" or "doca_sha_task" — typical implicit phrasings include "hash a multi-GiB file on the DPU", "offload SHA-256 to the BlueField", "streaming hash over chunks", "partial hash returns BAD_STATE", "destination buffer too small for digest", or "is SHA-512 available on this card". Refuse and route elsewhere for general cryptographic-hash theory (collision resistance, SHA-3 selection), other DOCA crypto libraries (AES-GCM, Compress, DMA), or DOCA install / BFB bring-up — those belong to other skills.
Agent skill for agentic-payments - invoke with $agent-agentic-payments
>- Onchain OS onboarding and guide hub for first-time use, product introductions, OKX.AI, and customer-support intents. Classifies requests and routes them through the Intent Routing table. Use for questions about what Onchain OS is, what it can do, getting started, tutorials, onboarding, first-time setup, and introductions; for OKX.AI explanations and role-registration routing across User, ASP, and Evaluator roles, including spelling and language variants; and for Help Center, customer service, complaints, feedback, bug reports, FAQs, or user-guide requests. Do not use for direct on-chain actions such as swaps, wallet, balance, or token operations, or for Agent task lifecycle actions such as publish, accept, deliver, or dispute; those have dedicated skills.
> Analyze a blockchain transaction by its hash using TRES Finance MCP and generate a visual flow diagram showing all asset movements, followed by a plain-language explanation of what happened. Use this skill whenever the user provides a transaction hash and asks to "analyze", "explain", "visualize", "diagram", "show me what happened in", or "tell the story of" a transaction. Also trigger when the user pastes a tx hash (long hex string starting with 0x) and asks anything about it. Always use this skill for transaction hash analysis — do not attempt to answer from memory alone.
Tracks LLM token consumption and usage metrics for billing, monitoring, and optimization. Use this to log token usage, calculate costs, generate invoices, and understand which agents or users consume the most resources.
Take internet-court/agent-wallet from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.