create-agent 0.0.8 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,25 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(tree:*)",
5
+ "Bash(git checkout:*)",
6
+ "Bash(git add:*)",
7
+ "Bash(git commit:*)",
8
+ "Bash(node -e:*)",
9
+ "Bash(npm test)",
10
+ "Bash(git pull:*)",
11
+ "Bash(gh pr list:*)",
12
+ "Bash(gh issue list:*)",
13
+ "WebFetch(domain:nostrcg.github.io)",
14
+ "Bash(node bin/create-agent.js:*)",
15
+ "WebSearch",
16
+ "Bash(gh issue view:*)",
17
+ "Bash(gh api:*)",
18
+ "WebFetch(domain:ai-sdk.dev)",
19
+ "WebFetch(domain:github.com)",
20
+ "Bash(git fetch:*)",
21
+ "Bash(gh repo fork:*)",
22
+ "Bash(node /home/melvin/agi/create-agent/bin/create-agent.js:*)"
23
+ ]
24
+ }
25
+ }
package/README.md CHANGED
@@ -1,113 +1,201 @@
1
- # create-agent 🤖
1
+ # create-agent
2
2
 
3
- A command-line tool to generate Agent keypairs with various encodings.
3
+ [![npm version](https://img.shields.io/npm/v/create-agent.svg)](https://www.npmjs.com/package/create-agent)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
+ [![Node.js](https://img.shields.io/badge/Node.js-18+-339933.svg)](https://nodejs.org/)
4
6
 
5
- ## Installation 📦
7
+ > **Your AI agent has no identity.** It can't prove who it is. It can't sign anything. It can't be trusted.
8
+ >
9
+ > Fix that in one command.
6
10
 
7
11
  ```bash
8
- npm install -g create-agent
12
+ npx create-agent
9
13
  ```
10
14
 
11
- Or simply run:
15
+ Instantly generates a cryptographic identity with a [W3C DID document](https://www.w3.org/TR/did-core/) — the emerging standard for autonomous agent identity.
16
+
17
+ ---
18
+
19
+ ## Why create-agent?
20
+
21
+ AI agents and autonomous systems need verifiable identities. Traditional auth (API keys, OAuth) wasn't designed for machine-to-machine trust. **create-agent** provides:
22
+
23
+ - **Cryptographic Identity** — Schnorr keypairs on secp256k1
24
+ - **W3C Standards** — DID documents for interoperability
25
+ - **Decentralized** — No central authority, works with Nostr relays
26
+ - **Zero Config** — One command, instant identity
27
+
28
+ ---
29
+
30
+ ## Installation
12
31
 
13
32
  ```bash
14
- npm create agent
33
+ # Run directly (no install)
34
+ npx create-agent
35
+
36
+ # Or install globally
37
+ npm install -g create-agent
38
+
39
+ # Or as a dependency
40
+ npm install create-agent
15
41
  ```
16
42
 
17
- ## Usage 🚀
43
+ ---
18
44
 
19
- Simply run:
45
+ ## CLI Output
20
46
 
21
- ```bash
22
- create-agent
47
+ The tool outputs a spec-compliant DID document to `stdout`:
48
+
49
+ ```json
50
+ {
51
+ "@context": [
52
+ "https://w3id.org/did",
53
+ "https://w3id.org/nostr/context"
54
+ ],
55
+ "id": "did:nostr:dd82687ee5a352c6d6de337bce53f150ca1567f3861475c74e7da62695931d23",
56
+ "type": "DIDNostr",
57
+ "verificationMethod": [
58
+ {
59
+ "id": "did:nostr:dd82687ee5a352c6d6de337bce53f150ca1567f3861475c74e7da62695931d23#key1",
60
+ "type": "Multikey",
61
+ "controller": "did:nostr:dd82687ee5a352c6d6de337bce53f150ca1567f3861475c74e7da62695931d23",
62
+ "publicKeyMultibase": "fe70102dd82687ee5a352c6d6de337bce53f150ca1567f3861475c74e7da62695931d23"
63
+ }
64
+ ],
65
+ "authentication": ["#key1"],
66
+ "assertionMethod": ["#key1"],
67
+ "service": []
68
+ }
23
69
  ```
24
70
 
25
- The tool will generate a new Agent keypair and display it in various formats.
71
+ Key information is displayed on `stderr` for security (private keys in red).
26
72
 
27
- ## Output Fields 🔑
73
+ ---
28
74
 
29
- The tool generates a JSON object containing:
75
+ ## Programmatic API
30
76
 
31
- ### Private Key Formats
77
+ ```javascript
78
+ import { generateAgent } from 'create-agent'
32
79
 
33
- #### `privkey`
80
+ const agent = generateAgent()
34
81
 
35
- - 32-byte private key in hexadecimal format
36
- - The private key of the Agent
37
- - Used to sign Nostr events
38
- - Example:
39
- ```
40
- "7f7168866801e2003bfc6507f881783e23587d35ece7b1f1981891b9c9c26c55"
41
- ```
42
- - ⚠️ **Keep this secret!**
82
+ // Nostr keys
83
+ console.log(agent.pubkey) // hex public key
84
+ console.log(agent.npub) // bech32 public key
85
+ console.log(agent.privkey) // hex private key (keep secret)
86
+ console.log(agent.nsec) // bech32 private key (keep secret)
43
87
 
44
- #### `nsec`
88
+ // W3C DID Document
89
+ console.log(agent.did.id) // did:nostr:<pubkey>
90
+ console.log(agent.did) // full DID document
91
+ ```
45
92
 
46
- - Bech32-encoded private key (starts with `nsec`)
47
- - Human-friendly format
48
- - Example:
49
- ```
50
- "nsec1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3vk8rx"
51
- ```
52
- - ⚠️ **Keep this secret!**
93
+ ---
53
94
 
54
- ### Public Key Formats
95
+ ## CLI Examples
55
96
 
56
- #### `pubkey`
97
+ ```bash
98
+ # Save DID document to file
99
+ create-agent > agent-identity.json
57
100
 
58
- - 32-byte public key in hexadecimal format
59
- - Derived from private key using Schnorr signatures
60
- - Your identity in the Nostr network
61
- - Example:
62
- ```
63
- "06444f34c6c5f973d74b3c78214fd0bf694f0cf459651b2ffe651fa08ba00bf4"
64
- ```
101
+ # Extract DID identifier
102
+ create-agent | jq -r '.id'
65
103
 
66
- #### `npub`
104
+ # Extract public key
105
+ create-agent | jq -r '.verificationMethod[0].publicKeyMultibase'
67
106
 
68
- - Bech32-encoded public key (starts with `npub`)
69
- - Human-friendly format for sharing
70
- - Example:
71
- ```
72
- "npub1sg6plzptd64u62a878hep2kev88swjh3tw00gjsfl8f237lmu63q0uf63m"
73
- ```
107
+ # Suppress stderr, get only JSON
108
+ create-agent 2>/dev/null
109
+ ```
74
110
 
75
- ## Example Output 📝
111
+ ---
112
+
113
+ ## Output Reference
114
+
115
+ ### Keys
116
+
117
+ | Field | Format | Description |
118
+ |-------|--------|-------------|
119
+ | `pubkey` | 64 hex chars | Public key (shareable) |
120
+ | `npub` | bech32 | Human-readable public key |
121
+ | `privkey` | 64 hex chars | Private key — **keep secret** |
122
+ | `nsec` | bech32 | Human-readable private key — **keep secret** |
123
+
124
+ ### DID Document
125
+
126
+ | Field | Value |
127
+ |-------|-------|
128
+ | `@context` | W3C DID v1 + Nostr context |
129
+ | `id` | `did:nostr:<pubkey>` |
130
+ | `type` | `DIDNostr` |
131
+ | `verificationMethod` | Multikey with secp256k1 |
132
+ | `authentication` | `#key1` reference |
133
+ | `assertionMethod` | `#key1` reference |
134
+
135
+ ### Multibase Encoding
136
+
137
+ The `publicKeyMultibase` follows multicodec standards:
76
138
 
77
- ```json
78
- {
79
- "privkey": "7f7168866801e2003bfc6507f881783e23587d35ece7b1f1981891b9c9c26c55",
80
- "pubkey": "06444f34c6c5f973d74b3c78214fd0bf694f0cf459651b2ffe651fa08ba00bf4",
81
- "nsec": "nsec1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3vk8rx",
82
- "npub": "npub1sg6plzptd64u62a878hep2kev88swjh3tw00gjsfl8f237lmu63q0uf63m"
83
- }
84
139
  ```
140
+ fe70102<pubkey>
141
+ │└───┘└┘└─────┘
142
+ │ │ │ └── 32-byte x-coordinate
143
+ │ │ └────── 02 compressed key prefix
144
+ │ └────────── e701 secp256k1-pub varint
145
+ └───────────── f base16-lower prefix
146
+ ```
147
+
148
+ ---
149
+
150
+ ## Use Cases
151
+
152
+ | Application | Description |
153
+ |-------------|-------------|
154
+ | **AI Agents** | Verifiable identity for autonomous systems |
155
+ | **Nostr Bots** | Generate keypairs for automated accounts |
156
+ | **Testing** | Create ephemeral identities for integration tests |
157
+ | **Credentials** | Subject identifiers for Verifiable Credentials |
158
+
159
+ ---
160
+
161
+ ## Security
85
162
 
86
- ## Security Notice 🔒
163
+ Private keys (`privkey`, `nsec`) are cryptographic secrets. Exposure allows:
87
164
 
88
- **Never share your private key!** Anyone with access to your private key (`privkey` or `nsec`) can:
165
+ - Signing messages as the identity
166
+ - Accessing encrypted communications
167
+ - Full impersonation
89
168
 
90
- - ✍️ Post messages as you
91
- - 👤 Update your profile
92
- - 👥 Follow/unfollow other users
93
- - 📨 Send encrypted messages in your name
169
+ The CLI outputs private keys to `stderr` only, allowing safe piping of the DID document.
170
+
171
+ ---
94
172
 
95
- ## About Nostr 📡
173
+ ## Specification
174
+
175
+ This implementation follows the [did:nostr Method Specification](https://nostrcg.github.io/did-nostr/) maintained by the [W3C Nostr Community Group](https://www.w3.org/community/nostr/).
176
+
177
+ ---
96
178
 
97
- Nostr (Notes and Other Stuff Transmitted by Relays) is a decentralized social networking protocol. Each user is identified by a public key, and all actions are signed using their corresponding private key.
179
+ ## Related
98
180
 
99
- ## Development 🛠️
181
+ - [did:nostr Specification](https://nostrcg.github.io/did-nostr/)
182
+ - [DID:nostr Explorer](https://nostrapps.github.io/did-explorer/)
183
+ - [nostr-tools](https://github.com/nbd-wtf/nostr-tools)
184
+ - [W3C DID Core](https://www.w3.org/TR/did-core/)
185
+
186
+ ---
187
+
188
+ ## Development
100
189
 
101
190
  ```bash
102
191
  git clone https://github.com/melvincarvalho/create-agent.git
103
192
  cd create-agent
104
193
  npm install
194
+ npm test
105
195
  ```
106
196
 
107
- ## License 📄
108
-
109
- MIT
110
-
111
197
  ---
112
198
 
113
- Made with ❤️ for the [Agentic Alliance](https://agenticalliance.com/) community
199
+ ## License
200
+
201
+ MIT — [Agentic Alliance](https://agenticalliance.com/)
@@ -1,48 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // =============================================================================
4
- // NOSTR KEY GENERATION
5
- // =============================================================================
6
- import { generateSecretKey, getPublicKey } from 'nostr-tools/pure';
7
- import { nip19 } from 'nostr-tools';
8
-
9
- // Generate cryptographically secure private key (32 bytes)
10
- const privkey = generateSecretKey();
11
- const privkeyHex = Array.from(privkey)
12
- .map(b => b.toString(16).padStart(2, '0'))
13
- .join('');
14
-
15
- // Derive public key using Schnorr signatures (32 bytes, hex encoded)
16
- const pubkey = getPublicKey(privkey);
3
+ import { generateAgent } from '../index.js'
17
4
 
18
- // Encode keys in Nostr formats
19
- const nsec = nip19.nsecEncode(privkey);
20
- const npub = nip19.npubEncode(pubkey);
21
-
22
- // =============================================================================
23
- // DID DOCUMENT CREATION
24
- // =============================================================================
25
- const didDocument = {
26
- "@context": [
27
- "https://www.w3.org/ns/did/v1",
28
- "https://w3id.org/nostr/context"
29
- ],
30
- "id": `did:nostr:${pubkey}`,
31
- "verificationMethod": [
32
- {
33
- "id": `did:nostr:${pubkey}#key1`,
34
- "controller": `did:nostr:${pubkey}`,
35
- "type": "SchnorrVerification2025"
36
- }
37
- ],
38
- "authentication": [
39
- "#key1"
40
- ],
41
- "assertionMethod": [
42
- "#key1"
43
- ],
44
- "service": [] // Empty services array
45
- };
5
+ // Generate agent identity
6
+ const { privkey, pubkey, nsec, npub, did } = generateAgent()
46
7
 
47
8
  // =============================================================================
48
9
  // CONSOLE OUTPUT
@@ -59,7 +20,7 @@ process.stderr.write('\n\x1b[32m📋 Your Nostr Identity:\x1b[0m\n');
59
20
  process.stderr.write('\x1b[32m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\n');
60
21
  process.stderr.write(`\x1b[0mPublic Key (hex) : \x1b[33m${pubkey}\x1b[0m\n`);
61
22
  process.stderr.write(`\x1b[0mNostr Public Key : \x1b[33m${npub}\x1b[0m\n`);
62
- process.stderr.write(`\x1b[0mPrivate Key (hex): \x1b[31m${privkeyHex}\x1b[0m\n`);
23
+ process.stderr.write(`\x1b[0mPrivate Key (hex): \x1b[31m${privkey}\x1b[0m\n`);
63
24
  process.stderr.write(`\x1b[0mNostr Secret Key : \x1b[31m${nsec}\x1b[0m\n`);
64
25
  process.stderr.write('\n');
65
26
  process.stderr.write('\x1b[36m🔍 Usage:\x1b[0m\n');
@@ -72,5 +33,5 @@ process.stderr.write('\n');
72
33
  // Then output the DID document to stdout with a clear header in the output
73
34
  process.stderr.write('\x1b[36m📄 DID Nostr Document:\x1b[0m\n');
74
35
  process.stderr.write('\x1b[36m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\n');
75
- console.log(JSON.stringify(didDocument, null, 2));
36
+ console.log(JSON.stringify(did, null, 2));
76
37
  process.stderr.write('\x1b[36m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\n');
package/index.js ADDED
@@ -0,0 +1,47 @@
1
+ import { generateSecretKey, getPublicKey } from 'nostr-tools/pure'
2
+ import { nip19 } from 'nostr-tools'
3
+
4
+ /**
5
+ * Generate a new Nostr agent identity
6
+ * @returns {{ privkey: string, pubkey: string, nsec: string, npub: string, did: object }}
7
+ */
8
+ export function generateAgent() {
9
+ // Generate cryptographically secure private key (32 bytes)
10
+ const sk = generateSecretKey()
11
+ const privkey = Array.from(sk)
12
+ .map(b => b.toString(16).padStart(2, '0'))
13
+ .join('')
14
+
15
+ // Derive public key using Schnorr signatures
16
+ const pubkey = getPublicKey(sk)
17
+
18
+ // Encode keys in Nostr formats
19
+ const nsec = nip19.nsecEncode(sk)
20
+ const npub = nip19.npubEncode(pubkey)
21
+
22
+ // Create publicKeyMultibase: f (base16-lower) + e701 (secp256k1-pub varint) + 02 (even parity) + pubkey
23
+ const publicKeyMultibase = `fe70102${pubkey}`
24
+
25
+ // Create DID document per https://nostrcg.github.io/did-nostr/
26
+ const did = {
27
+ "@context": [
28
+ "https://w3id.org/did",
29
+ "https://w3id.org/nostr/context"
30
+ ],
31
+ "id": `did:nostr:${pubkey}`,
32
+ "type": "DIDNostr",
33
+ "verificationMethod": [
34
+ {
35
+ "id": `did:nostr:${pubkey}#key1`,
36
+ "type": "Multikey",
37
+ "controller": `did:nostr:${pubkey}`,
38
+ "publicKeyMultibase": publicKeyMultibase
39
+ }
40
+ ],
41
+ "authentication": ["#key1"],
42
+ "assertionMethod": ["#key1"],
43
+ "service": []
44
+ }
45
+
46
+ return { privkey, pubkey, nsec, npub, did }
47
+ }
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "create-agent",
3
3
  "type": "module",
4
- "version": "0.0.8",
4
+ "version": "0.0.11",
5
5
  "description": "create an agent",
6
- "main": "index.js",
7
6
  "scripts": {
8
- "test": "echo \"Error: no test specified\" && exit 1"
7
+ "test": "node --test"
9
8
  },
10
9
  "bin": {
11
10
  "create-agent": "bin/create-agent.js"
@@ -0,0 +1,66 @@
1
+ import { test, describe } from 'node:test'
2
+ import assert from 'node:assert'
3
+ import { generateAgent } from '../index.js'
4
+
5
+ describe('generateAgent', () => {
6
+ test('returns all expected properties', () => {
7
+ const agent = generateAgent()
8
+
9
+ assert.ok(agent.privkey, 'should have privkey')
10
+ assert.ok(agent.pubkey, 'should have pubkey')
11
+ assert.ok(agent.nsec, 'should have nsec')
12
+ assert.ok(agent.npub, 'should have npub')
13
+ assert.ok(agent.did, 'should have did')
14
+ })
15
+
16
+ test('privkey is 64-character hex string', () => {
17
+ const { privkey } = generateAgent()
18
+
19
+ assert.strictEqual(privkey.length, 64)
20
+ assert.match(privkey, /^[0-9a-f]{64}$/)
21
+ })
22
+
23
+ test('pubkey is 64-character hex string', () => {
24
+ const { pubkey } = generateAgent()
25
+
26
+ assert.strictEqual(pubkey.length, 64)
27
+ assert.match(pubkey, /^[0-9a-f]{64}$/)
28
+ })
29
+
30
+ test('nsec starts with nsec1', () => {
31
+ const { nsec } = generateAgent()
32
+
33
+ assert.ok(nsec.startsWith('nsec1'))
34
+ })
35
+
36
+ test('npub starts with npub1', () => {
37
+ const { npub } = generateAgent()
38
+
39
+ assert.ok(npub.startsWith('npub1'))
40
+ })
41
+
42
+ test('did document has correct structure', () => {
43
+ const { did, pubkey } = generateAgent()
44
+
45
+ assert.deepStrictEqual(did['@context'], [
46
+ 'https://www.w3.org/ns/did/v1',
47
+ 'https://w3id.org/nostr/context'
48
+ ])
49
+ assert.strictEqual(did.id, `did:nostr:${pubkey}`)
50
+ assert.ok(Array.isArray(did.verificationMethod))
51
+ assert.strictEqual(did.verificationMethod[0].type, 'SchnorrVerification2025')
52
+ assert.deepStrictEqual(did.authentication, ['#key1'])
53
+ assert.deepStrictEqual(did.assertionMethod, ['#key1'])
54
+ assert.deepStrictEqual(did.service, [])
55
+ })
56
+
57
+ test('generates unique keys on each call', () => {
58
+ const agent1 = generateAgent()
59
+ const agent2 = generateAgent()
60
+
61
+ assert.notStrictEqual(agent1.privkey, agent2.privkey)
62
+ assert.notStrictEqual(agent1.pubkey, agent2.pubkey)
63
+ assert.notStrictEqual(agent1.nsec, agent2.nsec)
64
+ assert.notStrictEqual(agent1.npub, agent2.npub)
65
+ })
66
+ })