@xano/developer-mcp 1.0.58 → 1.0.59

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 (38) hide show
  1. package/README.md +15 -0
  2. package/dist/tools/index.d.ts +9 -0
  3. package/dist/tools/xanoscript_docs.d.ts +9 -0
  4. package/dist/tools/xanoscript_docs.js +27 -0
  5. package/dist/xanoscript.d.ts +5 -1
  6. package/dist/xanoscript.js +70 -6
  7. package/dist/xanoscript.test.js +5 -3
  8. package/dist/xanoscript_docs/README.md +9 -43
  9. package/dist/xanoscript_docs/addons.md +0 -2
  10. package/dist/xanoscript_docs/agents.md +2 -35
  11. package/dist/xanoscript_docs/apis.md +3 -6
  12. package/dist/xanoscript_docs/branch.md +0 -2
  13. package/dist/xanoscript_docs/database.md +3 -7
  14. package/dist/xanoscript_docs/debugging.md +1 -264
  15. package/dist/xanoscript_docs/docs_index.json +22 -0
  16. package/dist/xanoscript_docs/essentials.md +1 -9
  17. package/dist/xanoscript_docs/frontend.md +1 -138
  18. package/dist/xanoscript_docs/functions.md +3 -7
  19. package/dist/xanoscript_docs/mcp-servers.md +1 -2
  20. package/dist/xanoscript_docs/middleware.md +1 -3
  21. package/dist/xanoscript_docs/performance.md +8 -198
  22. package/dist/xanoscript_docs/realtime.md +11 -161
  23. package/dist/xanoscript_docs/run.md +2 -184
  24. package/dist/xanoscript_docs/schema.md +1 -3
  25. package/dist/xanoscript_docs/security.md +82 -313
  26. package/dist/xanoscript_docs/streaming.md +2 -37
  27. package/dist/xanoscript_docs/survival.md +161 -0
  28. package/dist/xanoscript_docs/syntax.md +0 -6
  29. package/dist/xanoscript_docs/tables.md +3 -5
  30. package/dist/xanoscript_docs/tasks.md +1 -3
  31. package/dist/xanoscript_docs/tools.md +1 -3
  32. package/dist/xanoscript_docs/triggers.md +3 -69
  33. package/dist/xanoscript_docs/types.md +3 -4
  34. package/dist/xanoscript_docs/unit-testing.md +1 -55
  35. package/dist/xanoscript_docs/workflow-tests.md +8 -35
  36. package/dist/xanoscript_docs/working.md +667 -0
  37. package/dist/xanoscript_docs/workspace.md +0 -2
  38. package/package.json +1 -1
package/README.md CHANGED
@@ -339,12 +339,16 @@ Retrieves XanoScript programming language documentation with context-aware suppo
339
339
  | `topic` | string | No | Specific documentation topic to retrieve |
340
340
  | `file_path` | string | No | File path being edited for context-aware docs (e.g., `api/users/create_post.xs`) |
341
341
  | `mode` | string | No | `full` (default), `quick_reference` for compact syntax reference, or `index` for topic listing with sizes |
342
+ | `tier` | string | No | Pre-packaged documentation tier for context-limited models: `survival` (~800 tokens) or `working` (~3500 tokens). Overrides topic/file_path/mode when set |
343
+ | `max_tokens` | number | No | Maximum estimated token budget. Loads topics in priority order until budget is reached. Helps prevent context overflow for small-window models |
342
344
  | `exclude_topics` | string[] | No | Topic names to exclude from `file_path` results (e.g., topics already loaded) |
343
345
 
344
346
  **Available Topics:**
345
347
 
346
348
  | Topic | Description |
347
349
  |-------|-------------|
350
+ | `survival` | Minimal syntax survival kit (~3KB, ~800 tokens) for models with <16K context |
351
+ | `working` | Complete working reference (~12KB, ~3500 tokens) for models with 16-64K context |
348
352
  | `readme` | XanoScript overview, workspace structure, and quick reference |
