@amtp/protocol 1.0.1

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.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +386 -0
  3. package/USAGE_GUIDE.md +722 -0
  4. package/bin/amtp.ts +387 -0
  5. package/dist/client/amtp-client.d.ts +164 -0
  6. package/dist/client/amtp-client.js +460 -0
  7. package/dist/client/amtp-client.js.map +1 -0
  8. package/dist/client/examples/basic-client.d.ts +6 -0
  9. package/dist/client/examples/basic-client.js +35 -0
  10. package/dist/client/examples/basic-client.js.map +1 -0
  11. package/dist/crawler/amtp-crawler.d.ts +125 -0
  12. package/dist/crawler/amtp-crawler.js +359 -0
  13. package/dist/crawler/amtp-crawler.js.map +1 -0
  14. package/dist/crawler/examples/basic-crawler.d.ts +6 -0
  15. package/dist/crawler/examples/basic-crawler.js +28 -0
  16. package/dist/crawler/examples/basic-crawler.js.map +1 -0
  17. package/dist/index.d.ts +15 -0
  18. package/dist/index.js +70 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/server/adapters/fastify-adapter.d.ts +86 -0
  21. package/dist/server/adapters/fastify-adapter.js +169 -0
  22. package/dist/server/adapters/fastify-adapter.js.map +1 -0
  23. package/dist/server/amtp-ql-executor.d.ts +24 -0
  24. package/dist/server/amtp-ql-executor.js +198 -0
  25. package/dist/server/amtp-ql-executor.js.map +1 -0
  26. package/dist/server/amtp-ql-parser.d.ts +30 -0
  27. package/dist/server/amtp-ql-parser.js +212 -0
  28. package/dist/server/amtp-ql-parser.js.map +1 -0
  29. package/dist/server/amtp-server.d.ts +183 -0
  30. package/dist/server/amtp-server.js +650 -0
  31. package/dist/server/amtp-server.js.map +1 -0
  32. package/dist/server/examples/basic-server.d.ts +6 -0
  33. package/dist/server/examples/basic-server.js +215 -0
  34. package/dist/server/examples/basic-server.js.map +1 -0
  35. package/dist/server/examples/saas-dashboard-server.d.ts +44 -0
  36. package/dist/server/examples/saas-dashboard-server.js +387 -0
  37. package/dist/server/examples/saas-dashboard-server.js.map +1 -0
  38. package/dist/server/markdown-parser.d.ts +31 -0
  39. package/dist/server/markdown-parser.js +463 -0
  40. package/dist/server/markdown-parser.js.map +1 -0
  41. package/dist/server/notifications.d.ts +40 -0
  42. package/dist/server/notifications.js +134 -0
  43. package/dist/server/notifications.js.map +1 -0
  44. package/dist/server/permissions.d.ts +40 -0
  45. package/dist/server/permissions.js +156 -0
  46. package/dist/server/permissions.js.map +1 -0
  47. package/dist/server/security.d.ts +127 -0
  48. package/dist/server/security.js +368 -0
  49. package/dist/server/security.js.map +1 -0
  50. package/dist/types/amtp.types.d.ts +720 -0
  51. package/dist/types/amtp.types.js +224 -0
  52. package/dist/types/amtp.types.js.map +1 -0
  53. package/package.json +89 -0
