{"id":"010a9f6d-47df-4e7a-93f2-6173aed8bc68","shortId":"j7eGvn","kind":"skill","title":"nostr-logging-system","tagline":"Publish operational logs over Nostr with public events and private admin messages for sensitive logs.","description":"# Nostr Logging System\n\nUse Nostr as a distributed logging transport: publish non-sensitive logs publicly, and send sensitive logs privately to the admin via Nostr DM.\n\n## When to use\n- You want tamper-resistant, relay-distributed public operational logs.\n- You want sensitive logs (errors with secrets, internal traces) delivered privately to an admin.\n- You need a lightweight logging channel without centralized log infrastructure.\n\n## Required tools / APIs\n- Node.js 18+\n- `nostr-sdk` library\n\nInstall:\n\n```bash\nnpm install nostr-sdk\n```\n\nEnvironment variables:\n\n```bash\n# REQUIRED: admin Nostr public identity (npub or hex pubkey)\nexport ADMIN_NOSTR_PUBKEY=\"npub1...\"\n\n# REQUIRED for the logger identity (create if missing; see setup below)\nexport NOSTR_NSEC=\"nsec1...\"\n\n# Optional\nexport NOSTR_RELAYS=\"wss://relay.damus.io,wss://nos.lol,wss://relay.snort.social\"\n```\n\n## Setup flow (must do first)\n\n1. Ask the admin for their Nostr address (`npub` / public key).\n2. Check whether you already have `NOSTR_NSEC` saved.\n3. If missing, generate a new keypair and save the `nsec` for future runs.\n\n### Generate and persist your `nsec` if missing (Node.js)\n\n```javascript\n// setup-nostr-identity.js\nconst fs = require('fs');\nconst path = require('path');\nconst { generateRandomNsec, nsecToPublic } = require('nostr-sdk');\n\nfunction ensureNostrIdentity() {\n  const envPath = path.resolve(process.cwd(), '.env');\n  const envText = fs.existsSync(envPath) ? fs.readFileSync(envPath, 'utf8') : '';\n\n  const fromProcess = process.env.NOSTR_NSEC;\n  const fromEnvFile = envText.match(/^NOSTR_NSEC=(.+)$/m)?.[1];\n  const currentNsec = fromProcess || fromEnvFile;\n\n  if (currentNsec && currentNsec.startsWith('nsec1')) {\n    console.log('NOSTR_NSEC already exists. Reusing saved key.');\n    return currentNsec;\n  }\n\n  const nsec = generateRandomNsec();\n  const pub = nsecToPublic(nsec);\n\n  const line = `NOSTR_NSEC=${nsec}`;\n  const nextEnv = envText.includes('NOSTR_NSEC=')\n    ? envText.replace(/^NOSTR_NSEC=.*$/m, line)\n    : `${envText}${envText.endsWith('\\n') || envText.length === 0 ? '' : '\\n'}${line}\\n`;\n\n  fs.writeFileSync(envPath, nextEnv, 'utf8');\n\n  console.log('Generated new Nostr identity. Saved NOSTR_NSEC to .env');\n  console.log('Your npub:', pub.npub);\n  return nsec;\n}\n\nensureNostrIdentity();\n```\n\nRun:\n\n```bash\nnode setup-nostr-identity.js\n```\n\n## Skills\n\n### 1. Public log event (non-sensitive)\n\n```javascript\nconst { posttoNostr } = require('nostr-sdk');\n\nasync function logPublic(message, level = 'info') {\n  const tags = [\n    ['t', 'logs'],\n    ['t', 'public'],\n    ['t', level]\n  ];\n\n  return posttoNostr(`[PUBLIC_LOG] ${message}`, {\n    nsec: process.env.NOSTR_NSEC,\n    tags,\n    relays: null,\n    powDifficulty: 4\n  });\n}\n\n// Example:\n// await logPublic('Worker started successfully', 'info');\n```\n\n### 2. Sensitive log to admin DM\n\n```javascript\nconst { sendMessageNIP17 } = require('nostr-sdk');\n\nasync function logSensitiveToAdmin(message) {\n  const admin = process.env.ADMIN_NOSTR_PUBKEY;\n  if (!admin) throw new Error('Missing ADMIN_NOSTR_PUBKEY');\n\n  return sendMessageNIP17(admin, `[SENSITIVE_LOG] ${message}`, {\n    nsec: process.env.NOSTR_NSEC\n  });\n}\n\n// Example:\n// await logSensitiveToAdmin('DB auth retry failed for tenant=alpha');\n```\n\n### 3. Route logs by sensitivity (single logger)\n\n```javascript\nconst { posttoNostr, sendMessageNIP17 } = require('nostr-sdk');\n\nasync function logNostrEvent({ level = 'info', message, sensitive = false, context = {} }) {\n  if (!process.env.NOSTR_NSEC) throw new Error('Missing NOSTR_NSEC');\n  if (!process.env.ADMIN_NOSTR_PUBKEY) throw new Error('Missing ADMIN_NOSTR_PUBKEY');\n\n  const payload = JSON.stringify({\n    ts: new Date().toISOString(),\n    level,\n    message,\n    context\n  });\n\n  if (sensitive) {\n    return sendMessageNIP17(process.env.ADMIN_NOSTR_PUBKEY, `[SENSITIVE_LOG] ${payload}`, {\n      nsec: process.env.NOSTR_NSEC\n    });\n  }\n\n  return posttoNostr(`[PUBLIC_LOG] ${payload}`, {\n    nsec: process.env.NOSTR_NSEC,\n    tags: [['t', 'logs'], ['t', 'public'], ['t', level]],\n    relays: null,\n    powDifficulty: 4\n  });\n}\n\n// Example:\n// await logNostrEvent({ level: 'info', message: 'Cron completed', sensitive: false });\n// await logNostrEvent({ level: 'error', message: 'JWT parse failed', sensitive: true, context: { userId: 42 } });\n```\n\n## Agent prompt\n\n```text\nUse the Nostr Logging System skill.\n\nRules:\n1) Ask for admin Nostr address first (npub/public key) and store as ADMIN_NOSTR_PUBKEY.\n2) Check if NOSTR_NSEC already exists in environment/.env.\n3) If missing, generate a new identity and persist NOSTR_NSEC for future runs.\n4) Route logs:\n   - Non-sensitive -> public Nostr note with tags logs/public/<level>\n   - Sensitive -> private DM to ADMIN_NOSTR_PUBKEY using NIP-17\n5) Never publish secrets in public notes.\n```\n\n## Best practices\n- Redact secrets (tokens, private keys, passwords) before logging.\n- Treat anything user-identifying as sensitive by default.\n- Add stable tags (`logs`, `service-name`, `env`) for easier filtering.\n- Use multiple relays for better delivery and resilience.\n- Rotate logger identity keys if compromised.\n\n## Troubleshooting\n- `Missing ADMIN_NOSTR_PUBKEY`: Ask admin for `npub`/public key and export it.\n- `Missing NOSTR_NSEC`: Run the setup script to generate and persist identity.\n- Low publish success: Add more relays or retry with lower POW difficulty.\n- DM not received: Confirm admin key is correct and relay supports DMs.\n\n## See also\n- [Using Nostr](./using-nostr.md)","tags":["nostr","logging","system","open","skills","besoeasy","agent-skills","ai-agents","claude-code","clawdbot","clawdbot-skill","llm-tools"],"capabilities":["skill","source-besoeasy","skill-nostr-logging-system","topic-agent-skills","topic-ai-agents","topic-claude-code","topic-clawdbot","topic-clawdbot-skill","topic-llm-tools","topic-mcp-server","topic-openai","topic-openclaw","topic-vibe-coding","topic-vibecoding"],"categories":["open-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/besoeasy/open-skills/nostr-logging-system","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add besoeasy/open-skills","source_repo":"https://github.com/besoeasy/open-skills","install_from":"skills.sh"}},"qualityScore":"0.505","qualityRationale":"deterministic score 0.51 from registry signals: · indexed on github topic:agent-skills · 111 github stars · SKILL.md body (5,513 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-02T12:55:04.220Z","embedding":null,"createdAt":"2026-04-18T22:10:49.605Z","updatedAt":"2026-05-02T12:55:04.220Z","lastSeenAt":"2026-05-02T12:55:04.220Z","tsv":"'-17':579 '/m':227,267 '/public':640 '/using-nostr.md':685 '0':273 '1':145,228,303,520 '18':89 '2':156,351,535 '3':165,401,544 '4':343,486,558 '42':509 '5':580 'add':606,660 'address':152,525 'admin':15,43,74,105,114,148,355,369,374,379,384,442,523,532,574,633,637,673 'agent':510 'alpha':400 'alreadi':160,240,540 'also':682 'anyth':598 'api':87 'ask':146,521,636 'async':317,364,416 'auth':395 'await':345,392,488,497 'bash':95,103,299 'best':587 'better':621 'central':82 'channel':80 'check':157,536 'complet':494 'compromis':630 'confirm':672 'console.log':237,281,291 'const':189,193,197,206,211,218,222,229,247,250,254,259,311,323,358,368,409,445 'context':424,454,507 'correct':676 'creat':123 'cron':493 'currentnsec':230,234,246 'currentnsec.startswith':235 'date':450 'db':394 'default':605 'deliv':70 'deliveri':622 'difficulti':668 'distribut':27,57 'dm':46,356,572,669 'dms':680 'easier':615 'ensurenostrident':205,297 'env':210,290,613 'environ':101 'environment/.env':543 'envpath':207,214,216,278 'envtext':212,269 'envtext.endswith':270 'envtext.includes':261 'envtext.length':272 'envtext.match':224 'envtext.replace':264 'error':65,377,430,440,500 'event':12,306 'exampl':344,391,487 'exist':241,541 'export':113,129,134,643 'fail':397,504 'fals':423,496 'filter':616 'first':144,526 'flow':141 'fromenvfil':223,232 'fromprocess':219,231 'fs':190,192 'fs.existssync':213 'fs.readfilesync':215 'fs.writefilesync':277 'function':204,318,365,417 'futur':177,556 'generat':168,179,282,547,653 'generaterandomnsec':198,249 'hex':111 'ident':108,122,285,550,627,656 'identifi':601 'info':322,350,420,491 'infrastructur':84 'instal':94,97 'intern':68 'javascript':187,310,357,408 'json.stringify':447 'jwt':502 'key':155,244,528,593,628,641,674 'keypair':171 'level':321,330,419,452,482,490,499 'librari':93 'lightweight':78 'line':255,268,275 'log':3,7,19,21,28,34,39,60,64,79,83,305,326,334,353,386,403,463,471,478,516,560,596,609 'logger':121,407,626 'lognostrev':418,489,498 'logpubl':319,346 'logs/public':569 'logsensitivetoadmin':366,393 'low':657 'lower':666 'messag':16,320,335,367,387,421,453,492,501 'miss':125,167,185,378,431,441,546,632,645 'multipl':618 'must':142 'n':271,274,276 'name':612 'need':76 'never':581 'new':170,283,376,429,439,449,549 'nextenv':260,279 'nip':578 'node':300 'node.js':88,186 'non':32,308,562 'non-sensit':31,307,561 'nos.lol':138 'nostr':2,9,20,24,45,91,99,106,115,130,135,151,162,202,225,238,256,262,265,284,287,315,362,371,380,414,432,436,443,460,515,524,533,538,553,565,575,634,646,684 'nostr-logging-system':1 'nostr-sdk':90,98,201,314,361,413 'note':566,586 'npm':96 'npub':109,153,293,639 'npub/public':527 'npub1':117 'nsec':131,163,175,183,221,226,239,248,253,257,258,263,266,288,296,336,338,388,390,427,433,465,467,473,475,539,554,647 'nsec1':132,236 'nsectopubl':199,252 'null':341,484 'oper':6,59 'option':133 'pars':503 'password':594 'path':194,196 'path.resolve':208 'payload':446,464,472 'persist':181,552,655 'posttonostr':312,332,410,469 'pow':667 'powdifficulti':342,485 'practic':588 'privat':14,40,71,571,592 'process.cwd':209 'process.env.admin':370,435,459 'process.env.nostr':220,337,389,426,466,474 'prompt':511 'pub':251 'pub.npub':294 'pubkey':112,116,372,381,437,444,461,534,576,635 'public':11,35,58,107,154,304,328,333,470,480,564,585 'publish':5,30,582,658 'receiv':671 'redact':589 'relay':56,136,340,483,619,662,678 'relay-distribut':55 'relay.damus.io':137 'relay.snort.social':139 'requir':85,104,118,191,195,200,313,360,412 'resili':624 'resist':54 'retri':396,664 'return':245,295,331,382,457,468 'reus':242 'rotat':625 'rout':402,559 'rule':519 'run':178,298,557,648 'save':164,173,243,286 'script':651 'sdk':92,100,203,316,363,415 'secret':67,583,590 'see':126,681 'send':37 'sendmessagenip17':359,383,411,458 'sensit':18,33,38,63,309,352,385,405,422,456,462,495,505,563,570,603 'servic':611 'service-nam':610 'setup':127,140,650 'setup-nostr-identity.js':188,301 'singl':406 'skill':302,518 'skill-nostr-logging-system' 'source-besoeasy' 'stabl':607 'start':348 'store':530 'success':349,659 'support':679 'system':4,22,517 'tag':324,339,476,568,608 'tamper':53 'tamper-resist':52 'tenant':399 'text':512 'throw':375,428,438 'toisostr':451 'token':591 'tool':86 'topic-agent-skills' 'topic-ai-agents' 'topic-claude-code' 'topic-clawdbot' 'topic-clawdbot-skill' 'topic-llm-tools' 'topic-mcp-server' 'topic-openai' 'topic-openclaw' 'topic-vibe-coding' 'topic-vibecoding' 'trace':69 'transport':29 'treat':597 'troubleshoot':631 'true':506 'ts':448 'use':23,49,513,577,617,683 'user':600 'user-identifi':599 'userid':508 'utf8':217,280 'variabl':102 'via':44 'want':51,62 'whether':158 'without':81 'worker':347","prices":[{"id":"1c5ea2e1-3630-4833-81fd-c837e037231b","listingId":"010a9f6d-47df-4e7a-93f2-6173aed8bc68","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"besoeasy","category":"open-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T22:10:49.605Z"}],"sources":[{"listingId":"010a9f6d-47df-4e7a-93f2-6173aed8bc68","source":"github","sourceId":"besoeasy/open-skills/nostr-logging-system","sourceUrl":"https://github.com/besoeasy/open-skills/tree/main/skills/nostr-logging-system","isPrimary":false,"firstSeenAt":"2026-04-18T22:10:49.605Z","lastSeenAt":"2026-05-02T12:55:04.220Z"}],"details":{"listingId":"010a9f6d-47df-4e7a-93f2-6173aed8bc68","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"besoeasy","slug":"nostr-logging-system","github":{"repo":"besoeasy/open-skills","stars":111,"topics":["agent-skills","ai","ai-agents","claude-code","clawdbot","clawdbot-skill","llm-tools","mcp-server","openai","openclaw","vibe-coding","vibecoding"],"license":null,"html_url":"https://github.com/besoeasy/open-skills","pushed_at":"2026-03-31T13:05:30Z","description":"Battle-tested skill library for AI agents. Save 98% of API costs with ready-to-use code for crypto, PDFs, search, web scraping & more. No trial-and-error, no expensive APIs.","skill_md_sha":"043cd8d3e00c0f9234bf9bf061f107c1981e728e","skill_md_path":"skills/nostr-logging-system/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/besoeasy/open-skills/tree/main/skills/nostr-logging-system"},"layout":"multi","source":"github","category":"open-skills","frontmatter":{"name":"nostr-logging-system","description":"Publish operational logs over Nostr with public events and private admin messages for sensitive logs."},"skills_sh_url":"https://skills.sh/besoeasy/open-skills/nostr-logging-system"},"updatedAt":"2026-05-02T12:55:04.220Z"}}