@cleocode/lafs-protocol 0.1.1 → 1.0.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 CHANGED
@@ -1,45 +1,151 @@
1
- # lafs-protocol
1
+ # LAFS Protocol
2
2
 
3
- LLM-Agent-First Specification (LAFS) as a standalone protocol repository.
3
+ **LLM-Agent-First Specification** a response envelope contract for AI agent systems.
4
4
 
5
- This repository is language-neutral at the protocol layer and TypeScript-first for reference tooling.
5
+ LAFS defines a standard envelope format for structured responses from LLM-powered agents and tools. It complements transport protocols like [MCP](https://modelcontextprotocol.io/) and [A2A](https://github.com/google/A2A) by standardizing what comes back — not how it gets there.
6
6
 
7
- ## What this repo provides
7
+ **Current version:** 0.5.0 | [Spec](lafs.md) | [Migration Guides](migrations/)
8
8
 
9
- - Canonical protocol spec: `lafs.md`
10
- - Versioned JSON schemas: `schemas/v1/`
11
- - Error registry and transport mappings: `schemas/v1/error-registry.json`
12
- - TypeScript validation/conformance toolkit: `src/`
13
- - Automated conformance tests: `tests/`
9
+ ## What LAFS provides
10
+
11
+ | Layer | Files | Description |
12
+ |-------|-------|-------------|
13
+ | **Spec** | `lafs.md` | Protocol specification with RFC 2119 language |
14
+ | **Schemas** | `schemas/v1/envelope.schema.json` | Envelope schema (Draft-07) with conditional pagination validation |
15
+ | | `schemas/v1/context-ledger.schema.json` | Context ledger for state tracking across request/response cycles |
16
+ | | `schemas/v1/error-registry.json` | 12 registered error codes with HTTP/gRPC/CLI transport mappings |
17
+ | **Tooling** | `src/` | TypeScript validation, conformance runner, CLI diagnostic tool |
18
+ | **Tests** | `tests/` | 31 tests covering envelope, pagination, strict mode, error handling |
19
+ | **Fixtures** | `fixtures/` | 14 JSON fixtures (valid + invalid) for conformance testing |
20
+ | **Docs** | `docs/` | Positioning, vision, conformance tiers, deprecation policy |
14
21
 
15
22
  ## Install
16
23
 
17
24
  ```bash
18
- npm install
25
+ npm install @cleocode/lafs-protocol
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ ```typescript
31
+ import {
32
+ validateEnvelope,
33
+ runEnvelopeConformance,
34
+ isRegisteredErrorCode,
35
+ } from "@cleocode/lafs-protocol";
36
+
37
+ // Validate an envelope against the schema
38
+ const result = validateEnvelope(envelope);
39
+ if (!result.valid) {
40
+ console.error(result.errors);
41
+ }
42
+
43
+ // Run full conformance suite (schema + invariants + error codes + strict mode + pagination)
44
+ const report = runEnvelopeConformance(envelope);
45
+ console.log(report.ok); // true if all checks pass
19
46
  ```
20
47
 
21
- ## Commands
48
+ ## CLI
22
49
 
23
50
  ```bash
24
- npm run typecheck
51
+ # Run conformance checks on a fixture
52
+ npm run conformance -- --envelope fixtures/valid-success-envelope.json
53
+
54
+ # Run tests
25
55
  npm test
26
- npm run conformance -- --envelope fixtures/valid-success-envelope.json --flags fixtures/flags-valid.json
56
+
57
+ # Type check
58
+ npm run typecheck
27
59
  ```
28
60
 
29
- ## Canonical policy
61
+ ## Envelope structure
30
62
 
31
- - JSON default output is REQUIRED.
32
- - Human-readable output is explicit opt-in (`--human`).
33
- - `--json` is optional but recommended explicit alias/override.
34
- - `--human --json` is invalid and MUST fail with `E_FORMAT_CONFLICT`.
63
+ ```json
64
+ {
65
+ "$schema": "https://lafs.dev/schemas/v1/envelope.schema.json",
66
+ "_meta": {
67
+ "specVersion": "0.5.0",
68
+ "schemaVersion": "1.0.0",
69
+ "timestamp": "2026-02-13T00:00:00Z",
70
+ "operation": "example.list",
71
+ "requestId": "req_01",
72
+ "transport": "http",
73
+ "strict": true,
74
+ "mvi": "standard",
75
+ "contextVersion": 1
76
+ },
77
+ "success": true,
78
+ "result": { "items": [{ "id": "1", "title": "Example" }] },
79
+ "page": {
80
+ "mode": "cursor",
81
+ "nextCursor": "eyJpZCI6IjEwIn0=",
82
+ "hasMore": true
83
+ }
84
+ }
85
+ ```
86
+
87
+ ## Key features
88
+
89
+ - **Conditional pagination** — cursor, offset, and none modes with mode-specific required fields
90
+ - **Strict/lenient mode** — `strict: true` rejects unknown properties; `strict: false` allows them
91
+ - **MVI disclosure levels** — `minimal`, `standard`, `full`, `custom` control response verbosity
92
+ - **Field selection** (`_fields`) and **expansion** (`_expand`) request parameters
93
+ - **Context ledger** — tracks state across request/response cycles with monotonic versioning
94
+ - **Error registry** — 12 codes with category, retryability, and transport-specific status mappings
95
+ - **Extension mechanism** — `_extensions` field for vendor metadata (`x-` prefix convention)
96
+ - **Adoption tiers** — Core, Standard, Complete with progressive conformance requirements
97
+
98
+ ## Conformance checks
99
+
100
+ | Check | Description | Tier |
101
+ |-------|-------------|------|
102
+ | `envelope_schema_valid` | Validates against JSON Schema | Core |
103
+ | `envelope_invariants` | success/result/error consistency | Core |
104
+ | `error_code_registered` | Error code exists in registry | Core |
105
+ | `meta_mvi_present` | Valid MVI disclosure level | Standard |
106
+ | `meta_strict_present` | Strict mode declared | Standard |
107
+ | `strict_mode_behavior` | Optional fields omitted (not null) in strict mode | Standard |
108
+ | `strict_mode_enforced` | Additional properties rejected/allowed per mode | Standard |
109
+ | `pagination_mode_consistent` | Page fields match declared mode | Standard |
35
110
 
36
- ## Layout
111
+ ## Project layout
37
112
 
38
- ```text
39
- lafs.md
113
+ ```
114
+ lafs.md # Protocol specification
40
115
  schemas/v1/
116
+ envelope.schema.json # Envelope schema (Draft-07)
117
+ context-ledger.schema.json # Context ledger schema
118
+ error-registry.json # Error code registry
41
119
  src/
42
- tests/
43
- fixtures/
120
+ types.ts # TypeScript types (discriminated unions)
121
+ validateEnvelope.ts # Ajv-based schema validator
122
+ conformance.ts # Conformance runner (8 checks)
123
+ errorRegistry.ts # Error code helpers
124
+ flagSemantics.ts # Format flag resolution
125
+ cli.ts # CLI diagnostic tool
126
+ tests/ # 31 tests (vitest)
127
+ fixtures/ # 14 JSON test fixtures
44
128
  docs/
129
+ POSITIONING.md # MCP/A2A complementary positioning
130
+ VISION.md # Project vision and primary persona
131
+ CONFORMANCE.md # Conformance checks and adoption tiers
132
+ migrations/
133
+ v0.3.0-to-v0.4.0.md # Envelope rationalization migration
134
+ v0.4.0-to-v0.5.0.md # Pagination & MVI schema migration
135
+ CONTRIBUTING.md # Contributor guidelines, RFC process
45
136
  ```
137
+
138
+ ## Version history
139
+
140
+ | Version | Phase | Description |
141
+ |---------|-------|-------------|
142
+ | v0.5.0 | 2B | Conditional pagination, MVI field selection/expansion, context ledger schema |
143
+ | v0.4.0 | 2A | Optional page/error, extensions, strict/lenient mode, warnings |
144
+ | v0.3.0 | 1 | Strategic positioning, vision alignment, adoption tiers |
145
+ | v0.2.0 | 0 | Protocol cleanup, fixtures, governance, security considerations |
146
+ | v0.1.1 | — | Initial npm publish |
147
+ | v0.1.0 | — | Bootstrap |
148
+
149
+ ## License
150
+
151
+ MIT
@@ -0,0 +1,8 @@
1
+ /**
2
+ * LAFS Discovery Example Server
3
+ *
4
+ * Run with: npx tsx examples/discovery-server.ts
5
+ * Or: npm run build && node dist/examples/discovery-server.js
6
+ */
7
+ declare const app: import("express-serve-static-core").Express;
8
+ export default app;
@@ -0,0 +1,216 @@
1
+ /**
2
+ * LAFS Discovery Example Server
3
+ *
4
+ * Run with: npx tsx examples/discovery-server.ts
5
+ * Or: npm run build && node dist/examples/discovery-server.js
6
+ */
7
+ import express from "express";
8
+ import { discoveryMiddleware } from "../src/discovery.js";
9
+ const app = express();
10
+ const PORT = process.env.PORT || 3000;
11
+ /**
12
+ * LAFS-compliant envelope endpoint handler
13
+ * Demonstrates proper LAFS envelope processing
14
+ */
15
+ app.post("/api/v1/envelope", express.json(), (req, res) => {
16
+ const envelope = req.body;
17
+ // Validate basic envelope structure
18
+ if (!envelope._meta) {
19
+ return res.status(400).json({
20
+ success: false,
21
+ error: {
22
+ code: "INVALID_ENVELOPE",
23
+ message: "Missing _meta field",
24
+ category: "VALIDATION",
25
+ retryable: false,
26
+ retryAfterMs: null,
27
+ details: { missing: ["_meta"] }
28
+ },
29
+ result: null
30
+ });
31
+ }
32
+ // Process the request (simplified example)
33
+ const operation = envelope._meta.operation;
34
+ // Echo back with success
35
+ res.json({
36
+ $schema: "https://lafs.dev/schemas/v1/envelope.schema.json",
37
+ _meta: {
38
+ specVersion: envelope._meta.specVersion || "1.0.0",
39
+ schemaVersion: envelope._meta.schemaVersion || "1.0.0",
40
+ timestamp: new Date().toISOString(),
41
+ operation: `${operation}:response`,
42
+ requestId: envelope._meta.requestId || crypto.randomUUID(),
43
+ transport: "http",
44
+ strict: envelope._meta.strict ?? true,
45
+ mvi: envelope._meta.mvi || "standard",
46
+ contextVersion: (envelope._meta.contextVersion || 0) + 1
47
+ },
48
+ success: true,
49
+ result: {
50
+ received: true,
51
+ operation: operation,
52
+ data: envelope.payload || null
53
+ },
54
+ error: null
55
+ });
56
+ });
57
+ /**
58
+ * Context ledger endpoint
59
+ * Demonstrates context management capability
60
+ */
61
+ app.get("/api/v1/context/:ledgerId", (req, res) => {
62
+ const ledgerId = req.params.ledgerId;
63
+ // Return mock context ledger
64
+ res.json({
65
+ $schema: "https://lafs.dev/schemas/v1/context-ledger.schema.json",
66
+ ledgerId,
67
+ version: 1,
68
+ createdAt: new Date().toISOString(),
69
+ updatedAt: new Date().toISOString(),
70
+ entries: [],
71
+ checksum: "sha256:mock",
72
+ maxEntries: 1000
73
+ });
74
+ });
75
+ app.post("/api/v1/context/:ledgerId/entries", express.json(), (req, res) => {
76
+ const ledgerId = req.params.ledgerId;
77
+ const entry = req.body;
78
+ res.json({
79
+ $schema: "https://lafs.dev/schemas/v1/envelope.schema.json",
80
+ _meta: {
81
+ specVersion: "1.0.0",
82
+ schemaVersion: "1.0.0",
83
+ timestamp: new Date().toISOString(),
84
+ operation: "context:append",
85
+ requestId: crypto.randomUUID(),
86
+ transport: "http",
87
+ strict: true,
88
+ mvi: "standard",
89
+ contextVersion: 2
90
+ },
91
+ success: true,
92
+ result: {
93
+ ledgerId,
94
+ entryId: crypto.randomUUID(),
95
+ committed: true,
96
+ timestamp: new Date().toISOString()
97
+ },
98
+ error: null
99
+ });
100
+ });
101
+ /**
102
+ * Discovery configuration
103
+ * Advertises all LAFS capabilities and endpoints
104
+ */
105
+ const discoveryConfig = {
106
+ service: {
107
+ name: "example-lafs-service",
108
+ version: "1.0.0",
109
+ description: "Example LAFS-compliant API service demonstrating discovery protocol"
110
+ },
111
+ capabilities: [
112
+ {
113
+ name: "envelope-processor",
114
+ version: "1.0.0",
115
+ description: "Process and validate LAFS envelopes",
116
+ operations: ["process", "validate", "transform"]
117
+ },
118
+ {
119
+ name: "context-ledger",
120
+ version: "1.0.0",
121
+ description: "Manage context ledgers for stateful operations",
122
+ operations: ["read", "append", "query"]
123
+ },
124
+ {
125
+ name: "pagination-provider",
126
+ version: "1.0.0",
127
+ description: "Provide cursor and offset pagination for list endpoints",
128
+ operations: ["cursor", "offset", "none"],
129
+ optional: true
130
+ }
131
+ ],
132
+ endpoints: {
133
+ envelope: "/api/v1/envelope",
134
+ context: "/api/v1/context",
135
+ discovery: "https://lafs.dev/schemas/v1/discovery.schema.json"
136
+ },
137
+ cacheMaxAge: 3600,
138
+ lafsVersion: "1.0.0"
139
+ };
140
+ // Mount discovery middleware BEFORE other routes
141
+ // This ensures /.well-known/lafs.json is served at the root
142
+ app.use(discoveryMiddleware(discoveryConfig));
143
+ /**
144
+ * Health check endpoint
145
+ */
146
+ app.get("/health", (req, res) => {
147
+ res.json({
148
+ status: "healthy",
149
+ service: discoveryConfig.service.name,
150
+ version: discoveryConfig.service.version,
151
+ timestamp: new Date().toISOString()
152
+ });
153
+ });
154
+ /**
155
+ * Error handling middleware
156
+ */
157
+ app.use((err, req, res, next) => {
158
+ console.error("Error:", err);
159
+ res.status(500).json({
160
+ success: false,
161
+ error: {
162
+ code: "INTERNAL_ERROR",
163
+ message: err.message || "Internal server error",
164
+ category: "INTERNAL",
165
+ retryable: false,
166
+ retryAfterMs: null,
167
+ details: process.env.NODE_ENV === "development" ? { stack: err.stack } : {}
168
+ },
169
+ result: null
170
+ });
171
+ });
172
+ /**
173
+ * Start server
174
+ */
175
+ const server = app.listen(PORT, () => {
176
+ console.log(`
177
+ ╔════════════════════════════════════════════════════════╗
178
+ ║ LAFS Discovery Server Running ║
179
+ ╠════════════════════════════════════════════════════════╣
180
+ ║ Service: ${discoveryConfig.service.name.padEnd(43)}║
181
+ ║ Version: ${discoveryConfig.service.version.padEnd(43)}║
182
+ ║ Port: ${String(PORT).padEnd(43)}║
183
+ ╠════════════════════════════════════════════════════════╣
184
+ ║ Endpoints: ║
185
+ ║ GET /.well-known/lafs.json (Discovery document) ║
186
+ ║ POST /api/v1/envelope (Envelope processor) ║
187
+ ║ GET /api/v1/context/:id (Context ledger) ║
188
+ ║ GET /health (Health check) ║
189
+ ╚════════════════════════════════════════════════════════╝
190
+
191
+ Test with:
192
+ curl http://localhost:${PORT}/.well-known/lafs.json | jq
193
+ curl http://localhost:${PORT}/health | jq
194
+ curl -X POST http://localhost:${PORT}/api/v1/envelope \
195
+ -H "Content-Type: application/json" \
196
+ -d '{"_meta":{"operation":"test","requestId":"123"},"payload":{"hello":"world"}}'
197
+ `);
198
+ });
199
+ /**
200
+ * Graceful shutdown
201
+ */
202
+ process.on("SIGTERM", () => {
203
+ console.log("\nShutting down gracefully...");
204
+ server.close(() => {
205
+ console.log("Server closed");
206
+ process.exit(0);
207
+ });
208
+ });
209
+ process.on("SIGINT", () => {
210
+ console.log("\nShutting down gracefully...");
211
+ server.close(() => {
212
+ console.log("Server closed");
213
+ process.exit(0);
214
+ });
215
+ });
216
+ export default app;
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP-LAFS Client Example
4
+ *
5
+ * A client that connects to the MCP-LAFS server and validates responses
6
+ * are LAFS-compliant. Demonstrates budget negotiation and envelope validation.
7
+ *
8
+ * Usage: npx ts-node examples/mcp-lafs-client.ts
9
+ */
10
+ export {};