npm package: @signet-labs/signet-guardian
Description: Payment guard middleware for OpenClaw: policy (payments on/off, per-transaction and monthly limits) for AI agent payments.
Latest version: 0.1.9

# Signet Guardian

Payment guard middleware for OpenClaw. Enforces a single policy layer (payments on/off, per-transaction limit, monthly cap) so payment-capable skills route through it before and after spending.

- **Preflight** — Check if a payment is allowed (ALLOW / DENY / CONFIRM_REQUIRED).
- **Record** — Append completed payments to the ledger (enforces monthly cap under lock).
- **Report** — View spending for today or month.
- **Policy** — Show or edit limits and rules.

Full behaviour and agent contract: [SKILL.md](./SKILL.md).

## Table of contents

- [Requirements](#requirements)
- [Install](#install)
- [Secure Setup (recommended)](#secure-setup-recommended)
- [Production hardening](#production-hardening-code--config-tampering)
- [Configuration](#configuration)
- [Dashboard](#dashboard)
- [Usage](#usage)
- [Testing](#testing)
- [License](#license)

## Documentation

| Doc | Description |
|-----|-------------|
| [docs/PRODUCTION_HARDENING.md](docs/PRODUCTION_HARDENING.md) | Production hardening, integrity manifest, safe upgrade workflow |
| [docs/TAMPER_RESISTANCE.md](docs/TAMPER_RESISTANCE.md) | Policy tamper-resistance (OTP, admin-only, audit) |
| [docs/TRANSACTION_AUDIT.md](docs/TRANSACTION_AUDIT.md) | Transaction audit trail (JSONL, event types, commands) |
| [docs/TELEGRAM_TX_COMMANDS.md](docs/TELEGRAM_TX_COMMANDS.md) | Telegram transaction commands and privacy rules |
| [docs/ACCEPTANCE_TESTS.md](docs/ACCEPTANCE_TESTS.md) | Manual acceptance tests (dashboard, secure setup, hardened mode) |

---

## Requirements

- Node.js 18+
- OpenClaw (see [openclaw](https://github.com/openclaw/openclaw))

---

## Install

### From npm (OpenClaw plugin)

```bash
openclaw plugins install @signet-labs/signet-guardian
openclaw gateway restart
```

**Install warnings:** When installing (e.g. `openclaw plugins update` or `npm install -g`), you may see deprecation warnings such as `npm warn deprecated npmlog@...` or `glob@...`. These come from npm’s own dependency tree, not from Signet Guardian. They do not affect the plugin or the CLI and can be safely ignored. Updating them is handled by the npm ecosystem.

### Development (from repo)

```bash
git clone <repo-url>
cd signet-guardian
pnpm install
pnpm run build
```

---

## Secure Setup (recommended)

You **install the package**, then **run the setup command** once. No manual file copying or script running — the setup command creates `/etc/signet/policy.json`, sets permissions, and configures OpenClaw to use it. After that, policy is read only from that file and the agent cannot change it.

**After install (ensure hardening):** run `sudo signet setup` (or `sudo npx @signet-labs/signet-guardian setup`), then `signet doctor` — all checks should show PASS. Optional full host lock: `sudo signet harden-host`.

**1. Install the package**

```bash
openclaw plugins install @signet-labs/signet-guardian
openclaw gateway restart
```

**2. Harden policy (one-time, requires sudo)**

```bash
sudo npx @signet-labs/signet-guardian setup
```

If you installed the CLI globally: `sudo signet setup`.

**3. Verify hardening**

```bash
npx @signet-labs/signet-guardian doctor
# or, if global: signet doctor
```

All checks should show **PASS**. If any fail, follow the remediation (e.g. run `sudo signet setup` again). In hardened mode, policy is managed by `/etc/signet/policy.json`; dashboard policy edits are ignored. To change policy later: `sudo npx @signet-labs/signet-guardian setup --edit-policy` (or `sudo signet setup --edit-policy` when global).

**Hardened mode (default):** With no extra config, Signet uses only `/etc/signet/policy.json`. If that file is missing or invalid, all payments are **DENY** (fail-closed). Use `SIGNET_DEV_MODE=true` only for local development to allow config/file fallbacks.

**Optional — global CLI:** To have `signet` in your PATH and avoid the npx prompt each time: `npm install -g @signet-labs/signet-guardian`, then use `signet doctor`, `signet setup`, etc.

**Optional — manual hardening:** If you cannot use the setup command (e.g. no npm/npx), you can create and secure the policy file by hand:

```bash
sudo mkdir -p /etc/signet
sudo cp ./references/policy.json /etc/signet/policy.json
sudo chown root:root /etc/signet/policy.json
sudo chmod 644 /etc/signet/policy.json
npx @signet-labs/signet-guardian doctor
```

---

## Production hardening (code + config tampering)

For stricter protection — runtime user cannot modify policy, plugin code, or OpenClaw config — run the host hardening script once (as root). It locks ownership/permissions and creates an integrity manifest. Optional: run a periodic integrity check via systemd.

**1. Run once (as root)**

After installing the package, you can run hardening via the CLI (no need to find the script path):

```bash
sudo signet harden-host
# or: sudo npx @signet-labs/signet-guardian harden-host
```

From the repo you can instead run:

```bash
sudo bash scripts/harden-signet-host.sh
# or: pnpm run harden:host
```

Defaults: `RUNTIME_USER=clawdbot`, `PLUGIN_DIR=/home/clawdbot/.openclaw/extensions/signet-guardian`, `CONFIG_FILE=/home/clawdbot/.openclaw/openclaw.json`, `POLICY_FILE=/etc/signet/policy.json`. Override with env vars if needed.

**2. Verify**

```bash
sudo bash scripts/check-signet-integrity.sh
npx @signet-labs/signet-guardian doctor
```

Integrity check must pass; doctor should report PASS for policy, config, plugin dir, and manifest.

**3. Optional: periodic integrity check (systemd)**

Copy the timer and service, install the check script, then enable the timer:

```bash
sudo cp scripts/systemd/signet-integrity.service scripts/systemd/signet-integrity.timer /etc/systemd/system/
sudo cp scripts/check-signet-integrity.sh /usr/local/bin/
sudo systemctl daemon-reload
sudo systemctl enable --now signet-integrity.timer
```

On failure the check script logs `SIGNET_INTEGRITY_FAIL` to syslog and exits non-zero. Use `--json` for machine-readable output.

**Safe upgrade (after hardening)**  
Updates require a temporary unlock: disable the timer, restore ownership/perms for the plugin (and config if needed), update the plugin, re-run the hardening script to regenerate the manifest, then re-enable the timer. See [docs/PRODUCTION_HARDENING.md](docs/PRODUCTION_HARDENING.md).

---

## Configuration

**Source of truth (dev only):** When `SIGNET_DEV_MODE=true`, the CLI reads policy from OpenClaw config first (`plugins.entries.signet-guardian.config.policy` in `~/.openclaw/openclaw.json`), then legacy `signet.policy`, then `references/policy.json`. You can edit policy in the Control UI (Dashboard) when the extension is installed; see [openclaw-extension/README.md](./openclaw-extension/README.md).

Policy shape (config or file):

```json
{
  "paymentsEnabled": true,
  "maxPerTransaction": 20,
  "maxPerMonth": 500,
  "currency": "GBP",
  "requireConfirmationAbove": 5,
  "blockedMerchants": [],
  "allowedMerchants": []
}
```

**Tamper resistance:** Policy changes are admin-only and OTP-gated. Set `SIGNET_ADMIN_TOTP_SECRET` (base32) and use `signet-policy-set --otp <6-digit> --reason "..."`. The payment path (preflight/record) cannot mutate policy. See [docs/TAMPER_RESISTANCE.md](./docs/TAMPER_RESISTANCE.md).

---

## Dashboard

### Install from GitHub (manual)

If you cloned this repo, the dashboard shows Signet only after the plugin is in OpenClaw’s extensions path.

1. Open the dashboard: `openclaw dashboard` (or visit <http://127.0.0.1:18789/>).
2. Copy the plugin into the extensions path:

   ```bash
   mkdir -p ~/.openclaw/workspace/.openclaw/extensions
   cp -r "$PWD/openclaw-extension/signet-guardian" ~/.openclaw/workspace/.openclaw/extensions/
   ```

3. Restart: `openclaw gateway restart`.
4. In the dashboard, go to **Settings → Config** and look under `plugins.entries.signet-guardian.config.policy`.

### Install via plugin (published)

When using the published package:

```bash
openclaw plugins install @signet-labs/signet-guardian
openclaw gateway restart
openclaw dashboard
```

The plugin is installed under `~/.openclaw/extensions/` and enabled automatically.

---

## Usage

Set the skill directory so the CLI uses the project’s `references/`:

```bash
export OPENCLAW_SKILL_DIR="$PWD"
```

| Command | Description |
|---------|-------------|
| `signet setup` | **(After install, with sudo.)** Create and harden `/etc/signet/policy.json` |
| `signet harden-host` | **(Optional, with sudo.)** Full host hardening: lock plugin/config, create integrity manifest |
| `signet policy --show` | Print current policy |
| `signet policy --edit` | Edit policy file in `$EDITOR` |
| `signet policy --wizard` | Interactive policy setup |
| `signet policy --migrate-file-to-config` | Copy file policy into OpenClaw config |
| `signet status` | Human summary (Telegram-friendly) |
| `signet remaining [--json]` | Remaining this month |
| `signet policy-get [--key <key>]` | Read policy or one key |
| `signet policy-set --key <k> --value <v> --otp <6-digit> --reason "..."` | **Admin-only.** Update one policy field. |
| `signet policy-audit [--tail N]` | Last N policy audit entries |
| `signet doctor [--json]` | Check hardened policy (PASS/FAIL + remediation) |
| `signet spend --period today\|month\|last30d` | Spending summary |
| `signet transactions [--limit N] [--status completed\|denied]` | Recent transactions |
| `signet preflight --amount 10 --currency GBP --payee "..." --purpose "..."` | Check if payment is allowed |
| `signet record --amount 10 --currency GBP --payee "..." --purpose "..." [--tx <txId>] [--idempotency-key "..."]` | Record a completed payment (emits payment_attempted / payment_result / tx_closed to audit) |
| `signet report --period month` | Spending for the month |
| `signet tx-event --tx <txId> --type <type> [--payload <JSON>]` | Append an event to the transaction audit (intent_received, research_started, option_evaluated, recommendation_made, user_confirmation, etc.) |
| `signet tx-show --tx <txId> [--json]` | Show all events for a transaction |
| `signet tx-list [--limit 20] [--json]` | List recent tx (time, status, total, item/purpose, vendor) |
| `signet tx-explain --tx <txId>` | Plain-language timeline (“what happened and why”) |
| `signet tx-latest [--json]` | Short summary of most recent transaction |
| `signet tx-breakdown --tx <txId> [--json]` | Cost breakdown only (subtotal, shipping, tax, fees, total) |
| `signet tx-alternatives --tx <txId> [--json]` | Options considered + reasons + chosen |
| `signet tx-export --format csv\|json --from <ISO> --to <ISO> [--limit N]` | Export summary rows for date range (dashboard/reporting) |

**Transaction audit trail:** One append-only JSONL log (default `/var/log/signet/transaction-audit.jsonl`, or `references/transaction-audit.jsonl` if not writable). Every event has `txId`, `ts`, `actor`, `eventType`. No raw card/bank secrets. **Viewing layers:** (1) **Telegram** — primary; use `signet tx latest`, `signet tx list`, `signet tx show <id>`, `signet tx explain`, `signet tx breakdown`, `signet tx alternatives`; see [docs/TELEGRAM_TX_COMMANDS.md](docs/TELEGRAM_TX_COMMANDS.md). (2) **Dashboard** — “Recent Transactions” widget + filters + export (OpenClaw UI). (3) **CLI** — above commands; power users. (4) **Raw audit file** — forensics only. See [docs/TRANSACTION_AUDIT.md](docs/TRANSACTION_AUDIT.md).

Preflight returns JSON: `{"result":"ALLOW","reason":"..."}` or `"DENY"` / `"CONFIRM_REQUIRED"`. Exit code 0 for ALLOW/CONFIRM_REQUIRED, 1 for DENY.

When running from the repo without the global CLI: `npx tsx scripts/signet-cli.ts <command> ...` (e.g. `npx tsx scripts/signet-cli.ts doctor`).

---

## Testing

From the repo root:

```bash
./test-guardian.sh
```

Uses `references/` and exercises preflight, record, and report. To test the package as installed from npm: `./scripts/test-install.sh`. Manual acceptance checklists (dashboard, Telegram, secure setup, hardened mode): [docs/ACCEPTANCE_TESTS.md](docs/ACCEPTANCE_TESTS.md).

---

## License

See repository.