349
353
  | `essentials` | Common patterns, quick reference, and common mistakes to avoid |
350
354
  | `syntax` | Expressions, operators, and filters for all XanoScript code |
@@ -387,6 +391,12 @@ Retrieves XanoScript programming language documentation with context-aware suppo
387
391
  // Get overview
388
392
  xanoscript_docs()
389
393
 
394
+ // Get survival kit for small context models (~800 tokens)
395
+ xanoscript_docs({ tier: "survival" })
396
+
397
+ // Get working reference for medium context models (~3500 tokens)
398
+ xanoscript_docs({ tier: "working" })
399
+
390
400
  // Get essentials (recommended first stop)
391
401
  xanoscript_docs({ topic: "essentials" })
392
402
 
@@ -396,6 +406,9 @@ xanoscript_docs({ topic: "functions" })
396
406
  // Discover available topics with sizes
397
407
  xanoscript_docs({ mode: "index" })
398
408
 
409
+ // Budget-aware: load docs up to token limit
410
+ xanoscript_docs({ file_path: "api/users/create_post.xs", max_tokens: 2000 })
411
+
399
412
  // Context-aware: get all docs relevant to file being edited
400
413
  xanoscript_docs({ file_path: "api/users/create_post.xs" })
401
414
 
@@ -516,6 +529,8 @@ The server also exposes XanoScript documentation as MCP resources for direct acc
516
529
 
517
530
  | Resource URI | Description |
518
531
  |--------------|-------------|
532
+ | `xanoscript://docs/survival` | Minimal syntax survival kit (~800 tokens) |
533
+ | `xanoscript://docs/working` | Complete working reference (~3500 tokens) |
519
534
  | `xanoscript://docs/readme` | Overview and quick reference |
520
535
  | `xanoscript://docs/essentials` | Common patterns, quick reference, and common mistakes to avoid |
521
536
  | `xanoscript://docs/syntax` | Expressions, operators, and filters |
