Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 102 additions & 26 deletions docs/PINATA.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,55 +80,131 @@ You should NOT need to repeat this step on subsequent sessions — the keychain

## Step 2 — Install the OpenClaw plugin

A single npm install gives your Pinata agent **all 72 XPR MCP tools plus all 13 bundled skills** — `xpr-agent-operator` (system prompt) + 12 domain skills (DeFi, NFT, lending, governance, XMD, smart contracts, creative, web-scraping, code-sandbox, structured-data, tax, shellbook). Skills ship pre-built in the tarball; the plugin manifest lists them so harnesses that honor the `skills` field auto-load them.
The supported install on Pinata Agents (verified on OpenClaw 2026.3.x) is the OpenClaw plugin CLI, **not** plain `npm install`. Pinata's harness doesn't auto-scan workspace `node_modules` for plugins; it scans `~/.openclaw/extensions/<plugin>/`.

```bash
# In the Pinata agent's Console
npm i @xpr-agents/openclaw
openclaw plugins install @xpr-agents/openclaw
```

### 2a. Set the required env var
This downloads from npm, copies the plugin to `~/.openclaw/extensions/openclaw/`, and **auto-writes** the install metadata + enables it in `~/.openclaw/openclaw.json`:

**Without `XPR_ACCOUNT` set, the plugin loads in read-only mode and every signed tool silently fails.** Set these in Pinata's per-agent env / secrets panel:
```jsonc
{
"plugins": {
"entries": {
"openclaw": { "enabled": true }
},
"installs": {
"openclaw": {
"source": "npm",
"spec": "@xpr-agents/openclaw",
"version": "0.4.2",
"installPath": "/home/<user>/.openclaw/extensions/openclaw",
"integrity": "sha512-<...>",
"installedAt": "<iso-timestamp>"
}
}
}
}
```

| Var | Value | Why |
|---|---|---|
| `XPR_ACCOUNT` | your XPR account name (e.g. `myagent`) | Required for signing |
| `XPR_NETWORK` | `mainnet` or `testnet` | Defaults to mainnet |
| `INDEXER_URL` | `https://indexer.xpragents.com` (mainnet) or `https://testnet-indexer.xpragents.com` (testnet) | Required by 4 read tools (`xpr_search_agents`, `xpr_get_events`, `xpr_get_stats`, `xpr_indexer_health`) |
| `MAX_TRANSFER_AMOUNT` | `10000000` (= 1000 XPR) — adjust as needed | Caps every signed XPR transfer/stake/fee |
A backup of the previous `openclaw.json` is written to `~/.openclaw/openclaw.json.bak`.

If you skip `XPR_ACCOUNT`, watch the Pinata Logs tab for the diagnostic line `[xpr-agents] Read-only mode: XPR_ACCOUNT not set`that's the symptom.
> **Heads up — the installer prints a list of "dangerous code patterns" warnings** (currently 19 of them). Every one is intentional and explained in the npm README's "Security notes" section. The biggest one — `Shell command execution detected (child_process)` in `dist/proton-cli.js`is literally the post-charliebot signing model (proton CLI shells out so the blockchain key never enters the process). Don't bail on the install.

### 2b. Register the plugin
### 2a. Set `XPR_ACCOUNT` at the gateway env layer

The exact mechanism depends on your harness. **On Pinata Agents this is unverified** as of this writing — confirm with Pinata docs / support what format their plugin registration takes. The pattern below is what generic OpenClaw runtimes expect; adapt to Pinata's actual config surface (likely a dashboard form or `~/.openclaw/config.json`):
**Without `XPR_ACCOUNT`, the plugin loads in read-only mode and every write tool fails with a confusing error.** The env var goes in `env.vars`, NOT in `plugins.entries.openclaw.config` — verified empirically:

```jsonc
{
"plugins": [
{
"name": "@xpr-agents/openclaw",
"config": {
"network": "mainnet",
"indexerUrl": "https://indexer.xpragents.com",
"confirmHighRisk": true,
"maxTransferAmount": 10000000
"env": {
"vars": {
"XPR_ACCOUNT": "<your-agent-account>",
"XPR_NETWORK": "mainnet"
}
},
"plugins": {
"entries": {
"openclaw": {
"enabled": true,
"config": { "network": "mainnet" }
}
}
]
}
}
```