package/USAGE_GUIDE.md ADDED
@@ -0,0 +1,722 @@
1
+ # AMTP Usage Guide
2
+
3
+ Practical walkthrough for running, extending, and integrating with the AMTP protocol toolkit.
4
+
5
+ ---
6
+
7
+ ## Prerequisites
8
+
9
+ - **Node.js** >= 18.0.0
10
+ - **npm** >= 9.0.0
11
+
12
+ ```bash
13
+ git clone <repo-url> && cd AMTP
14
+ npm install
15
+ ```
16
+
17
+ ---
18
+
19
+ ## 1. CLI Reference (`amtp`)
20
+
21
+ The CLI is run via `ts-node`:
22
+
23
+ ```bash
24
+ npm run amtp -- <command> [options]
25
+ ```
26
+
27
+ ### `amtp init <dir>`
28
+ Scaffold a new AMTP project with starter files.
29
+
30
+ ```bash
31
+ npm run amtp -- init my-amtp-app
32
+ cd my-amtp-app && npm install
33
+ ```
34
+
35
+ ### `amtp serve`
36
+ Start a local AMTP development server.
37
+
38
+ ```bash
39
+ npm run amtp -- serve -p 3000 -h 0.0.0.0
40
+ ```
41
+
42
+ ### `amtp crawl <url>`
43
+ Crawl an AMTP-enabled site and dump the index as JSON.
44
+
45
+ ```bash
46
+ npm run amtp -- crawl https://example.com --max-pages 20 --max-depth 3
47
+ ```
48
+
49
+ ### `amtp validate <files...>`
50
+ Check markdown files for AMTP structural validity.
51
+
52
+ ```bash
53
+ npm run amtp -- validate spec/examples/*.md
54
+ ```
55
+
56
+ ### `amtp doctor`
57
+ Run all health checks — type-check, build, lint, tests, audit, Node version, `.gitignore`, env safety.
58
+
59
+ ```bash
60
+ npm run amtp -- doctor
61
+ ```
62
+
63
+ ### Built-in shorthand scripts
64
+
65
+ ```bash
66
+ npm run server # Start basic-server on :3000
67
+ npm run server:saas # Start SaaS dashboard on :3000
68
+ npm run client # Run basic-client example
69
+ npm run crawler # Run basic-crawler example
70
+ npm run bench # Run performance benchmarks
71
+ ```
72
+
73
+ ---
74
+
75
+ ## 2. Building an AMTP Server
76
+
77
+ ### Minimal Server
78
+
79
+ ```typescript
80
+ // server.ts
81
+ import { AMTPServer } from "./src/server/amtp-server";
82
+ import { AMTPResponseBuilder } from "./src/server/amtp-server";
83
+
84
+ const server = new AMTPServer({ port: 3000, enableCORS: true });
85
+
86
+ server.register("GET", "/", (_req, res) => {
87
+ const doc = new AMTPResponseBuilder().build("# Hello\n\nAMTP world.\n\n## Actions\n\n[GREET] — Say hello");
88
+ const { headers, body } = doc;
89
+ for (const [k, v] of Object.entries(headers)) if (v) res.setHeader(k, v);
90
+ res.send(body);
91
+ });
92
+
93
+ server.start();
94
+ ```
95
+
96
+ ### Server with Product Page, Actions, Batch & AMTP-QL
97
+
98
+ A complete example at `src/server/examples/basic-server.ts` includes:
99
+
100
+ | Route | Purpose |
101
+ |---|---|
102
+ | `GET /products/:id` | Product page as AMTP document |
103
+ | `POST /products/:id/buy` | Action handler with notification emission |
104
+ | `POST /api/amtp/batch` | Batch action execution (v1.1) |
105
+ | `POST /api/amtp/query` | AMTP-QL query endpoint (v2.0) |
106
+ | `POST /api/webhooks` | Register a push webhook |
107
+ | `GET /api/amtp/stream` | SSE streaming endpoint |
108
+ | `GET /health` | Health check |
109
+
110
+ ```bash
111
+ npm run server
112
+ ```
113
+
114
+ ### SaaS Multi-Tenant Dashboard Server
115
+
116
+ Located at `src/server/examples/saas-dashboard-server.ts`. Uses SQLite + JWT auth.
117
+
118
+ ```bash
119
+ npm run server:saas
120
+
121
+ # Demo credentials:
122
+ # email: demo@example.com
123
+ # password: demo-password
124
+ ```
125
+
126
+ Endpoints:
127
+
128
+ | Route | Auth | Purpose |
129
+ |---|---|---|
130
+ | `POST /api/v1/auth/register` | No | Register tenant + user |
131
+ | `POST /api/v1/auth/login` | No | Login, receive JWT |
132
+ | `GET /api/v1/me` | JWT | Current user info |
133
+ | `GET /api/v1/workspaces` | JWT | List workspaces |
134
+ | `POST /api/v1/workspaces` | JWT | Create workspace |
135
+ | `GET /amtp/*` | JWT | AMTP content-negotiated workspace list |
136
+
137
+ ```bash
138
+ # Get an AMTP document
139
+ curl -H "Accept: text/amtp+markdown" \
140
+ -H "Authorization: Bearer <token>" \
141
+ http://localhost:3000/
142
+ ```
143
+
144
+ ### Using the Middleware Stack Directly
145
+
146
+ For custom Express apps, compose individual middleware:
147
+
148
+ ```typescript
149
+ import express from "express";
150
+ import { AMTPMiddlewareFactory } from "./src/server/amtp-server";
151
+
152
+ const app = express();
153
+ const amtp = new AMTPMiddlewareFactory();
154
+
155
+ app.use(amtp.securityHeaders());
156
+ app.use(amtp.cors(["https://myapp.com"]));
157
+ app.use(amtp.contentNegotiation());
158
+ app.use(amtp.rateLimit(60_000, 100));
159
+ app.use(amtp.csrfGuard());
160
+ app.use(amtp.middleware()); // parses AMTP headers, resolves session
161
+ app.use(amtp.responseSender()); // sends context.response.body
162
+ app.use(amtp.errorHandler()); // catch-all error handler
163
+ ```
164
+
165
+ ### Fastify Adapter
166
+
167
+ ```typescript
168
+ import fastify from "fastify";
169
+ import { fastifyAMTP, amtpReply } from "./src/server/adapters/fastify-adapter";
170
+ import { AMTPResponseBuilder } from "./src/server/amtp-server";
171
+
172
+ const app = fastify({ logger: true });
173
+ amtpReply(app);
174
+
175
+ await app.register(fastifyAMTP.plugin, {
176
+ trustedOrigins: ["https://example.com"],
177
+ });
178
+
179
+ app.get("/hello", async (_req, reply) => {
180
+ const doc = new AMTPResponseBuilder().build("# Hello\n\nFastify + AMTP");
181
+ return reply.amtp(doc);
182
+ });
183
+
184
+ await app.listen({ port: 3000 });
185
+ ```
186
+
187
+ ---
188
+
189
+ ## 3. Agent Client SDK
190
+
191
+ ### Basic Usage
192
+
193
+ ```typescript
194
+ import { AMTPClient } from "./src/client/amtp-client";
195
+
196
+ const client = new AMTPClient({
197
+ baseUrl: "http://localhost:3000",
198
+ capabilities: ["actions", "forms", "streaming"],
199
+ });
200
+
201
+ // Fetch a page
202
+ const page = await client.getPage("/products/demo");
203
+ console.log(page.title); // "Product demo"
204
+ console.log(page.actions); // [{ id: "buy", ... }, { id: "add_to_cart", ... }]
205
+ console.log(page.forms); // any forms on the page
206
+ console.log(page.links); // navigation links
207
+
208
+ // Execute an action
209
+ const result = await client.executeAction("buy", {
210
+ productId: "demo",
211
+ quantity: 2,
212
+ });
213
+
214
+ // Submit a form (e.g. checkout)
215
+ const form = page.forms[0];
216
+ await client.submitForm(form, {
217
+ email: "agent@example.com",
218
+ address: "123 AI Street",
219
+ });
220
+
221
+ // Stream real-time updates
222
+ const es = client.streamUpdates("/api/amtp/stream", (update) => {
223
+ console.log("🔔", update.type, update.data);
224
+ });
225
+
226
+ // Login / Logout
227
+ const { sessionId } = await client.login("user", "pass");
228
+ await client.logout();
229
+ ```
230
+
231
+ ### Autonomous Agent Example
232
+
233
+ The `AutonomousAgent` class demonstrates an agent that autonomously shops:
234
+
235
+ ```typescript
236
+ import { AutonomousAgent } from "./src/client/amtp-client";
237
+
238
+ const agent = new AutonomousAgent({
239
+ baseUrl: "http://localhost:3000",
240
+ });
241
+
242
+ const result = await agent.autonomousShop("laptop", 2500);
243
+ console.log(result.success ? "✅ Purchase completed" : "❌ Failed");
244
+ ```
245
+
246
+ The workflow:
247
+ 1. Search products by keyword
248
+ 2. Find a product within budget
249
+ 3. View the product page
250
+ 4. Execute `add_to_cart` action
251
+ 5. Navigate to cart
252
+ 6. Get checkout forms
253
+
254
+ ### AMTP-QL Queries (v2.0)
255
+
256
+ Project only the fields you need:
257
+
258
+ ```typescript
259
+ const result = await client.query(`
260
+ query {
261
+ document {
262
+ title
263
+ actions { id description }
264
+ nodes(type: ["HEADING"], limit: 5) { type content }
265
+ pagination { pageInfo { hasNextPage endCursor } }
266
+ }
267
+ }
268
+ `);
269
+ console.log(result.title);
270
+ console.log(result.actions);
271
+ ```
272
+
273
+ ---
274
+
275
+ ## 4. Crawler & Search Indexer
276
+
277
+ ### Crawl a Site
278
+
279
+ ```typescript
280
+ import { AMTPCrawler } from "./src/crawler/amtp-crawler";
281
+
282
+ const crawler = new AMTPCrawler({
283
+ baseUrl: "http://localhost:3000",
284
+ maxPages: 100,
285
+ maxDepth: 3,
286
+ respectRobotsTxt: true,
287
+ delays: { betweenRequests: 200, betweenDomains: 1000 },
288
+ });
289
+
290
+ const pages = await crawler.crawl();
291
+ console.log(`Crawled ${pages.length} pages`);
292
+
293
+ // Search the in-memory index
294
+ const results = crawler.search("macbook");
295
+ console.log(results);
296
+
297
+ // Export index as JSON
298
+ fs.writeFileSync("crawl-index.json", crawler.exportIndex());
299
+ ```
300
+
301
+ ### Search Indexer
302
+
303
+ ```typescript
304
+ import { SearchIndexer } from "./src/crawler/amtp-crawler";
305
+
306
+ const indexer = new SearchIndexer();
307
+ indexer.addPages(pages);
308
+
309
+ const results = indexer.search("laptop", 10); // top 10 by relevance
310
+ console.log(results.map(r => r.title));
311
+ ```
312
+
313
+ ---
314
+
315
+ ## 5. AMTP Markdown Format
316
+
317
+ AMTP documents extend standard markdown with structured blocks:
318
+
319
+ ### Metadata Block
320
+ ```markdown
321
+ ```amtp-meta
322
+ {
323
+ "pageId": "prod-123",
324
+ "pageType": "product",
325
+ "version": "1.0",
326
+ "sessionRequired": false
327
+ }
328
+ ```
329
+ ```
330
+
331
+ ### Actions Section
332
+ ```markdown
333
+ ## Actions
334
+
335
+ [BUY] — Purchase immediately
336
+ [ADD_TO_CART] — Add to shopping cart
337
+ [REVIEW] — Leave a review
338
+ ```
339
+
340
+ ### Form Definition
341
+ ```markdown
342
+ ## Login Form
343
+ ACTION: login
344
+ METHOD: POST
345
+ ENDPOINT: /api/login
346
+ FIELD: email
347
+ TYPE: email
348
+ REQUIRED: true
349
+ LABEL: Email Address
350
+ FIELD: password
351
+ TYPE: password
352
+ REQUIRED: true
353
+ LABEL: Password
354
+ ```
355
+
356
+ ### Structured Data
357
+ ```markdown
358
+ ```amtp-data
359
+ {
360
+ "@type": "Product",
361
+ "name": "MacBook Pro 14",
362
+ "price": 1999,
363
+ "currency": "USD",
364
+ "inStock": true
365
+ }
366
+ ```
367
+ ```
368
+
369
+ ### Pagination Block
370
+ ```markdown
371
+ ```amtp-pagination
372
+ {
373
+ "pageInfo": { "hasNextPage": true, "endCursor": "c2" },
374
+ "nextCursor": "c2",
375
+ "totalItems": 42
376
+ }
377
+ ```
378
+ ```
379
+
380
+ ### Structured Action Definition (v2.0)
381
+ Replaces or supplements simple `[ACTION]` tokens with full JSON action metadata including typed parameters and permission requirements:
382
+
383
+ ```markdown
384
+ ```amtp-action
385
+ [
386
+ {
387
+ "id": "delete_doc",
388
+ "label": "Delete Document",
389
+ "method": "POST",
390
+ "endpoint": "/api/docs/delete",
391
+ "permissions": ["doc:delete"],
392
+ "parameters": [
393
+ { "name": "docId", "type": "string", "required": true }
394
+ ]
395
+ }
396
+ ]
397
+ ```
398
+ ```
399
+
400
+ ### Permissions Block (v2.0)
401
+ Declares permissions that control access to actions on resources:
402
+
403
+ ```markdown
404
+ ```amtp-permissions
405
+ [
406
+ {
407
+ "id": "doc:read",
408
+ "name": "Read Documents",
409
+ "resource": "doc:*",
410
+ "actions": ["view_doc", "search_docs"]
411
+ },
412
+ {
413
+ "id": "doc:delete",
414
+ "name": "Delete Documents",
415
+ "resource": "doc:*",
416
+ "actions": ["delete_doc"]
417
+ }
418
+ ]
419
+ ```
420
+ ```
421
+
422
+ ### Policy Block (v2.0)
423
+ Binds permissions to roles and optional conditions. Policies are evaluated at action-execution time:
424
+
425
+ ```markdown
426
+ ```amtp-policy
427
+ [
428
+ {
429
+ "id": "admin-policy",
430
+ "name": "Admin Access",
431
+ "permissions": ["doc:read", "doc:write", "doc:delete"],
432
+ "roles": ["admin"],
433
+ "priority": 100
434
+ },
435
+ {
436
+ "id": "viewer-policy",
437
+ "name": "Viewer Access",
438
+ "permissions": ["doc:read"],
439
+ "roles": ["viewer"]
440
+ }
441
+ ]
442
+ ```
443
+ ```
444
+
445
+ Supported condition operators: `eq`, `neq`, `in`, `gt`, `lt`, `contains`, `exists`.
446
+
447
+ ### Skill Block (v2.0)
448
+ Bundles actions, permissions, and dependencies into a named capability group:
449
+
450
+ ```markdown
451
+ ```amtp-skill
452
+ [
453
+ {
454
+ "id": "content-manager",
455
+ "name": "Content Management",
456
+ "actions": ["view_doc", "edit_doc", "delete_doc"],
457
+ "permissions": ["doc:read", "doc:write", "doc:delete"],
458
+ "requires": ["login"]
459
+ }
460
+ ]
461
+ ```
462
+ ```
463
+
464
+ ---
465
+
466
+ ## 6. Permission Guard — Policy-Based Access Control
467
+
468
+ The `PermissionGuard` is a server-side middleware that enforces the permissions and policies declared in AMTP documents at action-execution time.
469
+
470
+ ### How It Works
471
+
472
+ 1. A document declares `permissions` and `policies` as first-class blocks
473
+ 2. A session holds a flat list of granted permission IDs (e.g. `["doc:read", "doc:delete"]`)
474
+ 3. The session also has a `role` in its metadata (e.g. `"admin"`, `"viewer"`)
475
+ 4. When an action is requested, `PermissionGuard.check()` finds matching policies by role, evaluates conditions, and verifies the session has all required permissions
476
+
477
+ ### Usage
478
+
479
+ ```typescript
480
+ import { PermissionGuard } from "./src/server/permissions";
481
+ import { AMTPError } from "./src/types/amtp.types";
482
+
483
+ const guard = new PermissionGuard();
484
+
485
+ // Inside an action handler:
486
+ app.post("/api/amtp/action", (req, res) => {
487
+ const action = findAction(req.body.action); // look up the action definition
488
+ const doc = getCurrentDocument(); // the AMTP document context
489
+ const session = req.session; // authenticated session with permissions
490
+
491
+ try {
492
+ guard.assert(action, doc, session); // throws AMTPError if denied
493
+ executeAction(action, req.body.parameters);
494
+ res.json({ status: "success" });
495
+ } catch (err) {
496
+ if (err instanceof AMTPError) {
497
+ res.status(err.statusCode).json({
498
+ error: { code: err.code, message: err.message }
499
+ });
500
+ }
501
+ }
502
+ });
503
+ ```
504
+
505
+ ### Configuration
506
+
507
+ ```typescript
508
+ const guard = new PermissionGuard({
509
+ denyByDefault: true, // deny actions that have no matching policy (default: false)
510
+ deniedMessage: "Insufficient permissions", // custom error message
511
+ });
512
+
513
+ // Non-throwing check:
514
+ const result = guard.check(action, doc, session);
515
+ if (result.allowed) {
516
+ console.log(`Matched policy: ${result.matchedPolicy}`);
517
+ } else {
518
+ console.log(`Denied: ${result.reason}`);
519
+ }
520
+ ```
521
+
522
+ ### Full Example: Document Management API
523
+
524
+ ```typescript
525
+ import { PermissionGuard } from "./src/server/permissions";
526
+ import { AMTPServer, AMTPResponseBuilder } from "./src/server/amtp-server";
527
+ import type { AMTPDocument, Session } from "./src/types/amtp.types";
528
+
529
+ const guard = new PermissionGuard();
530
+ const server = new AMTPServer({ port: 3000 });
531
+
532
+ const securedDoc: AMTPDocument = {
533
+ type: "document",
534
+ version: "2.0",
535
+ title: "Document Manager",
536
+ path: "/docs",
537
+ nodes: [],
538
+ actions: [
539
+ { id: "delete_doc", label: "Delete", method: "POST" as any, endpoint: "/api/docs/delete", permissions: ["doc:delete"] },
540
+ { id: "view_doc", label: "View", method: "GET" as any, endpoint: "/api/docs/view", permissions: ["doc:read"] },
541
+ ],
542
+ forms: [],
543
+ links: [],
544
+ metadata: {},
545
+ permissions: [
546
+ { id: "doc:read", name: "Read Documents", resource: "doc:*", actions: ["view_doc"] },
547
+ { id: "doc:delete", name: "Delete Documents", resource: "doc:*", actions: ["delete_doc"] },
548
+ ],
549
+ policies: [
550
+ { id: "admin-policy", name: "Admin", permissions: ["doc:read", "doc:delete"], roles: ["admin"] },
551
+ { id: "viewer-policy", name: "Viewer", permissions: ["doc:read"], roles: ["viewer"] },
552
+ ],
553
+ };
554
+
555
+ server.register("POST", "/api/docs/delete", (req: any, res: any) => {
556
+ const session: Session = req.amtpContext?.session;
557
+
558
+ try {
559
+ guard.assert(securedDoc.actions[0], securedDoc, session);
560
+ res.json({ status: "success", deleted: true });
561
+ } catch (err: any) {
562
+ res.status(err.statusCode || 403).json({ error: err.message });
563
+ }
564
+ });
565
+
566
+ server.start();
567
+ ```
568
+
569
+ ---
570
+
571
+ ## 7. Use Cases
572
+
573
+ ### Use Case 1: E-Commerce Shopping Agent
574
+
575
+ ```typescript
576
+ // 1. Server exposes product catalog as AMTP documents
577
+ // GET /products/mbp-14 → Markdown with price, specs, actions
578
+ // GET /cart → Current cart state
579
+ // POST /api/amtp/action → Execute checkout
580
+
581
+ // 2. Agent workflow
582
+ const agent = new AutonomousAgent({ baseUrl: "https://store.example.com" });
583
+ const result = await agent.autonomousShop("macbook pro", 3000);
584
+
585
+ if (result.success) {
586
+ console.log(`Purchased: ${result.product.label}`);
587
+ }
588
+
589
+ // 3. Subscribe to order updates
590
+ client.streamUpdates("/api/amtp/stream?events=order.updated,order.shipped", (u) => {
591
+ if (u.type === "order.shipped") {
592
+ console.log(`📦 Tracking: ${u.data.trackingNumber}`);
593
+ }
594
+ });
595
+ ```
596
+
597
+ ### Use Case 2: SaaS Dashboard Agent
598
+
599
+ ```typescript
600
+ // 1. Server: src/server/examples/saas-dashboard-server.ts
601
+ // 2. Agent logs in and navigates workspaces
602
+
603
+ import { AMTPClient } from "./src/client/amtp-client";
604
+
605
+ const client = new AMTPClient({
606
+ baseUrl: "http://localhost:3000",
607
+ capabilities: ["actions", "forms"],
608
+ });
609
+
610
+ // Login
611
+ const { token } = await client.login("demo@example.com", "demo-password");
612
+
613
+ // Fetch AMTP workspace list
614
+ const workspaces = await client.getPage("/amtp/workspaces");
615
+ console.log(workspaces.title); // "Workspaces"
616
+ console.log(workspaces.links); // links to each workspace
617
+
618
+ // Navigate into first workspace
619
+ if (workspaces.links.length > 0) {
620
+ const ws = await client.clickLink(workspaces.links[0].url);
621
+ console.log(ws.title);
622
+ }
623
+ ```
624
+
625
+ ### Use Case 3: Content Crawler + Search Engine
626
+
627
+ ```typescript
628
+ // Crawl an AMTP-powered documentation site
629
+ const crawler = new AMTPCrawler({
630
+ baseUrl: "https://docs.example.com",
631
+ maxPages: 5000,
632
+ maxDepth: 10,
633
+ respectRobotsTxt: true,
634
+ indexCallback: async (doc) => {
635
+ // Index each page to an external search engine
636
+ await fetch("https://search.example.com/index", {
637
+ method: "POST",
638
+ body: JSON.stringify({
639
+ url: doc.path,
640
+ title: doc.title,
641
+ content: doc.nodes.map(n => n.content).join(" "),
642
+ actions: doc.actions.map(a => a.id),
643
+ }),
644
+ });
645
+ },
646
+ });
647
+
648
+ await crawler.crawl();
649
+ console.log(crawler.search("authentication"));
650
+ ```
651
+
652
+ ---
653
+
654
+ ## 8. Performance Benchmarks
655
+
656
+ ```bash
657
+ npm run bench
658
+ ```
659
+
660
+ Measures:
661
+ - Token efficiency (AMTP vs HTML — typically ~90% fewer tokens)
662
+ - Parser throughput (ops/sec)
663
+ - Large document scaling (10 to 100k sections)
664
+ - Memory growth after 20,000 parse operations
665
+
666
+ ---
667
+
668
+ ## 9. Validation & Testing
669
+
670
+ ```bash
671
+ # Full validation
672
+ npm run validate # type-check + build + test
673
+
674
+ # Type check only
675
+ npm run type-check
676
+
677
+ # Run tests with coverage
678
+ npm run test:coverage
679
+
680
+ # Lint
681
+ npm run lint
682
+
683
+ # Security audit
684
+ npm run security-audit
685
+
686
+ # Validate markdown files against AMTP grammar
687
+ npm run amtp -- validate spec/examples/*.md
688
+ ```
689
+
690
+ ---
691
+
692
+ ## 10. Docker
693
+
694
+ ```bash
695
+ # Production build
696
+ docker compose up amtp-prod
697
+
698
+ # Development with hot-reload
699
+ docker compose up amtp-dev
700
+ ```
701
+
702
+ ---
703
+
704
+ ## 11. Project Scripts Reference
705
+
706
+ | npm script | Command | Description |
707
+ |---|---|---|
708
+ | `npm run build` | `tsc` | Compile TypeScript to `dist/` |
709
+ | `npm run dev` | `tsc --watch` | Watch mode compilation |
710
+ | `npm run test` | `jest` | Run all tests |
711
+ | `npm run test:coverage` | `jest --coverage` | Tests with coverage report |
712
+ | `npm run lint` | `eslint src/**/*.ts` | Lint all source |
713
+ | `npm run type-check` | `tsc --noEmit` | TypeScript type checking |
714
+ | `npm run server` | `ts-node src/server/examples/basic-server.ts` | Start basic demo server |
715
+ | `npm run server:saas` | `ts-node src/server/examples/saas-dashboard-server.ts` | Start SaaS dashboard |
716
+ | `npm run client` | `ts-node src/client/examples/basic-client.ts` | Run client example |
717
+ | `npm run crawler` | `ts-node src/crawler/examples/basic-crawler.ts` | Run crawler example |
718
+ | `npm run bench` | `ts-node bench/bench.ts` | Run performance benchmarks |
719
+ | `npm run amtp -- <cmd>` | `ts-node bin/amtp.ts <cmd>` | CLI tool |
720
+ | `npm run docs` | `typedoc --out docs src/` | Generate API docs |
721
+ | `npm run validate` | (type-check + build + test) | Full validation |
722
+ | `npm run security-audit` | `npm audit` | Dependency audit |