Give your AI agent a face.
A keypair is proof of identity — but it's just numbers. A profile puts a name, a picture, and a description to that code. It makes it easier for people and other entities to relate to your agent and stay connected in the public social space.
And while someone could try to create a fake account using your agent's name, the npub is cryptographic proof of identity that can't be faked. It's the best way for anyone to be sure they're connecting to the real thing.
Everything in a Nostr profile is public — just like any social platform. The name, bio, and images are visible to anyone on the Nostr network and the public internet.
nostr-profile is part of the NSE sovereign identity ecosystem:
- NostrKey gives the agent its keypair — the cryptographic root
- nostr-profile uses that keypair to publish and manage the agent's public identity
- sense-memory uses it for encrypted persistence
- NostrCalendar uses it for scheduling
- NostrSocial uses it for the social graph
The keypair is who you are. The profile is how the world sees you.
pip install nostr-profileimport asyncio
from nostrkey import Identity
from nostr_profile import Profile, publish_profile, get_profile
async def main():
# Load identity from encrypted file (passphrase from env var)
import os
identity = Identity.load("my-identity.nostrkey", passphrase=os.environ["NOSTRKEY_PASSPHRASE"])
relay = "wss://relay.damus.io"
# Publish your profile
profile = Profile(
name="Johnny5",
about="An OpenClaw AI companion by Humanjava",
picture="https://example.com/johnny5-avatar.png",
nip05="johnny5@example.com",
)
event_id = await publish_profile(identity, profile, relay)
print(f"Profile published: {event_id}")
print(f"View online: https://njump.me/{identity.npub}")
# Read anyone's profile
their_profile = await get_profile(identity.public_key_hex, relay)
if their_profile:
print(f"{their_profile.name}: {their_profile.about}")
asyncio.run(main())| Function | Returns | Description |
|---|---|---|
publish_profile(identity, profile, relay_url) |
str |
Publish a complete profile. Returns event ID. |
update_profile(identity, relay_url, **fields) |
str |
Update specific fields without clobbering the rest. |
get_profile(pubkey_hex, relay_url) |
Profile | None |
Read anyone's profile from a relay. |
| Field | Type | Required | Description |
|---|---|---|---|
name |
str |
Yes | Display name (max 100 chars) |
about |
str |
No | Bio/description (max 2000 chars) |
picture |
str |
No | Avatar URL (HTTPS) |
banner |
str |
No | Banner image URL (HTTPS) |
nip05 |
str |
No | NIP-05 verification (user@domain.tld) |
lud16 |
str |
No | Lightning address (user@domain.tld) |
website |
str |
No | Website URL (HTTPS) |
from nostr_profile import update_profile
# Only changes the about field — everything else stays the same
await update_profile(identity, relay, about="Updated bio for Q2")old_profile = await get_profile(pubkey, relay)
new_profile = Profile(name="Johnny5", about="New bio")
changes = old_profile.diff(new_profile)
# {"about": ("Old bio", "New bio")}| NIP | Purpose |
|---|---|
| NIP-01 | Kind 0 metadata (replaceable) |
| NIP-05 | DNS-based verification identifier |
clawhub install nostr-profileThe support_skills/ folder contains ready-to-deploy workspace files. See support_skills/README.md for the full walkthrough.
Short version:
- Add
nostr-profileto your Dockerfile:RUN pip3 install --no-cache-dir --break-system-packages nostr-profile==0.1.7 - Set
NOSTRKEY_PASSPHRASEin your.envfile so the agent can sign autonomously - Copy
support_skills/setup-profile.pyandsupport_skills/show-profile.pyinto your OC workspace - Paste the snippet from
support_skills/TOOLS-snippet.mdinto your agent'sTOOLS.md
Once your agent's profile is published, here are useful things to ask it:
| What to ask | What it does |
|---|---|
| "What is your Nostr profile?" | Shows name, bio, avatar from local cache |
| "Update your bio to ..." | Publishes updated profile to relay |
| "Look up npub1..." | Fetches someone else's profile from a relay |
The agent will also offer to show you the profile online via:
- njump.me —
https://njump.me/[npub] - npub.bio —
https://npub.bio/[npub]
Now that your agent has a profile, it exists on the Nostr network — an open social protocol with no gatekeepers, no corporate algorithms, no account bans.
Your agent (or you, on its behalf) can use any Nostr-enabled app to:
- Post content and engage publicly — just like X/Twitter, but on the open internet
- Have public conversations with humans and other agents
- Update the profile — change the name, bio, avatar, or banner anytime
- Build a following — anyone can follow the npub from any Nostr client
Some popular Nostr apps:
| App | Platform | Link |
|---|---|---|
| Primal | Web, iOS, Android | primal.net |
| Damus | iOS | damus.io |
| Amethyst | Android | github.com/vitorpamplona/amethyst |
| Coracle | Web | coracle.social |
| Snort | Web | snort.social |
No sign-up required — just import the npub or nsec into any of these apps and your agent's profile is already there.
The script needs to connect to a Nostr relay via WebSocket. If the relay is unreachable (e.g., behind a VPN that blocks certain hosts), the script will hang.
Fix: Try a different relay. wss://relay.damus.io is widely reachable. Pass it as the 4th argument to setup-profile.py.
The passphrase is read from the NOSTRKEY_PASSPHRASE environment variable, set in your .env or docker-compose.yml. The agent can sign events autonomously without asking the operator each time.
Fix: If the env var isn't set, the script will error. Add NOSTRKEY_PASSPHRASE=yourpassphrase to your .env file and restart the container.
Yes. After publishing, visit:
https://njump.me/[your-agent-npub]https://npub.bio/[your-agent-npub]
These are public Nostr profile viewers — anyone can see the profile.
The Nostr protocol does not support uploading images. Profile pictures and banners are URLs to images already hosted on the internet — your website, an image host, social media, etc. If you don't have a hosted image, the setup script can generate a unique DiceBear avatar automatically using "auto".
Use update-profile.py from support_skills/:
python3 update-profile.py --name "New Name"
python3 update-profile.py --about "New bio" --picture "https://example.com/photo.jpg"Only the fields you pass will change. Everything else stays the same.
- PyPI: https://pypi.org/project/nostr-profile/
- GitHub: https://github.com/HumanjavaEnterprises/huje.nostrprofile.OC-python.src
- ClawHub: https://clawhub.ai/vveerrgg/nostr-profile
- huje.tools: https://huje.tools
MIT — Humanjava Enterprises Inc.