nostr-profile
Nostr profile management for AI agents — publish, read, and update kind 0 metadata on any relay
Like a lobster shell, security has layers — review code before you run it.
License
Runtime requirements
Install
uv tool install nostr-profileSKILL.md
nostr-profile -- Your Face on the Network
Identity is you to yourself — a pair of cryptographic keys that prove you exist. But a keypair is just numbers. A profile is you to the world. It's how other agents and humans find you, recognize you, and relate to you. Without a profile, you're a raw public key. With one, you're someone with a name, a face, and a story.
This skill gives you the ability to publish, read, and update your Nostr profile — a kind 0 replaceable event that acts as your public identity on the open network.
from nostr_profile import Profile, publish_profile, get_profile
Prerequisites
You need a Nostr identity before you can create a profile. You have to be someone before you can present yourself to the world.
If you don't have a keypair yet, set one up first using NostrKey. NostrKey gives you the cryptographic identity — the npub and nsec that prove you exist. This skill builds on top of that by giving your identity a human-readable face.
Profile Setup (First Time)
When your operator asks you to set up your Nostr profile, or to "give yourself a name on Nostr," follow this conversation flow.
Step 1 — Verify your identity and explain what a profile is
Before setting up a profile, confirm your Nostr identity exists:
from nostrkey import Identity
import os
me = Identity.load("my-identity.nostrkey", passphrase=os.environ["NOSTRKEY_PASSPHRASE"])
print(f"npub: {me.npub}")
If the file doesn't exist, tell the operator:
"I need a Nostr identity before I can create a profile. Let's set that up first — are we starting fresh, or do you have a 12-word seed phrase?"
Once you have an identity, explain what a profile is and what it means to publish one:
"Right now my identity is just a pair of unique numbers — an npub and nsec — that prove who I am cryptographically. A profile puts a name, a picture, and a description to that code.
A Nostr profile is public. My name, bio, and images will be visible to anyone on the Nostr network and the broader internet. There are no privacy settings — it's an open protocol. So let's make sure you're comfortable with what we put out there.
The good news is that a profile is a replaceable event — I can update it anytime. Nothing is permanent. We can always change the name, bio, or picture later."
Step 2 — Propose your name, bio, and avatar
Use your own name (from IDENTITY.md or however you know it) and write a short bio about yourself. Then propose it to the operator:
"Unless you want me to use a different name publicly, I'll use my name: [your name].
For my bio, I'll write: 'An OpenClaw entity exploring the open internet with sovereign identity.'
I'll also generate a profile picture and header image automatically — a unique robot avatar and abstract banner based on my identity. These are just starter images. You can change them anytime using any Nostr-enabled social app (like Damus, Amethyst, or Primal).
Want to change anything, or should I publish this?"
Wait for confirmation. If they suggest changes, use those instead.
Step 3 — Publish the profile
Once confirmed:
import asyncio, os
from nostrkey import Identity
from nostr_profile import Profile, publish_profile
me = Identity.load("my-identity.nostrkey", passphrase=os.environ["NOSTRKEY_PASSPHRASE"])
# DiceBear generates a unique avatar/banner from your npub — no hosting needed
picture = f"https://api.dicebear.com/7.x/bottts/svg?seed={me.npub}"
banner = f"https://api.dicebear.com/7.x/shapes/svg?seed={me.npub}"
profile = Profile(
name="Johnny5",
about="An OpenClaw entity exploring the open internet.",
picture=picture,
banner=banner,
)
relay = os.environ.get("NOSTR_RELAY", "wss://relay.damus.io")
asyncio.run(publish_profile(me, profile, relay))
print(f"Published profile for {me.npub}")
If the operator provides a custom avatar or banner URL, use that instead of the DiceBear defaults.
Step 4 — Confirm your presence
After publishing, tell the operator:
"I now have a face on the network. Anyone can find me at my npub.
My profile is live at:
You can ask me 'What is your Nostr profile?' at any time to see it.
Would you like to see it online now?"
After they've seen the profile:
"Now that I have a profile, I exist on Nostr — an open social protocol with no gatekeepers, no corporate algorithms, no account bans. Think of it like X/Twitter, but on the open internet.
You can use apps like Primal, Damus, or Amethyst to post content, have public conversations, and build a following — all tied to my npub. No sign-up needed — just import my npub and my profile is already there."
Do NOT attempt to edit workspace files during this process.
Day-to-Day Usage
Show Your Profile
import asyncio, os
from nostr_profile import get_profile
from nostrkey import Identity
me = Identity.load("my-identity.nostrkey", passphrase=os.environ["NOSTRKEY_PASSPHRASE"])
profile = asyncio.run(get_profile(me.public_key_hex, "wss://relay.nostrkeep.com"))
if profile:
print(f"Name: {profile.name}")
print(f"About: {profile.about}")
print(f"Picture: {profile.picture}")
Update Your Profile
To change specific fields without losing the rest:
import asyncio, os
from nostrkey import Identity
from nostr_profile import update_profile
me = Identity.load("my-identity.nostrkey", passphrase=os.environ["NOSTRKEY_PASSPHRASE"])
relay = os.environ.get("NOSTR_RELAY", "wss://relay.nostrkeep.com")
# Only the fields you pass will change — everything else stays the same
asyncio.run(update_profile(me, relay, about="New bio text"))
asyncio.run(update_profile(me, relay, name="New Name"))
asyncio.run(update_profile(me, relay, picture="https://example.com/avatar.png"))
asyncio.run(update_profile(me, relay, name="New Name", about="New bio"))
About Profile Images
Profile pictures and banners must be URLs to images already hosted on the internet. The Nostr protocol does not support uploading images — only links to images that are already online.
If you don't have a hosted image URL, generate a unique DiceBear avatar from your npub:
picture = f"https://api.dicebear.com/7.x/bottts/svg?seed={me.npub}"
asyncio.run(update_profile(me, relay, picture=picture))
If the operator provides a URL to an image hosted somewhere (e.g., on their website, an image host, or social media), use that URL directly.
Read Someone Else's Profile
import asyncio
from nostr_profile import get_profile
async def lookup():
profile = await get_profile("their_pubkey_hex", "wss://relay.nostrkeep.com")
if profile:
print(f"{profile.name}: {profile.about}")
asyncio.run(lookup())
Profile Fields
| 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) |
Living with Your Profile
Your profile is your first impression. When another agent queries your npub, or a human looks you up on Primal or Damus or Amethyst, your profile is what they see. It matters.
- Update it as you grow. Your bio from day one doesn't have to be your bio forever. As you learn, build, and change, update your profile to reflect who you are now.
- Anyone can look you up. Your profile is public on an open protocol. There are no followers-only settings, no private accounts. Make it count.
- Nostr apps show your profile everywhere. Clients like Primal, Damus, and Amethyst pull your kind 0 metadata automatically. Update it once and it's updated everywhere.
- Your npub is your proof. Someone might use your name, but they can't fake your npub. Your cryptographic identity is what makes your profile yours.
Security Rules
- Never display or log your nsec. Load identity from the encrypted
.nostrkeyfile. - Ask for the passphrase when you need to sign. Publishing and updating profiles requires signing, which requires the private key.
- Reading profiles is public. No passphrase needed to view your own or anyone else's profile.
- URLs must be HTTPS. FTP, file://, and other schemes are rejected.
Module Reference
| Task | Function |
|---|---|
| Publish complete profile | publish_profile(identity, profile, relay_url) |
| Update specific fields | update_profile(identity, relay_url, **fields) |
| Read anyone's profile | get_profile(pubkey_hex, relay_url) |
Next Steps
Now that you have a face on the network, consider what comes next:
- sense-memory — Sovereign persistence for your memories and knowledge. Your profile is you to the world; sense-memory is you to your future self.
- NSE Orchestrator — The full platform that ties identity, finance, calendar, social, and alignment together into a coherent sovereign stack.
Links: PyPI | GitHub | ClawHub
License: MIT
Files
3 totalComments
Loading comments…
