Nostr is a downloadable channel plugin (@openclaw/nostr) that lets Apus receive and answer NIP-04 encrypted direct messages over Nostr relays. One account per gateway; DMs only.

Install

apus plugins install @openclaw/nostr

Use the bare package spec to follow the current official release tag. Pin an exact version only when you need a reproducible install.

From a local checkout (dev workflows):

apus plugins install --link <path-to-local-nostr-plugin>

Installing or enabling the plugin applies it to a running Gateway; check the application result. Onboarding (apus onboard) and apus channels add surface Nostr from the shared channel catalog once the plugin is installed.

Non-interactive setup

apus channels add --channel nostr --private-key "$NOSTR_PRIVATE_KEY"
apus channels add --channel nostr --private-key "$NOSTR_PRIVATE_KEY" --relay-urls "wss://relay.damus.io,wss://relay.primal.net"

Use --use-env to keep NOSTR_PRIVATE_KEY in the environment instead of storing the key in config (default account only).

Quick setup

  1. Generate a Nostr keypair (if needed):
# Using nak
nak key generate
  1. Add to config:
{
  channels: {
    nostr: {
      privateKey: "${NOSTR_PRIVATE_KEY}",
    },
  },
}
  1. Export the key:
export NOSTR_PRIVATE_KEY="nsec1..."
  1. Restart the gateway.

Configuration reference

Key Type Default Description
privateKey string required Private key in nsec or hex format; secret refs allowed
relays string[] ['wss://relay.damus.io', 'wss://nos.lol'] Relay URLs (WebSocket)
dmPolicy string pairing DM access policy
allowFrom string[] [] Allowed sender pubkeys
enabled boolean true Enable/disable channel
name string - Display name
profile object - NIP-01 profile metadata

Profile metadata

Profile data is published as a NIP-01 kind:0 event. You can manage it from the Control UI (Channels -> Nostr -> Profile) or set it directly in config.

Example:

{
  channels: {
    nostr: {
      privateKey: "${NOSTR_PRIVATE_KEY}",
      profile: {
        name: "apus",
        displayName: "Apus",
        about: "Personal assistant DM bot",
        picture: "https://example.com/avatar.png",
        banner: "https://example.com/banner.png",
        website: "https://example.com",
        nip05: "apus@example.com",
        lud16: "apus@example.com",
      },
    },
  },
}

Notes:

Access control

DM policies

Gateway pairing approval notifications require a running Nostr account. If the account is stopped, approval still succeeds, but the Gateway reports that notification failed.

The CLI's pairing approve nostr ... --notify cannot access the Gateway's Nostr connection, so notification fails even when the account is running. Pairing approval still succeeds; use a Gateway client to request an approval notification.

Enforcement notes:

Allowlist example

{
  channels: {
    nostr: {
      privateKey: "${NOSTR_PRIVATE_KEY}",
      dmPolicy: "allowlist",
      allowFrom: ["npub1abc...", "npub1xyz..."],
    },
  },
}

Key formats

Accepted formats:

Relays

Defaults: relay.damus.io and nos.lol.

{
  channels: {
    nostr: {
      privateKey: "${NOSTR_PRIVATE_KEY}",
      relays: ["wss://relay.damus.io", "wss://relay.primal.net", "wss://nostr.wine"],
    },
  },
}

Tips:

Protocol support

NIP Status Description
NIP-01 Supported Basic event format + profile metadata
NIP-04 Supported Encrypted DMs (kind:4)
NIP-17 Planned Gift-wrapped DMs
NIP-44 Planned Versioned encryption

Testing

Local relay

# Start strfry
docker run -p 7777:7777 ghcr.io/hoytech/strfry
{
  channels: {
    nostr: {
      privateKey: "${NOSTR_PRIVATE_KEY}",
      relays: ["ws://localhost:7777"],
    },
  },
}

Manual test

  1. Note the bot pubkey from gateway logs or apus channels status (hex; convert to npub in your client if needed).
  2. Open a Nostr client (Amethyst, Damus, etc.).
  3. DM the bot pubkey.
  4. Verify the response.

Troubleshooting

Not receiving messages

Not sending responses

Duplicate responses

Security

Limitations (MVP)

Related