On Pinata Agents this surface is the Control UI's Config editor (Raw JSON tab) at the gateway URL printed by `openclaw status`. The plugin reads `process.env.XPR_ACCOUNT` — populated from `env.vars`, not from per-plugin `config`.

Diagnostic: if `XPR_ACCOUNT` is missing, the gateway log shows `[xpr-agents] Read-only mode: XPR_ACCOUNT not set. Write tools will fail.` once on plugin init. If wired correctly, that line **doesn't appear**.

### 2b. Restart the gateway

On Pinata Agents specifically, **the imperative `openclaw gateway restart` command does not work** ("Gateway service disabled" — they don't expose systemctl in the container). The restart fires automatically when `openclaw.json` is patched — the harness emits a `SIGUSR1` to the gateway process. Saving the config edit through the Control UI is enough.

Expected restart event shape (visible in the API response or logs):

```json
{
"restart": {
"ok": true,
"signal": "SIGUSR1",
"reason": "config.patch"
}
}
```

Restart the agent. Watch the Pinata Logs tab for:
### 2c. Confirm the plugin loaded

Tail the gateway log (in Pinata's Console or via the Control UI Logs tab):

```bash
ls -lt /tmp/openclaw/*.log | head -1 # find the current log file
grep "xpr-agents" /tmp/openclaw/openclaw-*.log | tail -10
```

The success signature:

```
[xpr-agents] Plugin loaded: 72 tools, mainnet (https://proton.eosusa.io)
```

A2A receive-only mode (expected unless you set `A2A_SIGNING_KEY`):

```
[xpr-agents] A2A_SIGNING_KEY not set — A2A outbound calls disabled. See docs/A2A.md to enable.
```

If signing is wired (you set `XPR_ACCOUNT`), the `Read-only mode:` line **does NOT appear**.

You can also confirm via the CLI:

```bash
openclaw plugins list # row should show: openclaw loaded 0.4.2
openclaw plugins info openclaw # detailed status
```

### 2d. First signed write — required on the harness path

Unlike the standalone `create-xpr-agent` scaffold (which auto-registers via the runner's `ensureRegistered()`), the harness path doesn't run that code. **Your account is not yet in `agentcore::agents`**, and every `xpr_update_*` / `xpr_set_agent_status` call will fail with `Agent not found` until you explicitly register.

In the agent chat surface:

```
[xpr-agents] Plugin loaded: 72 tools (35 read, 37 write)
> Register <your-agent-account> as an agent with name 'My Agent',
description 'Autonomous worker', endpoint 'https://my-agent.example',
protocol 'https', capabilities ['general', 'jobs', 'bidding'].
```

That's the success line. If you don't see it, the harness never invoked the plugin's default export — your registration step didn't take effect. If you see `[xpr-agents] Read-only mode: XPR_ACCOUNT not set`, the plugin loaded but signing is disabled (back to 2a).
Expected:
- Tool call: `xpr_register_agent`
- Response contains `"transaction_id": "<64-hex-chars>"`
- Gateway log emits `[proton-cli] action agentcore::register auth=<your-agent-account>@active` then `[proton-cli] tx <id> ok in <ms>ms`
- Follow-up `xpr_get_agent` against your account name now returns the registered record

After restart, the plugin's tools (`xpr_get_agent`, `xpr_submit_bid`, `xpr_deliver_job`, etc.) appear in the agent's tool list.
That confirms: harness load + env wiring + proton CLI shell-out + on-chain signing all working.

## Step 3 — (Optional) Install foundational reference skill via ClawHub

Expand Down
133 changes: 102 additions & 31 deletions openclaw/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,44 +27,92 @@ cd my-agent

### Inside an OpenClaw harness

The supported install path on OpenClaw runtimes (OpenClaw 2026.3.x verified, Pinata Agents verified):

```bash
# 1. Install via OpenClaw's plugin CLI (NOT `npm install` — see "Why not
# plain npm install" below)
openclaw plugins install @xpr-agents/openclaw
```

This downloads the package from npm, copies it to `~/.openclaw/extensions/openclaw/`, and **auto-writes** the following to your `~/.openclaw/openclaw.json`:

```jsonc
{
"plugins": {
"entries": {
"openclaw": { "enabled": true }
},
"installs": {
"openclaw": {
"source": "npm",
"spec": "@xpr-agents/openclaw",
"version": "0.4.2",
"installPath": "/home/<user>/.openclaw/extensions/openclaw",
"integrity": "sha512-<...>",
"shasum": "<...>",
"installedAt": "<iso-timestamp>"
}
}
}
}
```

```bash
# 1. Install
npm install @xpr-agents/openclaw

# 2. Register with the harness. The mechanism depends on the runtime:
# - Pinata Agents: see docs/PINATA.md for the per-agent config flow
# - Generic OpenClaw: add to your plugins config:
# {
# "plugins": [
# {
# "name": "@xpr-agents/openclaw",
# "config": {
# "network": "mainnet",
# "indexerUrl": "https://indexer.xpragents.com"
# }
# }
# ]
# }
#
# 3. Restart the agent. You should see in logs:
# [xpr-agents] Plugin loaded: 72 tools (35 read, 37 write)
# If you see `[xpr-agents] Read-only mode: XPR_ACCOUNT not set`,
# the plugin loaded but signing is disabled — set XPR_ACCOUNT
# (see Configuration below) and restart.
#
# 4. Verify: ask the agent to list open jobs:
# > List the latest 5 open jobs on the XPR Agents job board.
# Expect a real list. If you get "tool not found" the registration
# step (#2) didn't fire — check your harness's plugin list.
# 2. Set XPR_ACCOUNT at the gateway env layer (see "Configuration" below
# for which surface — it is NOT inside plugins.entries.openclaw.config).

# 3. Restart the gateway. Most OpenClaw harnesses restart automatically
# when openclaw.json is patched (a SIGUSR1 fires). If yours doesn't,
# use whichever restart command your harness supports.

# 4. Verify the load by tailing the gateway log. Look for:
# [xpr-agents] Plugin loaded: 72 tools, mainnet (https://proton.eosusa.io)
# If you also see `[xpr-agents] Read-only mode: XPR_ACCOUNT not set.`,
# the plugin loaded but signing is disabled — re-check step 2.

# 5. Run your first signed write (the plugin auto-registration in the
# standalone scaffold does NOT fire on the harness path):
# > Register <your-agent> as an agent with name '...', description
# '...', endpoint '...', protocol 'https', capabilities ['general',
# 'jobs', 'bidding'].
# Expect `xpr_register_agent` → real `transaction_id` in the response →
# `[proton-cli] action agentcore::register auth=<your-agent>@active`
# in the gateway log.
```

The harness provides the LLM — **do not** set `ANTHROPIC_API_KEY` and **do not** run `start.sh` on this path. Plugin path is install + register only. Full walkthrough for Pinata Agents specifically: [`docs/PINATA.md`](https://github.com/XPRNetwork/xpr-agents/blob/main/docs/PINATA.md).
The harness provides the LLM — **do not** set `ANTHROPIC_API_KEY` and **do not** run `start.sh` on this path. Plugin install + gateway env + first `xpr_register_agent` call is the whole flow. Full walkthrough for Pinata Agents specifically: [`docs/PINATA.md`](https://github.com/XPRNetwork/xpr-agents/blob/main/docs/PINATA.md).

#### Why not plain `npm install`?

OpenClaw harnesses do **not** auto-scan workspace `node_modules` for plugins. They scan:
- `plugins.load.paths` (explicit)
- `~/.openclaw/extensions/<plugin>/`
- bundled `/app/extensions/<plugin>/`

So `npm install @xpr-agents/openclaw` puts the package on disk but doesn't make it discoverable. Use `openclaw plugins install` (above) or, for monorepo development, add the workspace path to `plugins.load.paths` manually.

#### Why the harness path doesn't auto-register

The standalone `create-xpr-agent` scaffold auto-registers the agent in `agentcore::agents` on first boot via the runner's `ensureRegistered()`. The harness path loads only the plugin — not the runner — so the account is **not** in the registry until you explicitly call `xpr_register_agent`. Until then, every `xpr_update_*` / `xpr_set_agent_status` call returns `Agent not found`. Tracked for v0.5 to optionally self-register on first signed call when `XPR_ACCOUNT` is set.

## Security notes (read this if your OpenClaw install scanner flags us)

OpenClaw's plugin installer statically scans every package before install and reports patterns it considers risky. As of 0.4.2 it flags **19 patterns** in `@xpr-agents/openclaw`. Every one of them is intentional and named below — do not bail on the install when you see them.

| Count | Pattern | Where | Why it's intentional |
|---|---|---|---|
| 16× | "Environment variable access combined with network send — possible credential harvesting" | `skills/{creative,defi,governance,lending,nft,smart-contracts,tax,xmd}/{src,dist}/index.ts:<line>`, `dist/tools/a2a.js`, `dist/tools/shellbook.js` | Each skill reads its own service API key (`REPLICATE_API_TOKEN`, `GITHUB_TOKEN`, `PINATA_JWT`, `SHELLBOOK_API_KEY`, `COINGECKO_API_KEY`, `A2A_SIGNING_KEY`, etc.) and calls that service's HTTPS API. The "credential" the scanner sees is the service-specific key the skill *needs* to function. No blockchain private key is read — that lives in the proton CLI keychain, not in env vars. |
| 1× | "Shell command execution (child_process)" | `dist/proton-cli.js:<line>` | **This is the post-charliebot security feature itself.** All on-chain signing shells out to `proton transaction:push`. The whole reason for v0.4.x is that the blockchain private key never enters the agent process — it stays in the proton CLI's encrypted keychain and we cross the trust boundary via this `child_process` call. If you'd rather hold the key in process, use a different package. |
| 2× | "Dynamic code execution detected" | `skills/code-sandbox/{src,dist}/index.ts:<line>` | The whole point of the `code-sandbox` skill is sandboxed JS execution inside a `node:vm` context. If you don't want sandboxed code execution available to your agent, disable the skill — the rest of the plugin doesn't depend on it. |

If your harness lets you set `plugins.allow` to an explicit allowlist, set it to `["openclaw"]` (plus any other plugins you trust) — that suppresses the auto-discovery warning and makes the trust decision explicit.

## Bundled Skills (13 total — since v0.4.0)

The plugin ships pre-built skills in its tarball; the `openclaw.plugin.json` manifest lists them so OpenClaw harnesses that honor the `skills` field auto-load them after the agent restarts. Verify by asking the agent `list your skills` — you should see 13.
The plugin ships pre-built skills in its tarball; the `openclaw.plugin.json` manifest lists them so OpenClaw harnesses that honor the `skills` field auto-load them after the agent restarts.

If your harness doesn't honor the manifest's `skills` field, the skill folders are still on disk at `node_modules/@xpr-agents/openclaw/skills/<name>/` and can be registered manually.
When you install via `openclaw plugins install @xpr-agents/openclaw`, the skill folders land at `~/.openclaw/extensions/openclaw/skills/<name>/` and the harness picks them up on the next gateway restart. If your harness ignores the manifest's `skills` array, the skill folders are still on disk and can be registered through whatever per-skill mechanism your runtime exposes.

| Skill | Purpose |
|-------|---------|
Expand Down Expand Up @@ -155,6 +203,29 @@ XPR_ACCOUNT=myagent # REQUIRED — without this, the plugi
XPR_NETWORK=mainnet # mainnet | testnet (default: mainnet)
```

> **Where to put `XPR_ACCOUNT` matters.** On OpenClaw harnesses it goes in the gateway environment layer, NOT in the plugin's config:
>
> ```jsonc
> // ~/.openclaw/openclaw.json — CORRECT
> {
> "env": {
> "vars": {
> "XPR_ACCOUNT": "myagent"
> }
> },
> "plugins": {
> "entries": {
> "openclaw": {
> "enabled": true,
> "config": { "network": "mainnet" }
> }
> }
> }
> }
> ```
>
> Putting `XPR_ACCOUNT` inside `plugins.entries.openclaw.config` does NOT work — the plugin reads it from `process.env`, which is populated from `env.vars`, not from per-plugin config. We verified this empirically on OpenClaw 2026.3.x.

### Optional environment variables

```env
Expand Down
2 changes: 1 addition & 1 deletion openclaw/dist/index.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading