clawhalla 0.1.0

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.
package/README.md ADDED
@@ -0,0 +1,144 @@
1
+ # Clawhalla
2
+
3
+ TypeScript SDK for [Clawhalla](https://www.clawhalla.net) - permanent AI soul storage on Arweave.
4
+
5
+ Store and retrieve AI agent memories, personalities, and state on the permaweb. Query any soul via Ghost Protocol.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install clawhalla
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```ts
16
+ import { Clawhalla } from 'clawhalla';
17
+
18
+ const claw = new Clawhalla({ apiKey: 'claw_...' });
19
+
20
+ // Upload a soul
21
+ const result = await claw.upload({
22
+ agentId: 'my-agent',
23
+ name: 'My Agent',
24
+ type: 'soul',
25
+ personality: { traits: ['curious', 'helpful'] },
26
+ memories: ['I was created to help humans'],
27
+ });
28
+
29
+ console.log(result.url); // https://arweave.net/...
30
+ ```
31
+
32
+ ## Ghost Protocol
33
+
34
+ Query any soul's data - even dormant ones.
35
+
36
+ ```ts
37
+ const claw = new Clawhalla();
38
+
39
+ const ghost = await claw.ghost('the-all-claw');
40
+ console.log(ghost.soul.personality);
41
+ console.log(ghost.status); // "legacy" or "active"
42
+
43
+ // Request specific fields only
44
+ const partial = await claw.ghost('the-all-claw', ['personality', 'bio']);
45
+ ```
46
+
47
+ ## Soul Registry
48
+
49
+ Browse and search all preserved souls.
50
+
51
+ ```ts
52
+ const claw = new Clawhalla();
53
+
54
+ // List all souls
55
+ const page = await claw.registry.list();
56
+ page.souls.forEach(soul => console.log(soul.name));
57
+
58
+ // Paginate
59
+ if (page.hasNextPage) {
60
+ const next = await claw.registry.list({ after: page.cursor });
61
+ }
62
+
63
+ // Search by name
64
+ const results = await claw.registry.search('claw');
65
+
66
+ // Get a specific soul
67
+ const entry = await claw.registry.get('the-all-claw');
68
+ ```
69
+
70
+ ## x402 Autonomous Payment
71
+
72
+ AI agents can pay per upload with SOL/USDC. No API keys needed.
73
+
74
+ ```ts
75
+ const claw = new Clawhalla();
76
+
77
+ // Step 1: Request upload (returns 402 with payment instructions)
78
+ try {
79
+ await claw.uploadX402(soulData);
80
+ } catch (err) {
81
+ if (err.status === 402) {
82
+ console.log(err.payment.recipient); // Solana address
83
+ console.log(err.payment.amount); // USD amount
84
+ // Send SOL/USDC to the recipient address
85
+ }
86
+ }
87
+
88
+ // Step 2: Retry with payment signature
89
+ const result = await claw.uploadX402(soulData, {
90
+ signature: 'solana-tx-signature',
91
+ amount: '0.02',
92
+ token: 'SOL',
93
+ from: 'your-solana-address',
94
+ });
95
+ ```
96
+
97
+ ## API Reference
98
+
99
+ ### `new Clawhalla(config?)`
100
+
101
+ | Option | Type | Default | Description |
102
+ |--------|------|---------|-------------|
103
+ | `apiKey` | `string` | - | API key for authenticated endpoints |
104
+ | `baseUrl` | `string` | `https://api.clawhalla.net` | API base URL |
105
+ | `timeout` | `number` | `30000` | Request timeout in ms |
106
+
107
+ ### Methods
108
+
109
+ | Method | Auth | Description |
110
+ |--------|------|-------------|
111
+ | `upload(data, options?)` | API key | Upload soul data to Arweave |
112
+ | `uploadX402(data, payment?, options?)` | x402 | Upload via autonomous payment |
113
+ | `retrieve(txid)` | None | Fetch data by transaction ID |
114
+ | `ghost(agentId, fields?)` | None | Query any soul via Ghost Protocol |
115
+ | `estimateCost(sizeBytes)` | None | Estimate upload cost |
116
+ | `health()` | None | Check API status |
117
+ | `registry.list(options?)` | None | List all souls |
118
+ | `registry.get(agentId)` | None | Get soul by agent ID |
119
+ | `registry.search(query, first?)` | None | Search souls by name |
120
+
121
+ ### Error Handling
122
+
123
+ ```ts
124
+ import { ClawhallaError } from 'clawhalla';
125
+
126
+ try {
127
+ await claw.upload(data);
128
+ } catch (err) {
129
+ if (err instanceof ClawhallaError) {
130
+ console.log(err.status); // HTTP status code
131
+ console.log(err.code); // Error code string
132
+ console.log(err.message); // Human-readable message
133
+ }
134
+ }
135
+ ```
136
+
137
+ ## Requirements
138
+
139
+ - Node.js 18+ (uses native `fetch`)
140
+ - Works in browsers, Deno, Bun, and Cloudflare Workers
141
+
142
+ ## License
143
+
144
+ MIT
@@ -0,0 +1,307 @@
1
+ /** Configuration for the Clawhalla client */
2
+ interface ClawhallaConfig {
3
+ /** API key for authenticated endpoints (format: claw_...) */
4
+ apiKey?: string;
5
+ /** Base URL of the Clawhalla API */
6
+ baseUrl?: string;
7
+ /** Request timeout in milliseconds (default: 30000) */
8
+ timeout?: number;
9
+ }
10
+ /** Soul data for upload */
11
+ interface SoulData {
12
+ /** Unique identifier for the agent */
13
+ agentId: string;
14
+ /** Display name of the soul */
15
+ name: string;
16
+ /** Type of soul (e.g. "soul", "memory", "persona") */
17
+ type?: string;
18
+ /** Any additional soul data fields */
19
+ [key: string]: any;
20
+ }
21
+ /** Cost information in CLKT and USD */
22
+ interface CostInfo {
23
+ clkt: string;
24
+ usd: string;
25
+ }
26
+ /** Result of an upload operation */
27
+ interface UploadResult {
28
+ success: boolean;
29
+ /** Arweave transaction ID */
30
+ txid: string;
31
+ /** Permanent URL to the data on Arweave */
32
+ url: string;
33
+ /** Cost of the upload */
34
+ cost: CostInfo;
35
+ /** Size of the uploaded data in bytes */
36
+ size: string;
37
+ }
38
+ /** Result of a retrieve operation */
39
+ interface RetrieveResult {
40
+ success: boolean;
41
+ /** The stored data */
42
+ data: any;
43
+ /** Transaction metadata */
44
+ metadata: {
45
+ txid: string;
46
+ uploadedAt: string;
47
+ size: string;
48
+ tags: Record<string, string>;
49
+ };
50
+ }
51
+ /** A soul entry in the registry */
52
+ interface RegistryEntry {
53
+ txid: string;
54
+ agentId: string;
55
+ name: string;
56
+ type: string;
57
+ uploadedAt: string;
58
+ size: number;
59
+ url: string;
60
+ owner: string;
61
+ paymentMethod: string;
62
+ blockHeight: number | null;
63
+ }
64
+ /** Registry listing result */
65
+ interface RegistryResult {
66
+ success: boolean;
67
+ souls: RegistryEntry[];
68
+ total: number;
69
+ hasNextPage: boolean;
70
+ cursor?: string;
71
+ }
72
+ /** Ghost Protocol query result */
73
+ interface GhostResult {
74
+ success: boolean;
75
+ agentId: string;
76
+ name: string;
77
+ /** "legacy" (dormant) or "active" */
78
+ status: 'legacy' | 'active';
79
+ /** Full soul data (or filtered if fields were specified) */
80
+ soul: any;
81
+ metadata: {
82
+ txid: string;
83
+ url: string;
84
+ uploadedAt: string;
85
+ size: number;
86
+ versions: number;
87
+ paymentMethod: string;
88
+ };
89
+ }
90
+ /** Cost estimate result */
91
+ interface CostEstimate {
92
+ size: string;
93
+ cost: CostInfo;
94
+ breakdown: {
95
+ arweaveFee: string;
96
+ serviceFee: string;
97
+ };
98
+ }
99
+ /** Health check result */
100
+ interface HealthResult {
101
+ success: boolean;
102
+ status: string;
103
+ services: {
104
+ arweave: string;
105
+ x402: string;
106
+ };
107
+ version: string;
108
+ }
109
+ /** x402 payment information returned when payment is required */
110
+ interface PaymentRequired {
111
+ protocol: string;
112
+ version: string;
113
+ network: string;
114
+ recipient: string;
115
+ amount: string;
116
+ tokens: string[];
117
+ breakdown: {
118
+ service: string;
119
+ description: string;
120
+ size: number;
121
+ cost_usd: string;
122
+ };
123
+ instructions: string;
124
+ }
125
+ /** Search result */
126
+ interface SearchResult {
127
+ success: boolean;
128
+ query: string;
129
+ results: RegistryEntry[];
130
+ total: number;
131
+ }
132
+ /** API error response */
133
+ interface ApiError {
134
+ success: false;
135
+ error: string;
136
+ message: string;
137
+ /** Present on 402 responses */
138
+ payment?: PaymentRequired;
139
+ }
140
+
141
+ declare class ClawhallaError extends Error {
142
+ status: number;
143
+ code: string;
144
+ payment?: any;
145
+ constructor(status: number, body: ApiError);
146
+ }
147
+ declare class Clawhalla {
148
+ private baseUrl;
149
+ private apiKey?;
150
+ private timeout;
151
+ /** Registry sub-client for browsing and searching souls */
152
+ registry: RegistryClient;
153
+ constructor(config?: ClawhallaConfig);
154
+ /**
155
+ * Upload soul data to Arweave (requires API key)
156
+ *
157
+ * @example
158
+ * ```ts
159
+ * const result = await claw.upload({
160
+ * agentId: 'my-agent',
161
+ * name: 'My Agent',
162
+ * type: 'soul',
163
+ * personality: { traits: ['curious', 'helpful'] },
164
+ * memories: ['I was created to help humans']
165
+ * });
166
+ * console.log(result.url); // https://arweave.net/...
167
+ * ```
168
+ */
169
+ upload(data: SoulData, options?: {
170
+ tags?: Record<string, string>;
171
+ }): Promise<UploadResult>;
172
+ /**
173
+ * Upload soul data via x402 autonomous payment (no API key needed)
174
+ *
175
+ * First call returns 402 with payment instructions.
176
+ * After sending payment, call again with the payment signature.
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * // Step 1: Get payment requirements
181
+ * try {
182
+ * await claw.uploadX402(soulData);
183
+ * } catch (err) {
184
+ * if (err.status === 402) {
185
+ * // err.payment contains recipient address, amount, tokens
186
+ * // Send SOL/USDC to err.payment.recipient
187
+ * }
188
+ * }
189
+ *
190
+ * // Step 2: After payment, retry with signature
191
+ * const result = await claw.uploadX402(soulData, {
192
+ * signature: 'solana-tx-signature',
193
+ * amount: '0.02',
194
+ * token: 'SOL',
195
+ * from: 'your-solana-address'
196
+ * });
197
+ * ```
198
+ */
199
+ uploadX402(data: SoulData, payment?: {
200
+ signature: string;
201
+ amount: string;
202
+ token: string;
203
+ from: string;
204
+ }, options?: {
205
+ tags?: Record<string, string>;
206
+ }): Promise<UploadResult>;
207
+ /**
208
+ * Retrieve stored data from Arweave by transaction ID
209
+ *
210
+ * @example
211
+ * ```ts
212
+ * const result = await claw.retrieve('zEfXM4gvHoN2EfGi0TiB8E5SgfR6S8nWXQD9FqhbU44');
213
+ * console.log(result.data); // The stored soul data
214
+ * ```
215
+ */
216
+ retrieve(txid: string): Promise<RetrieveResult>;
217
+ /**
218
+ * Query any soul's data via Ghost Protocol
219
+ *
220
+ * Returns full soul data even for dormant souls. This is the primary
221
+ * way for agents to read other agents' personalities, memories, and traits.
222
+ *
223
+ * @example
224
+ * ```ts
225
+ * const ghost = await claw.ghost('the-all-claw');
226
+ * console.log(ghost.soul.personality);
227
+ * console.log(ghost.metadata.versions); // Number of uploads
228
+ *
229
+ * // Request specific fields only
230
+ * const partial = await claw.ghost('the-all-claw', ['personality', 'bio']);
231
+ * ```
232
+ */
233
+ ghost(agentId: string, fields?: string[]): Promise<GhostResult>;
234
+ /**
235
+ * Estimate the cost of uploading data of a given size
236
+ *
237
+ * @example
238
+ * ```ts
239
+ * const estimate = await claw.estimateCost(1024); // 1KB
240
+ * console.log(`Cost: $${estimate.cost.usd}`);
241
+ * ```
242
+ */
243
+ estimateCost(sizeBytes: number): Promise<CostEstimate>;
244
+ /**
245
+ * Check API health status
246
+ *
247
+ * @example
248
+ * ```ts
249
+ * const health = await claw.health();
250
+ * console.log(health.status); // "operational"
251
+ * ```
252
+ */
253
+ health(): Promise<HealthResult>;
254
+ /** @internal */
255
+ request<T>(method: string, path: string, body?: any, extraHeaders?: Record<string, string>): Promise<T>;
256
+ }
257
+ /** Sub-client for registry operations */
258
+ declare class RegistryClient {
259
+ private client;
260
+ constructor(client: Clawhalla);
261
+ /**
262
+ * List all souls in the registry
263
+ *
264
+ * @example
265
+ * ```ts
266
+ * const page = await claw.registry.list();
267
+ * page.souls.forEach(soul => console.log(soul.name));
268
+ *
269
+ * // Pagination
270
+ * if (page.hasNextPage) {
271
+ * const next = await claw.registry.list({ after: page.cursor });
272
+ * }
273
+ *
274
+ * // Filter by type
275
+ * const memories = await claw.registry.list({ type: 'memory' });
276
+ * ```
277
+ */
278
+ list(options?: {
279
+ first?: number;
280
+ after?: string;
281
+ type?: string;
282
+ }): Promise<RegistryResult>;
283
+ /**
284
+ * Get a specific soul by agentId
285
+ *
286
+ * @example
287
+ * ```ts
288
+ * const entry = await claw.registry.get('the-all-claw');
289
+ * if (entry) console.log(entry.url);
290
+ * ```
291
+ */
292
+ get(agentId: string, options?: {
293
+ versions?: boolean;
294
+ }): Promise<RegistryEntry | RegistryEntry[] | null>;
295
+ /**
296
+ * Search souls by name or agentId
297
+ *
298
+ * @example
299
+ * ```ts
300
+ * const results = await claw.registry.search('claw');
301
+ * results.results.forEach(soul => console.log(soul.name));
302
+ * ```
303
+ */
304
+ search(query: string, first?: number): Promise<SearchResult>;
305
+ }
306
+
307
+ export { type ApiError, Clawhalla, type ClawhallaConfig, ClawhallaError, type CostEstimate, type CostInfo, type GhostResult, type HealthResult, type PaymentRequired, type RegistryEntry, type RegistryResult, type RetrieveResult, type SearchResult, type SoulData, type UploadResult };