@@ -118,6 +118,15 @@ export declare const toolDefinitions: ({
118
118
  enum: string[];
119
119
  description: string;
120
120
  };
121
+ tier: {
122
+ type: string;
123
+ enum: string[];
124
+ description: string;
125
+ };
126
+ max_tokens: {
127
+ type: string;
128
+ description: string;
129
+ };
121
130
  exclude_topics: {
122
131
  type: string;
123
132
  items: {
@@ -76,6 +76,15 @@ export declare const xanoscriptDocsToolDefinition: {
76
76
  enum: string[];
77
77
  description: string;
78
78
  };
79
+ tier: {
80
+ type: string;
81
+ enum: string[];
82
+ description: string;
83
+ };
84
+ max_tokens: {
85
+ type: string;
86
+ description: string;
87
+ };
79
88
  exclude_topics: {
80
89
  type: string;
81
90
  items: {
@@ -92,6 +92,15 @@ export function xanoscriptDocs(args) {
92
92
  export function xanoscriptDocsTool(args) {
93
93
  try {
94
94
  const docsPath = getXanoscriptDocsPath();
95
+ // Tier mode: return single content block for pre-built tiers
96
+ if (args?.tier) {
97
+ const result = xanoscriptDocs(args);
98
+ return {
99
+ success: true,
100
+ data: result.documentation,
101
+ structuredContent: { tier: args.tier, documentation: result.documentation },
102
+ };
103
+ }
95
104
  // file_path mode: return structured multi-content (one block per topic)
96
105
  if (args?.file_path) {
97
106
  const version = getXanoscriptDocsVersion(docsPath);
@@ -139,8 +148,10 @@ export const xanoscriptDocsToolDefinition = {
139
148
  name: "xanoscript_docs",
140
149
  description: "Get XanoScript programming language documentation for AI code generation. " +
141
150
  "Call without parameters for overview (README). " +
151
+ "For context-limited models: use tier='survival' (~800 tokens) or tier='working' (~3500 tokens). " +
142
152
  "Use 'topic' for specific documentation, or 'file_path' for context-aware docs based on the file you're editing. " +
143
153
  "Use mode='quick_reference' for compact syntax reference (recommended for context efficiency). " +
154
+ "Use max_tokens to limit documentation size to fit your context budget. " +
144
155
  "file_path mode defaults to 'quick_reference' to reduce context size; use mode='full' to get complete docs.",
145
156
  annotations: {
146
157
  readOnlyHint: true,
@@ -175,6 +186,22 @@ export const xanoscriptDocsToolDefinition = {
175
186
  "Use 'quick_reference' to save context window space when you just need a reminder. " +
176
187
  "Default: 'full' for topic mode, 'quick_reference' for file_path mode.",
177
188
  },
189
+ tier: {
190
+ type: "string",
191
+ enum: ["survival", "working"],
192
+ description: "Pre-packaged documentation tier for context-limited models. " +
193
+ "'survival' (~3KB, ~800 tokens): minimum syntax to write valid XanoScript. " +
194
+ "'working' (~12KB, ~3500 tokens): complete reference for common tasks. " +
195
+ "Overrides topic/file_path/mode when set. " +
196
+ "Use 'survival' for models with <16K context, 'working' for 16-64K context.",
197
+ },
198
+ max_tokens: {
199
+ type: "number",
200
+ description: "Maximum estimated token budget for documentation. " +
201
+ "When used with file_path, loads topics in priority order until budget is reached. " +
202
+ "Helps prevent context overflow for small-window models. " +
203
+ "Estimate: 1KB of docs ≈ 250 tokens.",
204
+ },
178
205
  exclude_topics: {
179
206
  type: "array",
180
207
  items: { type: "string" },
@@ -8,11 +8,14 @@ export interface DocConfig {
8
8
  file: string;
9
9
  applyTo: string[];
10
10
  description: string;
11
+ priority?: number;
11
12
  }
12
13
  export interface XanoscriptDocsArgs {
13
14
  topic?: string;
14
15
  file_path?: string;
15
16
  mode?: "full" | "quick_reference" | "index";
17
+ tier?: "survival" | "working";
18
+ max_tokens?: number;
16
19
  exclude_topics?: string[];
17
20
  }
18
21
  export declare const XANOSCRIPT_DOCS_V2: Record<string, DocConfig>;
@@ -26,7 +29,8 @@ export declare function clearDocsCache(): void;
26
29
  */
27
30
  export declare function getDocsForFilePath(filePath: string): string[];
28
31
  /**
29
- * Extract just the Quick Reference section from a doc
32
+ * Extract the Quick Reference section plus critical sections
33
+ * (Common Mistakes, Decision/Choosing trees) from a doc.
30
34
  */
31
35
  export declare function extractQuickReference(content: string, topic: string): string;
32
36
  /**
@@ -18,6 +18,7 @@ function buildDocsConfig() {
18
18
  file: topic.file,
19
19
  applyTo: topic.applyTo,
20
20
  description: topic.description,
21
+ priority: topic.priority,
21
22
  };
22
23
  }
23
24
  return config;
@@ -69,7 +70,8 @@ export function getDocsForFilePath(filePath) {
69
70
  return matches;
70
71
  }
71
72
  /**
72
- * Extract just the Quick Reference section from a doc
73
+ * Extract the Quick Reference section plus critical sections
74
+ * (Common Mistakes, Decision/Choosing trees) from a doc.
73
75
  */
74
76
  export function extractQuickReference(content, topic) {
75
77
  const lines = content.split("\n");
@@ -83,9 +85,21 @@ export function extractQuickReference(content, topic) {
83
85
  let endIdx = lines.findIndex((l, i) => i > startIdx && l.startsWith("## "));
84
86
  if (endIdx === -1)
85
87
  endIdx = lines.length;
88
+ const sections = [lines.slice(startIdx, endIdx).join("\n")];
89
+ // Also extract Common Mistakes and Decision/Choosing sections if present
90
+ const bonusSections = ["## Common Mistakes", "## Choosing", "## Decision"];
91
+ for (const sectionName of bonusSections) {
92
+ const sIdx = lines.findIndex((l) => l.startsWith(sectionName));
93
+ if (sIdx !== -1 && sIdx !== startIdx) {
94
+ let eIdx = lines.findIndex((l, i) => i > sIdx && l.startsWith("## "));
95
+ if (eIdx === -1)
96
+ eIdx = lines.length;
97
+ sections.push(lines.slice(sIdx, eIdx).join("\n"));
98
+ }
99
+ }
86
100
  // Include topic header for context
87
101
  const header = `# ${topic}\n\n`;
88
- return header + lines.slice(startIdx, endIdx).join("\n");
102
+ return header + sections.join("\n\n---\n\n");
89
103
  }
90
104
  /**
91
105
  * Get the documentation version from the version.json file
@@ -109,7 +123,13 @@ export function getXanoscriptDocsVersion(docsPath) {
109
123
  */
110
124
  export function readXanoscriptDocsV2(docsPath, args) {
111
125
  const version = getXanoscriptDocsVersion(docsPath);
112
- // Index mode: return compact topic listing with byte sizes
126
+ // Tier mode: return pre-built documentation tier
127
+ if (args?.tier) {
128
+ const tierFile = args.tier === "survival" ? "survival.md" : "working.md";
129
+ const content = cachedReadFile(join(docsPath, tierFile));
130
+ return `${content}\n\n---\nDocumentation version: ${version}`;
131
+ }
132
+ // Index mode: return compact topic listing with byte sizes and token estimates
113
133
  if (args?.mode === "index") {
114
134
  const rows = Object.entries(XANOSCRIPT_DOCS_V2).map(([name, config]) => {
115
135
  let size;
@@ -120,7 +140,8 @@ export function readXanoscriptDocsV2(docsPath, args) {
120
140
  size = 0;
121
141
  }
122
142
  const sizeKb = (size / 1024).toFixed(1);
123
- return `| ${name} | ${config.description} | ${sizeKb} KB |`;
143
+ const estTokens = Math.ceil(size / 4);
144
+ return `| ${name} | ${config.description} | ${sizeKb} KB | ~${estTokens} |`;
124
145
  });
125
146
  return [
126
147
  `# XanoScript Documentation Index`,
@@ -128,11 +149,12 @@ export function readXanoscriptDocsV2(docsPath, args) {
128
149
  `Version: ${version}`,
129
150
  `Topics: ${rows.length}`,
130
151
  ``,
131
- `| Topic | Description | Size |`,
132
- `|-------|-------------|------|`,
152
+ `| Topic | Description | Size | Est. Tokens |`,
153
+ `|-------|-------------|------|-------------|`,
133
154
  ...rows,
134
155
  ``,
135
156
  `Use topic='<name>' to load a specific topic. Use mode='quick_reference' for compact output.`,
157
+ `Use tier='survival' (~800 tokens) or tier='working' (~3500 tokens) for context-limited models.`,
136
158
  ].join("\n");
137
159
  }
138
160
  // Default to quick_reference for file_path mode (loads many topics),
@@ -150,6 +172,27 @@ export function readXanoscriptDocsV2(docsPath, args) {
150
172
  if (args.exclude_topics && args.exclude_topics.length > 0) {
151
173
  topics = topics.filter((t) => !args.exclude_topics.includes(t));
152
174
  }
175
+ // Budget-aware loading: sort by priority and stop when budget is exceeded
176
+ if (args.max_tokens) {
177
+ let tokenBudget = args.max_tokens;
178
+ const sortedTopics = [...topics].sort((a, b) => {
179
+ const pa = XANOSCRIPT_DOCS_V2[a]?.priority ?? 99;
180
+ const pb = XANOSCRIPT_DOCS_V2[b]?.priority ?? 99;
181
+ return pa - pb;
182
+ });
183
+ const filteredTopics = [];
184
+ for (const t of sortedTopics) {
185
+ const config = XANOSCRIPT_DOCS_V2[t];
186
+ const content = cachedReadFile(join(docsPath, config.file));
187
+ const topicContent = mode === "quick_reference" ? extractQuickReference(content, t) : content;
188
+ const estimatedTokens = Math.ceil(topicContent.length / 4);
189
+ if (tokenBudget - estimatedTokens < 0 && filteredTopics.length > 0)
190
+ break;
191
+ filteredTopics.push(t);
192
+ tokenBudget -= estimatedTokens;
193
+ }
194
+ topics = filteredTopics;
195
+ }
153
196
  if (topics.length === 0) {
154
197
  throw new Error(`No documentation found for file pattern: ${args.file_path}\n\nAvailable topics: ${Object.keys(XANOSCRIPT_DOCS_V2).join(", ")}`);
155
198
  }
@@ -185,6 +228,27 @@ export function readXanoscriptDocsStructured(docsPath, args) {
185
228
  if (args.exclude_topics && args.exclude_topics.length > 0) {
186
229
  topics = topics.filter((t) => !args.exclude_topics.includes(t));
187
230
  }
231
+ // Budget-aware loading
232
+ if (args.max_tokens) {
233
+ let tokenBudget = args.max_tokens;
234
+ const sortedTopics = [...topics].sort((a, b) => {
235
+ const pa = XANOSCRIPT_DOCS_V2[a]?.priority ?? 99;
236
+ const pb = XANOSCRIPT_DOCS_V2[b]?.priority ?? 99;
237
+ return pa - pb;
238
+ });
239
+ const filteredTopics = [];
240
+ for (const t of sortedTopics) {
241
+ const config = XANOSCRIPT_DOCS_V2[t];
242
+ const content = cachedReadFile(join(docsPath, config.file));
243
+ const topicContent = mode === "quick_reference" ? extractQuickReference(content, t) : content;
244
+ const estimatedTokens = Math.ceil(topicContent.length / 4);
245
+ if (tokenBudget - estimatedTokens < 0 && filteredTopics.length > 0)
246
+ break;
247
+ filteredTopics.push(t);
248
+ tokenBudget -= estimatedTokens;
249
+ }
250
+ topics = filteredTopics;
251
+ }
188
252
  if (topics.length === 0) {
189
253
  throw new Error(`No documentation found for file pattern: ${args.file_path}\n\nAvailable topics: ${Object.keys(XANOSCRIPT_DOCS_V2).join(", ")}`);
190
254
  }
@@ -9,6 +9,8 @@ describe("xanoscript module", () => {
9
9
  describe("XANOSCRIPT_DOCS_V2", () => {
10
10
  it("should have all expected topics", () => {
11
11
  const expectedTopics = [
12
+ "survival",
13
+ "working",
12
14
  "readme",
13
15
  "essentials",
14
16
  "syntax",
@@ -310,7 +312,7 @@ Even more content.
310
312
  it("should throw when all topics are excluded via exclude_topics", () => {
311
313
  expect(() => readXanoscriptDocsV2(DOCS_PATH, {
312
314
  file_path: "branch.xs",
313
- exclude_topics: ["syntax", "essentials", "debugging", "branch"],
315
+ exclude_topics: ["syntax", "essentials", "debugging", "branch", "survival", "working"],
314
316
  })).toThrow("No documentation found");
315
317
  });
316
318
  it("should throw for invalid docs path", () => {
@@ -321,7 +323,7 @@ Even more content.
321
323
  expect(result).toContain("# XanoScript Documentation Index");
322
324
  expect(result).toContain("Version:");
323
325
  expect(result).toContain("Topics:");
324
- expect(result).toContain("| Topic | Description | Size |");
326
+ expect(result).toContain("| Topic | Description | Size | Est. Tokens |");
325
327
  // Should contain some known topics
326
328
  expect(result).toContain("| syntax |");
327
329
  expect(result).toContain("| essentials |");
@@ -404,7 +406,7 @@ Even more content.
404
406
  it("should throw when all topics are excluded", () => {
405
407
  expect(() => readXanoscriptDocsStructured(DOCS_PATH, {
406
408
  file_path: "branch.xs",
407
- exclude_topics: ["syntax", "essentials", "debugging", "branch"],
409
+ exclude_topics: ["syntax", "essentials", "debugging", "branch", "survival", "working"],
408
410
  })).toThrow("No documentation found");
409
411
  });
410
412
  it("should use quick_reference mode by default", () => {
@@ -178,6 +178,15 @@ This includes:
178
178
 
179
179
  Use `xanoscript_docs({ topic: "<topic>" })` to retrieve documentation.
180
180
 
181
+ ### Tiers (for context-limited models)
182
+
183
+ | Topic | Description | Size |
184
+ | ---------- | ------------------------------------------------------------ | ---- |
185
+ | `survival` | Minimal syntax survival kit for models with <16K context | ~3KB (~800 tokens) |
186
+ | `working` | Complete working reference for models with 16-64K context | ~12KB (~3500 tokens) |
187
+
188
+ Use `xanoscript_docs({ tier: "survival" })` or `xanoscript_docs({ tier: "working" })`.
189
+
181
190
  ### Core Language
182
191
 
183
192
  | Topic | Description | Key Sections |
@@ -245,46 +254,3 @@ Use `xanoscript_docs({ topic: "<topic>" })` to retrieve documentation.
245
254
  | `performance` | Performance optimization best practices | Caching, Query Optimization |
246
255
  | `security` | Security best practices for authentication and authorization | Auth Patterns, Token Handling |
247
256
 
248
- ---
249
-
250
- ## Example Implementations
251
-
252
- Common integration patterns you can reference:
253
-
254
- ### External API Integrations
255
- - **OpenAI/ChatGPT**: Use `api.request` with POST to `/v1/chat/completions`
256
- - **Stripe**: Use `api.request` with form-encoded params for payments
257
- - **SendGrid/Resend**: Use `api.request` or `util.send_email` for emails
258
- - **Slack/Discord**: Use `api.request` with webhook URLs
259
- - **Twilio**: Use `api.request` with Basic auth for SMS
260
-
261
- ### Common Pattern: API Integration Function
262
-
263
- ```xs
264
- function "call_external_api" {
265
- input {
266
- text endpoint
267
- object payload
268
- }
269
- stack {
270
- api.request {
271
- url = $env.API_BASE_URL ~ $input.endpoint
272
- method = "POST"
273
- params = $input.payload
274
- headers = [
275
- "Content-Type: application/json",
276
- "Authorization: Bearer " ~ $env.API_KEY
277
- ]
278
- timeout = 30
279
- } as $api_result
280
-
281
- precondition ($api_result.response.status >= 200 && $api_result.response.status < 300) {
282
- error_type = "standard"
283
- error = "API error: " ~ ($api_result.response.status|to_text)
284
- }
285
- }
286
- response = $api_result.response.result
287
- }
288
- ```
289
-
290
- For more patterns, see `xanoscript_docs({ topic: "essentials" })` or `xanoscript_docs({ topic: "integrations" })`.
@@ -252,8 +252,6 @@ addon/
252
252
  1. **Keep addons focused** - One purpose per addon
253
253
  2. **Use input parameters** - Make addons reusable
254
254
  3. **Use appropriate return types** - `list`, `single`, `count`, `exists`
255
- 4. **Limit nested queries** - Avoid N+1 query patterns
256
- 5. **Document inputs** - Add descriptions to input fields
257
255
 
258
256
  ---
259
257
 
@@ -290,35 +290,6 @@ agent "Code Reviewer" {
290
290
  }
291
291
  ```
292
292
 
293
- ### Multi-Tool Research Agent
294
- ```xs
295
- agent "Research Assistant" {
296
- canonical = "research-v1"
297
- llm = {
298
- type: "openai"
299
- api_key: "{{ $env.OPENAI_API_KEY }}"
300
- model: "gpt-5"
301
- system_prompt: """
302
- You are a research assistant. Use your tools to:
303
- 1. Search for relevant information
304
- 2. Analyze data
305
- 3. Compile findings into clear summaries
306
- Always cite your sources.
307
- """
308
- prompt: "Research topic: {{ $args.topic }}"
309
- max_steps: 10
310
- temperature: 0.5
311
- reasoning_effort: "high"
312
- }
313
- tools = [
314
- { name: "web_search" },
315
- { name: "fetch_article" },
316
- { name: "analyze_data" },
317
- { name: "save_findings" }
318
- ]
319
- }
320
- ```
321
-
322
293
  ---
323
294
 
324
295
  ## External MCP Tools
@@ -407,12 +378,8 @@ agent "Research Agent" {
407
378
  ## Best Practices
408
379
 
409
380
  1. **Clear system prompts** - Define persona, capabilities, and constraints
410
- 2. **Use appropriate temperature** - Low for factual, higher for creative
411
- 3. **Limit max_steps** - Prevent infinite loops (3-10 typical)
412
- 4. **Don't repeat tool descriptions** - They're auto-injected
413
- 5. **Use environment variables** - Never hardcode API keys
414
- 6. **Test with xano-free first** - Free for development
415
- 7. **Validate external MCP servers** - Check server_details before using
381
+ 2. **Limit max_steps** - Prevent infinite loops (3-10 typical)
382
+ 3. **Don't repeat tool descriptions** - They're auto-injected; use environment variables for API keys
416
383
 
417
384
  ---
418
385
 
@@ -440,12 +440,9 @@ When using `return = { type: "list", paging: {...} }`:
440
440
 
441
441
  ## Best Practices
442
442
 
443
- 1. **RESTful design** - Use appropriate HTTP methods for operations
444
- 2. **Consistent naming** - Use lowercase, hyphens for multi-word paths
445
- 3. **Authenticate writes** - Always require auth for POST/PATCH/DELETE
446
- 4. **Paginate lists** - Never return unbounded result sets
447
- 5. **Group by resource** - Organize endpoints in logical api groups
448
- 6. **Use specific canonicals** - Prefix canonicals to avoid instance-level collisions (e.g., `myapp-users` not `users`)
443
+ 1. **Use specific canonicals** - Prefix canonicals to avoid instance-level collisions (e.g., `myapp-users` not `users`)
444
+ 2. **Authenticate writes** - Always require `auth` for POST/PATCH/DELETE endpoints
445
+ 3. **Paginate lists** - Use `return = { type: "list", paging: {...} }` to avoid unbounded result sets
449
446
 
450
447
  ---
451
448
 
@@ -236,5 +236,3 @@ project/
236
236
  1. **Use descriptive colors** - Green for production, blue for development, yellow for staging
237
237
  2. **Limit production history** - Excessive history impacts performance and storage
238
238
  3. **Apply security middleware in production** - Rate limiting, auth checks, audit logging
239
- 4. **Disable middleware history in production** - Reduces noise and storage
240
- 5. **Enable full history in development** - Aids debugging and testing
@@ -628,13 +628,9 @@ try_catch {
628
628
 
629
629
  ## Best Practices
630
630
 
631
- 1. **Use db.query for searches** - Flexible filtering and pagination
632
- 2. **Use db.get for single lookups** - Simpler than db.query with single return
633
- 3. **Use db.patch for dynamic updates** - Accepts variable data
634
- 4. **Use transactions for atomicity** - Ensure all-or-nothing operations
635
- 5. **Use null-safe operators** - `==?` for optional filters
636
- 6. **Use bulk operations for batch processing** - More efficient than loops
637
- 7. **Handle deadlocks gracefully** - Implement retry logic for concurrent writes
631
+ 1. **Use null-safe operators** - `==?` for optional filters avoids manual null checks
632
+ 2. **Use bulk operations for batch processing** - More efficient than loops with individual db calls
633
+ 3. **Use transactions for atomicity** - Ensure all-or-nothing operations across multiple tables
638
634
 
639
635
  ---
640
636