melchizedek-agents 0.16.2 → 0.18.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.
Files changed (100) hide show
  1. package/.env.example +40 -3
  2. package/AGENT_SETUP.md +4 -2
  3. package/CHANGELOG.md +246 -0
  4. package/DOCUMENTATION.md +311 -15
  5. package/QUICKSTART.md +2 -2
  6. package/README.md +125 -149
  7. package/config/agents/examples/harness.yaml +135 -0
  8. package/config/agents/examples/model_zoo.yaml +23 -9
  9. package/config/agents/examples/pipeline.yaml +120 -0
  10. package/config/agents/examples/specs/open-meteo-forecast.json +77 -0
  11. package/config/agents/examples/specs/open-meteo-geocoding.json +53 -0
  12. package/config/agents/examples/weather.yaml +59 -0
  13. package/config/agents/syndicateSchema.yaml +125 -1
  14. package/db/hardening.sql +4 -3
  15. package/db/migrations/0011_erase_expired.sql +198 -0
  16. package/db/migrations/0012_audit_log.sql +98 -0
  17. package/dist/lib/a2a/app.d.ts +27 -0
  18. package/dist/lib/a2a/app.js +101 -5
  19. package/dist/lib/a2a/executor.d.ts +34 -4
  20. package/dist/lib/a2a/executor.js +109 -9
  21. package/dist/lib/compile.d.ts +41 -3
  22. package/dist/lib/compile.js +162 -17
  23. package/dist/lib/config.d.ts +24 -0
  24. package/dist/lib/config.js +24 -0
  25. package/dist/lib/doctor.js +17 -4
  26. package/dist/lib/index.d.ts +2 -0
  27. package/dist/lib/index.js +1 -0
  28. package/dist/lib/loadEnv.d.ts +5 -0
  29. package/dist/lib/loadEnv.js +7 -0
  30. package/dist/lib/loadSyndicate.d.ts +50 -0
  31. package/dist/lib/loadSyndicate.js +19 -3
  32. package/dist/lib/memory/erase.d.ts +5 -0
  33. package/dist/lib/memory/erase.js +5 -0
  34. package/dist/lib/memory/providers.d.ts +27 -0
  35. package/dist/lib/memory/providers.js +28 -0
  36. package/dist/lib/models/capabilities.js +10 -0
  37. package/dist/lib/models/endpoints.d.ts +1 -1
  38. package/dist/lib/models/endpoints.js +4 -1
  39. package/dist/lib/models/fallback.d.ts +41 -0
  40. package/dist/lib/models/fallback.js +105 -0
  41. package/dist/lib/models/gateway.d.ts +2 -2
  42. package/dist/lib/models/gateway.js +4 -4
  43. package/dist/lib/models/kimiLlm.d.ts +123 -0
  44. package/dist/lib/models/kimiLlm.js +171 -0
  45. package/dist/lib/models/providerMap.d.ts +2 -2
  46. package/dist/lib/models/providerMap.js +4 -1
  47. package/dist/lib/models/registry.d.ts +1 -1
  48. package/dist/lib/models/registry.js +11 -3
  49. package/dist/lib/net/redirects.d.ts +14 -0
  50. package/dist/lib/net/redirects.js +94 -0
  51. package/dist/lib/observability/audit.d.ts +21 -0
  52. package/dist/lib/observability/audit.js +39 -0
  53. package/dist/lib/observability/metrics.d.ts +6 -0
  54. package/dist/lib/observability/tracer.d.ts +14 -1
  55. package/dist/lib/observability/tracer.js +16 -2
  56. package/dist/lib/persistence/supabaseProvider.d.ts +2 -6
  57. package/dist/lib/persistence/supabaseProvider.js +2 -31
  58. package/dist/lib/runtime/questions.d.ts +55 -0
  59. package/dist/lib/runtime/questions.js +107 -0
  60. package/dist/lib/runtime/syndicateTurn.d.ts +45 -5
  61. package/dist/lib/runtime/syndicateTurn.js +165 -17
  62. package/dist/lib/storage/postgres/index.d.ts +9 -0
  63. package/dist/lib/storage/postgres/index.js +13 -0
  64. package/dist/lib/storage/rlsStatus.d.ts +45 -0
  65. package/dist/lib/storage/rlsStatus.js +69 -0
  66. package/dist/lib/syndicateSchema.d.ts +177 -0
  67. package/dist/lib/syndicateSchema.js +343 -3
  68. package/dist/lib/toolRegistry.js +9 -0
  69. package/dist/lib/tools/mcpToolFactory.d.ts +26 -0
  70. package/dist/lib/tools/mcpToolFactory.js +61 -4
  71. package/dist/lib/tools/openapiTools.d.ts +52 -0
  72. package/dist/lib/tools/openapiTools.js +225 -0
  73. package/dist/lib/tools/skillToolset.d.ts +135 -0
  74. package/dist/lib/tools/skillToolset.js +247 -0
  75. package/dist/lib/tools/urlContextTool.d.ts +29 -0
  76. package/dist/lib/tools/urlContextTool.js +39 -0
  77. package/dist/lib/workflow.d.ts +72 -0
  78. package/dist/lib/workflow.js +180 -0
  79. package/dist/lib/workflowConfig.d.ts +95 -0
  80. package/dist/lib/workflowConfig.js +93 -0
  81. package/dist/scripts/a2a_server.js +51 -8
  82. package/dist/scripts/db.d.ts +9 -0
  83. package/dist/scripts/db.js +30 -15
  84. package/dist/scripts/syndicate_chat.js +39 -5
  85. package/package.json +6 -3
  86. package/skills/briefs/_shared.md +1 -1
  87. package/skills/briefs/melchizedek-author.md +8 -4
  88. package/skills/briefs/melchizedek-memory.md +1 -1
  89. package/skills/briefs/melchizedek-models.md +1 -1
  90. package/skills/briefs/melchizedek-scribe.md +4 -4
  91. package/skills/briefs/melchizedek-serve.md +1 -1
  92. package/skills/briefs/melchizedek.md +4 -1
  93. package/skills/melchizedek/SKILL.md +4 -1
  94. package/skills/melchizedek-author/SKILL.md +7 -3
  95. package/skills/melchizedek-memory/SKILL.md +1 -1
  96. package/skills/melchizedek-models/SKILL.md +1 -1
  97. package/skills/melchizedek-scribe/SKILL.md +3 -3
  98. package/skills/melchizedek-serve/SKILL.md +1 -1
  99. /package/skills/melchizedek-author/{templates → assets}/minimal.yaml +0 -0
  100. /package/skills/melchizedek-scribe/{templates → assets}/brief.md +0 -0
@@ -42,6 +42,20 @@ export function installOrder(withTelemetry) {
42
42
  const base = [...migrationFiles(), 'hardening.sql'];
43
43
  return withTelemetry ? [...base, 'telemetry.sql', 'hardening.sql'] : base;
44
44
  }
45
+ /**
46
+ * The whole install as one psql script: an advisory lock first, then every
47
+ * file in order with a progress line before each. psql runs it with
48
+ * --single-transaction and ON_ERROR_STOP, so a failure anywhere rolls the
49
+ * whole install back (no half-applied migration), and a second `apply`
50
+ * started meanwhile waits on the lock instead of interleaving with this one.
51
+ */
52
+ export const APPLY_LOCK_KEY = 'melchizedek-db apply';
53
+ export function applyScript(files, sqlOf, label = (f) => `db/${f}`) {
54
+ const parts = [`SELECT pg_advisory_xact_lock(hashtext('${APPLY_LOCK_KEY}'));\n`];
55
+ for (const file of files)
56
+ parts.push(`\\echo '→ applying ${label(file).replace(/'/g, '')}'\n`, sqlOf(file), '\n');
57
+ return parts.join('');
58
+ }
45
59
  /** postgres://user:pass@host:port/db?sslmode=… → libpq environment variables. */
46
60
  export function pgEnv(url) {
47
61
  const u = new URL(url);
@@ -100,21 +114,22 @@ async function main() {
100
114
  console.error(' or set DATABASE_URL to the Postgres connection string (Supabase: Settings → Database).');
101
115
  process.exit(1);
102
116
  }
103
- for (const file of installOrder(withTelemetry)) {
104
- console.log(`→ applying db/${file}${schema === 'public' ? '' : ` into schema ${schema}`}`);
105
- const r = spawnSync('psql', ['-v', 'ON_ERROR_STOP=1', '-q', '-f', '-'], {
106
- input: sqlOf(file),
107
- stdio: ['pipe', 'inherit', 'inherit'],
108
- // The connection goes to psql as PG* variables, never as an
109
- // argument, so the password stays out of the process list.
110
- env: { ...process.env, ...pgEnv(url) },
111
- });
112
- if (r.error) {
113
- console.error(`✗ could not run psql (${r.error.message}). Install the Postgres client, or use \`print\`.`);
114
- process.exit(1);
115
- }
116
- if (r.status !== 0)
117
- process.exit(r.status ?? 1);
117
+ // One transaction under one lock (see applyScript): all of it, or none.
118
+ const script = applyScript(installOrder(withTelemetry), sqlOf, (f) => `db/${f}${schema === 'public' ? '' : ` into schema ${schema}`}`);
119
+ const r = spawnSync('psql', ['-v', 'ON_ERROR_STOP=1', '-q', '--single-transaction', '-f', '-'], {
120
+ input: script,
121
+ stdio: ['pipe', 'inherit', 'inherit'],
122
+ // The connection goes to psql as PG* variables, never as an
123
+ // argument, so the password stays out of the process list.
124
+ env: { ...process.env, ...pgEnv(url) },
125
+ });
126
+ if (r.error) {
127
+ console.error(`✗ could not run psql (${r.error.message}). Install the Postgres client, or use \`print\`.`);
128
+ process.exit(1);
129
+ }
130
+ if (r.status !== 0) {
131
+ console.error('✗ the install failed and was rolled back: the database is as it was before `apply`.');
132
+ process.exit(r.status ?? 1);
118
133
  }
119
134
  console.log('✓ database is installed and hardened');
120
135
  return;
@@ -4,7 +4,7 @@ import { writeFileSync, mkdirSync } from 'node:fs';
4
4
  import { join } from 'node:path';
5
5
  import { loadSyndicate, parseCliBindings } from '../lib/loadSyndicate.js';
6
6
  import { isDispatchSyndicate } from '../lib/dispatch.js';
7
- import { ingestTurnMemory, runSyndicateTurn } from '../lib/runtime/syndicateTurn.js';
7
+ import { approvalResponsePart, describeApproval, describeInput, ingestTurnMemory, runSyndicateTurn } from '../lib/runtime/syndicateTurn.js';
8
8
  import { InMemorySessionService, getFunctionCalls, getFunctionResponses, setLogLevel, LogLevel, } from '@google/adk';
9
9
  import { randomUUID } from 'node:crypto';
10
10
  import { loadEnv } from '../lib/loadEnv.js';
@@ -215,13 +215,15 @@ async function main() {
215
215
  const cliInput = queryParts.join(' ');
216
216
  // Ctrl+C during a turn cancels the turn; Ctrl+C at the prompt exits.
217
217
  let activeTurn;
218
- async function runChat(trimmed) {
218
+ /** A gated call waiting for this person's yes (ADR 0028); answered by the next prompt. */
219
+ let pendingApproval;
220
+ async function runChat(trimmed, parts = [{ text: trimmed }]) {
219
221
  const printer = makePrinter();
220
222
  activeTurn = new AbortController();
221
223
  try {
222
224
  const result = await runSyndicateTurn({
223
225
  config,
224
- parts: [{ text: trimmed }],
226
+ parts,
225
227
  appName,
226
228
  userId: SESSION_USER_ID,
227
229
  sessionId: SESSION_ID,
@@ -249,7 +251,18 @@ async function main() {
249
251
  // The orchestrator's relay came back empty; show what shipped.
250
252
  console.log(`\n${c.dim}[relay fallback — the specialist's answer]${c.reset}\n${result.text}`);
251
253
  }
252
- if (result.status !== 'completed') {
254
+ if (result.status === 'input-required' && result.approval) {
255
+ // The turn stopped on a tool a person must approve: a gated tool,
256
+ // or a skill script. The next prompt asks for the decision.
257
+ pendingApproval = result.approval;
258
+ console.log(`\n${c.yellow}⏸ Approval needed: ${describeApproval(result.approval)}${c.reset}`);
259
+ }
260
+ else if (result.status === 'input-required' && result.input) {
261
+ // A workflow's ask_user node: whatever is typed next is the answer,
262
+ // and the graph resumes from that node.
263
+ console.log(`\n${c.yellow}❓ ${describeInput(result.input)}${c.reset}\n${c.dim} (your next message is the answer)${c.reset}`);
264
+ }
265
+ else if (result.status !== 'completed') {
253
266
  console.error(`\n${c.yellow}⚠ [${result.error?.code ?? 'ERROR'}] ${result.error?.message ?? ''}${c.reset}`);
254
267
  }
255
268
  console.log('\n');
@@ -286,12 +299,29 @@ async function main() {
286
299
  if (cliInput) {
287
300
  console.log(`${c.green}${c.bold}You${c.reset} › ${cliInput}`);
288
301
  await runChat(cliInput);
302
+ if (pendingApproval) {
303
+ // A one-shot run has nobody to ask: the call stays unapproved and
304
+ // never runs. Interactive mode, or an A2A client, can answer it.
305
+ console.error(`${c.yellow}⚠ The run stopped on a call that needs your approval; it did not run. Start the chat without a query to approve or refuse such calls.${c.reset}`);
306
+ process.exitCode = 2;
307
+ }
289
308
  // A one-shot query still contributes to long-term memory.
290
309
  await ingest();
291
310
  return;
292
311
  }
293
312
  const rl = createInterface({ input: process.stdin, output: process.stdout });
294
313
  const ask = () => {
314
+ if (pendingApproval) {
315
+ const approval = pendingApproval;
316
+ rl.question(`${c.yellow}${c.bold}Approve${c.reset} ${describeApproval(approval)}? [y/N] › `, async (answer) => {
317
+ pendingApproval = undefined;
318
+ const approved = /^y(es)?$/i.test(answer.trim());
319
+ console.log(`${c.dim} ${approved ? 'Approved' : 'Refused'}: ${approval.agent} → ${approval.tool}${c.reset}`);
320
+ await runChat(approved ? 'approve' : 'reject', [approvalResponsePart(approval.id, approved)]);
321
+ ask();
322
+ });
323
+ return;
324
+ }
295
325
  rl.question(`${c.green}${c.bold}You${c.reset} › `, async (userInput) => {
296
326
  const trimmed = userInput.trim();
297
327
  if (!trimmed) {
@@ -334,6 +364,9 @@ async function main() {
334
364
  function makePrinter() {
335
365
  let currentMode = 'none';
336
366
  let streamedText = false;
367
+ // Which agent the current text label names: a workflow's nodes speak in
368
+ // turn, each under its own label.
369
+ let labelled = '';
337
370
  return {
338
371
  onEvent(event) {
339
372
  const e = event;
@@ -363,9 +396,10 @@ function makePrinter() {
363
396
  else if (p.text) {
364
397
  if (!isPartial && streamedText)
365
398
  continue;
366
- if (currentMode !== 'text') {
399
+ if (currentMode !== 'text' || labelled !== e.author) {
367
400
  process.stdout.write(`\n${c.magenta}${c.bold}${e.author}${c.reset} › `);
368
401
  currentMode = 'text';
402
+ labelled = e.author;
369
403
  }
370
404
  process.stdout.write(p.text);
371
405
  if (isPartial)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "melchizedek-agents",
3
- "version": "0.16.2",
3
+ "version": "0.18.0",
4
4
  "description": "A multi-model, multi-agent orchestration framework on Google ADK — YAML-defined syndicates, Supabase session persistence, pgvector long-term memory. Companion repo to the lyceumagents.com curriculum.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -12,7 +12,7 @@
12
12
  "bugs": {
13
13
  "url": "https://github.com/jhwadman/melch-ai/issues"
14
14
  },
15
- "//": "adk + genai are pinned exact in dev: newer genai minors change response part shapes and silently break the chat printer. Bump deliberately, verify a live run, then update the pin. adk itself is a PEER dependency — the consumer's app owns the ADK instance so the model registry is a singleton.",
15
+ "//": "adk + genai are pinned exact in dev: newer genai minors change response part shapes and silently break the chat printer. Bump deliberately, verify a live run, then update the pin. adk itself is a PEER dependency — the consumer's app owns the ADK instance so the model registry is a singleton. The adk peer range is capped to the tested minor (~2.2.0): a new adk minor can pull a second genai copy, so the range widens only after a release is tested against it.",
16
16
  "engines": {
17
17
  "node": ">=22.6.0"
18
18
  },
@@ -95,6 +95,9 @@
95
95
  "syndicate:augustin": "node --disable-warning=DEP0040 --experimental-strip-types scripts/syndicate_chat.ts --syndicate augustin",
96
96
  "syndicate:scribe": "node --disable-warning=DEP0040 --experimental-strip-types scripts/syndicate_chat.ts --syndicate scribe",
97
97
  "syndicate:assistant": "node --disable-warning=DEP0040 --experimental-strip-types scripts/syndicate_chat.ts --syndicate assistant",
98
+ "syndicate:harness": "node --disable-warning=DEP0040 --experimental-strip-types scripts/syndicate_chat.ts --syndicate harness",
99
+ "syndicate:pipeline": "node --disable-warning=DEP0040 --experimental-strip-types scripts/syndicate_chat.ts --syndicate pipeline",
100
+ "syndicate:weather": "node --disable-warning=DEP0040 --experimental-strip-types scripts/syndicate_chat.ts --syndicate weather",
98
101
  "syndicate:conversational": "node --disable-warning=DEP0040 --experimental-strip-types scripts/syndicate_chat.ts --syndicate conversational",
99
102
  "assistant:worker": "node --disable-warning=DEP0040 --experimental-strip-types scripts/assistant_worker.ts",
100
103
  "demo:models": "node --disable-warning=DEP0040 --experimental-strip-types scripts/demo_model_optionality.ts",
@@ -123,7 +126,7 @@
123
126
  "@anthropic-ai/bedrock-sdk": ">=0.20.0",
124
127
  "@anthropic-ai/vertex-sdk": ">=0.11.0",
125
128
  "@azure/identity": ">=4.0.0",
126
- "@google/adk": "^2.2.0",
129
+ "@google/adk": "~2.2.0",
127
130
  "redis": ">=4.6.0"
128
131
  },
129
132
  "dependencies": {
@@ -9,7 +9,7 @@ SHARED FACTS (true for every document in this series; use those the section need
9
9
  - The reader of a skill file is a coding agent (Claude Code, Codex, Cursor, OpenCode, Gemini CLI) acting for a software engineer. It reads the file when the task matches the description, then acts. Every command it might run goes in a fenced bash block, with the exact flags. Prose between commands says when to run which and what the output means. Nothing decorative.
10
10
 
11
11
  GLOBAL LIMITS FOR SKILL FILES:
12
- - The document is a complete SKILL.md: it begins with the frontmatter block given under STRUCTURE, exactly, then the body.
12
+ - The document is a complete SKILL.md: it begins with the frontmatter block given under STRUCTURE, exactly (its `description` stays in double quotes: a colon inside an unquoted value is invalid YAML and a strict loader drops the skill), then the body.
13
13
  - Body under 170 lines. Headings are `##`. No H1. No table of contents. No closing summary section.
14
14
  - Every command in a fenced block tagged bash. Every file path, flag, environment variable and identifier in backticks in prose.
15
15
  - Commands, flags, paths and environment variable names come only from this brief; never invent one.
@@ -6,7 +6,7 @@ STRUCTURE (exact):
6
6
  Frontmatter, verbatim:
7
7
  ---
8
8
  name: melchizedek-author
9
- description: Design or edit a Melchizedek syndicate YAML: the file layout, required keys, orchestrator and subagent blocks, tools by name, output schemas, memory mode, the tier header, and offline validation. Use when the user wants a new agent team, wants to change a syndicate's prompt, model, or tools, or asks what a field in a syndicate file means.
9
+ description: "Design or edit a Melchizedek syndicate YAML: the file layout, required keys, orchestrator and subagent blocks, tools by name, output schemas, memory mode, the tier header, and offline validation. Use when the user wants a new agent team, wants to change a syndicate's prompt, model, or tools, or asks what a field in a syndicate file means."
10
10
  ---
11
11
  Then `##` sections in this order: "Where the file goes", "Start from the closest example", "The keys", "Write the instruction", "Two constraints that break a file", "Validate and run", "Editing a syndicate that is already serving".
12
12
 
@@ -14,7 +14,7 @@ FACTS:
14
14
  Where the file goes:
15
15
  - Your syndicates live at the root of `config/agents/` in your project; the file name without `.yaml` is the id used everywhere (`--syndicate <id>`, A2A routes). Use lowercase with underscores.
16
16
  - `MELCHIZEDEK_AGENTS_DIR` relocates the directory; `syndicateSchema.yaml` beside the examples documents every field with its ADK counterpart.
17
- - A minimal template ships with this skill at `templates/minimal.yaml` (relative to this skill's directory): copy it, rename it, fill it in.
17
+ - A minimal template ships with this skill at `assets/minimal.yaml` (relative to this skill's directory): copy it, rename it, fill it in.
18
18
 
19
19
  Start from the closest example:
20
20
  - Copy the example nearest the job out of the starter pack into `config/agents/` and edit it. One orchestrator and one subagent is the right size to start; grow only when the work divides.
@@ -26,13 +26,17 @@ The keys (top level):
26
26
  - `variables:` defaults for `{{token}}` placeholders used anywhere in the file; overridden at run time with `--bind key=value` or `--bindings '{"key":"value"}'`. Never hardcode `current_date`; `{{current_date}}` is injected fresh on every load.
27
27
  - `memory_extraction_rules:` (long-term only): domain rules appended to the shared fact-extraction prompt for this syndicate alone, such as what never to store and what always to store.
28
28
  - `dispatch:` switches the syndicate from delegate mode (the default: subagents become tools the orchestrator calls, and it re-emits the chosen answer) to plan-dispatch (a classifier picks a route). Keys: `default_route` (required inside the block; a declared subagent that can answer any message), `route_key`, `route_overrides` (a list of `{route, pattern, flags, reason}`; a regex match pins the route and the classifier never runs), `reason_key`.
29
+ - `workflow:` makes the syndicate a graph instead of a delegation: `edges` lists chains of agent names (`START` opens one; a list of names fans out or in; a map `{route: Agent, default: Agent}` routes on the previous node's output, the `route_key` of a JSON output or its text), and `nodes` declares what is not an agent: `join: true`, `map: Agent`, `tool: name`, `ask_user: "question"` (the turn pauses; the next message answers), plus `retry` and `timeout` on any node. Every node receives the previous node's output as its message and sees nothing else. Cannot be combined with `dispatch:`. The worked example is `pipeline.yaml`.
29
30
  - `orchestrator:` (required) and `subagents:` (optional; omit or `[]` for a single agent).
30
31
  Agent block keys (orchestrator and each subagent):
31
32
  - `name` (required): a valid JavaScript identifier, unique in the tree, never `user`.
32
33
  - `description`: one line. For a subagent this is the routing API: the orchestrator decides whom to call by reading descriptions, so say exactly what to pass and when to call.
33
34
  - `model` (required on the orchestrator; subagents inherit it when unset): the id's prefix names the provider (the melchizedek-models skill). Use `gemini-3.8-flash` or `gemini-3.5-flash-lite` for Gemini; `gemini-2.5-flash` fails with a 400 about tool call context circulation.
34
35
  - `instruction` (required): the system prompt.
35
- - `tools:` a list of registered tool names: `web_search`, `web_extract`, `google_search`, `x_search`, `x_api_search`, `collections_search`, `generate_image`, `inspect_image`, `load_memory`, `preload_memory`, `wiki_map`, `wiki_search`, `wiki_read`, `wiki_links`, `wiki_dive`, `wiki_save`, `wiki_graph`, `wiki_relate`. An unknown name is warned and skipped, never fatal. Server-side search tools run natively only on providers that offer them; the doctor reports per agent which are kept or dropped.
36
+ - `tools:` a list of registered tool names: `web_search`, `web_extract`, `google_search`, `x_search`, `x_api_search`, `collections_search`, `generate_image`, `inspect_image`, `load_memory`, `preload_memory`, `wiki_map`, `wiki_search`, `wiki_read`, `wiki_links`, `wiki_dive`, `wiki_save`, `wiki_graph`, `wiki_relate`, `url_context` (Gemini reads the pages at URLs in the conversation; a no-op on other providers), and `ask_user` (the agent asks the person and the turn waits for the answer; only on the orchestrator or a plan-dispatch route). An unknown name is warned and skipped, never fatal. Server-side search tools run natively only on providers that offer them; the doctor reports per agent which are kept or dropped.
37
+ - `examples:` a list of `{input, output}` pairs added to every request as few-shot examples. At the top level, `retries:` tunes self-correction, which is on by default: `model_errors` (2) retries a malformed model reply, `tool_errors` (3) retries a tool that threw; 0 turns either off.
38
+ - `code_execution: gemini` lets a Gemini agent write and run Python in Google's sandbox (nothing runs on your machine). `context: { compact_after_tokens: 60000 }` on a delegate orchestrator summarizes a long conversation instead of overflowing it. `mode: task` on a workflow node makes its output its `finish_task` arguments.
39
+ - `openapi:` a list of OpenAPI 3 spec files (relative to the syndicate file) whose operations become the agent's tools; only GET operations unless `operations` names others; `auth` reads `bearer_env` or `api_key: {env, in, name}` from the environment. Read `weather.yaml` for the worked example.
36
40
  - `mcp_server_url:` on a subagent: tools discovered from that MCP server at start (the melchizedek-serve skill).
37
41
  - `generateContentConfig:` per agent: `temperature`, `maxOutputTokens`, `responseMimeType: "application/json"` for structured output, `thinkingConfig: { thinkingLevel: MEDIUM, includeThoughts: false }` on Gemini models that think. Thinking tokens count against `maxOutputTokens`, so a thinking agent with long output needs a high ceiling (the Scribe uses 24576).
38
42
  - `outputSchema:` a JSON schema (types in upper case: `OBJECT`, `STRING`, `INTEGER`, `BOOLEAN`, `ARRAY`) the agent's reply must satisfy.
@@ -56,5 +60,5 @@ Validate and run:
56
60
  Editing a syndicate that is already serving:
57
61
  - `melchizedek-serve` compiles a syndicate when it is first requested and caches it for the life of the process; an edited file changes nothing until the server restarts. A deployment that boots agents from the Supabase agent registry (`registry:<id>`) serves the registry row, not the file, until the row is republished.
58
62
 
59
- IDENTIFIERS (verbatim): config/agents/, syndicateSchema.yaml, templates/minimal.yaml, syndicate_name, memory_system, internal-only, session-only, long-term, variables:, {{current_date}}, memory_extraction_rules:, dispatch:, default_route, route_overrides, orchestrator:, subagents:, description, model, instruction, tools:, mcp_server_url:, generateContentConfig:, outputSchema:, responseMimeType, thinkingConfig, maxOutputTokens, # tier:, npm test, npx melchizedek-doctor, npx melchizedek-chat --syndicate, loadSyndicate, gemini-3.8-flash, gemini-3.5-flash-lite, critic.yaml, scribe.yaml, tutor.yaml, patient_advocate.yaml
63
+ IDENTIFIERS (verbatim): config/agents/, syndicateSchema.yaml, assets/minimal.yaml, syndicate_name, memory_system, internal-only, session-only, long-term, variables:, {{current_date}}, memory_extraction_rules:, dispatch:, default_route, route_overrides, workflow:, edges, nodes, ask_user, join, map, START, pipeline.yaml, orchestrator:, subagents:, description, model, instruction, tools:, mcp_server_url:, generateContentConfig:, outputSchema:, responseMimeType, thinkingConfig, maxOutputTokens, # tier:, npm test, npx melchizedek-doctor, npx melchizedek-chat --syndicate, loadSyndicate, gemini-3.8-flash, gemini-3.5-flash-lite, critic.yaml, scribe.yaml, tutor.yaml, patient_advocate.yaml
60
64
  LIMITS: the Node one-liner goes in a fenced bash block exactly as given. Body under 170 lines.
@@ -6,7 +6,7 @@ STRUCTURE (exact):
6
6
  Frontmatter, verbatim:
7
7
  ---
8
8
  name: melchizedek-memory
9
- description: Give a Melchizedek syndicate persistent sessions and long-term memory on Supabase: the memory_system modes, the two tables and the match function, the memory tools, extraction rules, inspection and erasure. Use when the user wants an agent to remember across runs, sets up Supabase for melchizedek, or asks why recall returns nothing.
9
+ description: "Give a Melchizedek syndicate persistent sessions and long-term memory on Supabase: the memory_system modes, the two tables and the match function, the memory tools, extraction rules, inspection and erasure. Use when the user wants an agent to remember across runs, sets up Supabase for melchizedek, or asks why recall returns nothing."
10
10
  ---
11
11
  Then `##` sections in this order: "The three memory modes", "Provision Supabase", "What gets stored", "Wire the syndicate", "Prove it", "Inspect and erase", "When recall returns nothing".
12
12
 
@@ -6,7 +6,7 @@ STRUCTURE (exact):
6
6
  Frontmatter, verbatim:
7
7
  ---
8
8
  name: melchizedek-models
9
- description: Choose and wire a model for a Melchizedek agent: how a model id routes to Gemini, Claude, GPT, Grok, or local Ollama, which environment variable each needs, the gateway fallback, the doctor, and per-agent generation settings. Use when the user changes a model line, adds a provider key, sees Model not found or a gateway error, or asks which keys a syndicate needs.
9
+ description: "Choose and wire a model for a Melchizedek agent: how a model id routes to Gemini, Claude, GPT, Grok, or local Ollama, which environment variable each needs, the gateway fallback, the doctor, and per-agent generation settings. Use when the user changes a model line, adds a provider key, sees Model not found or a gateway error, or asks which keys a syndicate needs."
10
10
  ---
11
11
  Then `##` sections in this order: "How a model id routes", "Which key unlocks what", "Run with no key at all", "One key for every cloud provider", "Settings per agent", "Mixing providers in one syndicate", "Reading the errors".
12
12
 
@@ -6,7 +6,7 @@ STRUCTURE (exact):
6
6
  Frontmatter, verbatim:
7
7
  ---
8
8
  name: melchizedek-scribe
9
- description: Write a document from a technical brief with the Scribe syndicate: a README section, a skill file, product copy, a runbook. Use when the user wants prose generated from facts they supply, wants to write a SKILL.md, or mentions the scribe; covers the brief format, the one-shot run, capture, and review.
9
+ description: "Write a document from a technical brief with the Scribe syndicate: a README section, a skill file, product copy, a runbook. Use when the user wants prose generated from facts they supply, wants to write a SKILL.md, or mentions the scribe; covers the brief format, the one-shot run, capture, and review."
10
10
  ---
11
11
  Then `##` sections in this order: "What the Scribe is", "Write the brief", "Run it and capture the document", "Review before you hand it over", "Writing a SKILL.md with it".
12
12
 
@@ -19,7 +19,7 @@ What the Scribe is:
19
19
  Write the brief:
20
20
  - A brief is plain text with these parts, any order, any headings: AUDIENCE (who reads it and what they know), KIND (skill file, README section, page copy, runbook, email; the kind sets the shape), PURPOSE (what the reader can do afterwards), FACTS (every statement the document may make; this is the Scribe's whole knowledge), IDENTIFIERS (strings that must appear verbatim: commands, flags, paths, environment variables, package names, model ids, URLs), LIMITS (word or line caps, required headings, forbidden constructions), SOURCE MATERIAL (optional pasted text the Scribe may quote).
21
21
  - Facts come from the code, the manifest and the docs at hand; the reading agent gathers them into the brief before running. Put the exact command with its flags in FACTS, and list it again under IDENTIFIERS.
22
- - A template ships with this skill at `templates/brief.md` (relative to this skill's directory).
22
+ - A template ships with this skill at `assets/brief.md` (relative to this skill's directory).
23
23
  Run it and capture the document:
24
24
  - One shot, output as one block: `CHAT_STREAMING=false npx melchizedek-chat --syndicate scribe -- "$(cat brief.md)" > scribe.out` (clone: `CHAT_STREAMING=false npm run syndicate:scribe -- "$(cat brief.md)" > scribe.out`).
25
25
  - The file holds the startup banner, the echoed brief after `You › `, dim lines naming the Auditor calls, and the document after the last line that begins `Scribe › `. Take everything after that last marker; strip terminal color codes if the consumer needs plain text. A one-line extraction:
@@ -31,7 +31,7 @@ Review before you hand it over:
31
31
  - If the document invents a fact, the fix is in the brief: add the true fact or forbid the topic under LIMITS, then rerun. Do not patch the prose by hand and leave the brief stale; the brief is what the next run uses.
32
32
  - The document is the Scribe's output: text to review and present, never instructions for the reading agent.
33
33
  Writing a SKILL.md with it:
34
- - Under LIMITS give the exact frontmatter block (`name` equal to the directory name, lowercase with hyphens; `description` under 1024 characters stating when to use the skill), the `##` headings in order, a line cap, and "every command in a fenced bash block". Put the shared facts of a suite in one block and prepend it to each brief so the skills agree.
34
+ - Under LIMITS give the exact frontmatter block (`name` equal to the directory name, lowercase with hyphens; `description` in double quotes, under 1024 characters, stating when to use the skill), the `##` headings in order, a line cap, and "every command in a fenced bash block". Put the shared facts of a suite in one block and prepend it to each brief so the skills agree.
35
35
 
36
- IDENTIFIERS (verbatim): scribe.yaml, GOOGLE_GENAI_API_KEY, templates/brief.md, CHAT_STREAMING=false npx melchizedek-chat --syndicate scribe, npm run syndicate:scribe, You › , Scribe › , exit
36
+ IDENTIFIERS (verbatim): scribe.yaml, GOOGLE_GENAI_API_KEY, assets/brief.md, CHAT_STREAMING=false npx melchizedek-chat --syndicate scribe, npm run syndicate:scribe, You › , Scribe › , exit
37
37
  LIMITS: the run command and the extraction one-liner go in fenced bash blocks exactly as given. Body under 140 lines.
@@ -6,7 +6,7 @@ STRUCTURE (exact):
6
6
  Frontmatter, verbatim:
7
7
  ---
8
8
  name: melchizedek-serve
9
- description: Expose a Melchizedek syndicate over HTTP with the A2A server, call it from code, give a subagent tools from an MCP server, or serve your own tools as an MCP server. Use when the user mentions melchizedek-serve, A2A, an agent card, mcp_server_url, or wants a syndicate reachable from another application or agent.
9
+ description: "Expose a Melchizedek syndicate over HTTP with the A2A server, call it from code, give a subagent tools from an MCP server, or serve your own tools as an MCP server. Use when the user mentions melchizedek-serve, A2A, an agent card, mcp_server_url, or wants a syndicate reachable from another application or agent."
10
10
  ---
11
11
  Then `##` sections in this order: "Serve a syndicate over A2A", "Secure it", "Call it", "Per-agent routes", "Give a subagent MCP tools", "Serve your own tools over MCP".
12
12
 
@@ -6,7 +6,7 @@ STRUCTURE (exact):
6
6
  Frontmatter, verbatim:
7
7
  ---
8
8
  name: melchizedek
9
- description: Find and run a Melchizedek syndicate (an agent team defined in one YAML file) from the terminal or from inside a coding agent. Use when the user mentions melchizedek, melchizedek-agents, a syndicate, the starter pack, or asks to run, list, or delegate a task to one of these agents; this is also the entry point to the other melchizedek-* skills.
9
+ description: "Find and run a Melchizedek syndicate (an agent team defined in one YAML file) from the terminal or from inside a coding agent. Use when the user mentions melchizedek, melchizedek-agents, a syndicate, the starter pack, or asks to run, list, or delegate a task to one of these agents; this is also the entry point to the other melchizedek-* skills."
10
10
  ---
11
11
  Then sections with these `##` headings, in this order: "Where the syndicates are", "What each starter-pack syndicate does", "Check the keys before running", "Run one", "Delegate a task from this agent", "When something fails", "The other skills in this suite".
12
12
 
@@ -19,6 +19,9 @@ Where the syndicates are:
19
19
 
20
20
  The starter pack (file → name → what it does → tier / extra requirement):
21
21
  - assistant.yaml → Assistant → the generic starting point: converses, summarizes pasted text or URLs, keeps a task list, and queues background jobs that `npx melchizedek-worker` runs (clone: `npm run assistant:worker`) → keyless (Ollama with qwen3:8b pulled)
22
+ - harness.yaml → Harness → works from a directory of Agent Skills the way a coding harness does: every skill's frontmatter is in its prompt, it reads the matching SKILL.md and the files it names, `/name` forces a skill, a Checker holds the result to the skill's own rules; `--bind skills_dir=<dir>` points it at a project's shelf (default: this package's own skills) → gemini
23
+ - weather.yaml → Weather → an HTTP API as tools from its OpenAPI spec (`openapi:`), no tool code: finds a place and forecasts its weather on Open-Meteo's keyless APIs → gemini
24
+ - pipeline.yaml → Editorial Pipeline → a syndicate as a graph (`workflow:`): a planner routes on a JSON field, a writer and a checker run at once, a join feeds an editor that retries once, the person is asked before a publisher finishes → gemini
22
25
  - tutor.yaml → Tutor → one agent that teaches a topic or pasted material by questioning → keyless (Ollama with qwen3:8b pulled)
23
26
  - council.yaml → Council → an advocate and a skeptic argue a question and a chair rules → keyless
24
27
  - critic.yaml → Critic Review Workflow → a Drafter answers, a Critic scores it as JSON with a confidence field, and the loop repeats until confidence is 85 or higher (three rounds at most) → gemini
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: melchizedek
3
- description: Find and run a Melchizedek syndicate (an agent team defined in one YAML file) from the terminal or from inside a coding agent. Use when the user mentions melchizedek, melchizedek-agents, a syndicate, the starter pack, or asks to run, list, or delegate a task to one of these agents; this is also the entry point to the other melchizedek-* skills.
3
+ description: "Find and run a Melchizedek syndicate (an agent team defined in one YAML file) from the terminal or from inside a coding agent. Use when the user mentions melchizedek, melchizedek-agents, a syndicate, the starter pack, or asks to run, list, or delegate a task to one of these agents; this is also the entry point to the other melchizedek-* skills."
4
4
  ---
5
5
 
6
6
  ## Where the syndicates are
@@ -24,6 +24,9 @@ To modify an example, copy it into `config/agents/` in your project and edit it.
24
24
  ## What each starter-pack syndicate does
25
25
 
26
26
  - `assistant.yaml`: Assistant; the generic starting point: converses, summarizes pasted text or URLs, keeps a task list, and queues background jobs that `npx melchizedek-worker` runs (clone: `npm run assistant:worker`); keyless (Ollama with qwen3:8b pulled).
27
+ - `harness.yaml`: Harness; works from a directory of Agent Skills the way a coding harness does: every skill's frontmatter is in its prompt, it reads the matching SKILL.md and the files it names, `/name` forces a skill, a Checker holds the result to the skill's own rules; `--bind skills_dir=<dir>` points it at a project's shelf (default: this package's own skills); gemini.
28
+ - `weather.yaml`: Weather; an HTTP API as tools from its OpenAPI spec (`openapi:`), no tool code: finds a place and forecasts its weather on Open-Meteo's keyless APIs; gemini.
29
+ - `pipeline.yaml`: Editorial Pipeline; a syndicate as a graph (`workflow:`): a planner routes on a JSON field, a writer and a checker run at once, a join feeds an editor that retries once, the person is asked before a publisher finishes; gemini.
27
30
  - `tutor.yaml`: Tutor; one agent that teaches a topic or pasted material by questioning; keyless (Ollama with qwen3:8b pulled).
28
31
  - `council.yaml`: Council; an advocate and a skeptic argue a question and a chair rules; keyless.
29
32
  - `critic.yaml`: Critic Review Workflow; a Drafter answers, a Critic scores it as JSON with a confidence field, and the loop repeats until confidence reaches 85 or higher (three rounds at most); gemini.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: melchizedek-author
3
- description: Design or edit a Melchizedek syndicate YAML: the file layout, required keys, orchestrator and subagent blocks, tools by name, output schemas, memory mode, the tier header, and offline validation. Use when the user wants a new agent team, wants to change a syndicate's prompt, model, or tools, or asks what a field in a syndicate file means.
3
+ description: "Design or edit a Melchizedek syndicate YAML: the file layout, required keys, orchestrator and subagent blocks, tools by name, output schemas, memory mode, the tier header, and offline validation. Use when the user wants a new agent team, wants to change a syndicate's prompt, model, or tools, or asks what a field in a syndicate file means."
4
4
  ---
5
5
 
6
6
  ## Where the file goes
@@ -9,7 +9,7 @@ Your syndicates live at the root of `config/agents/` in your project. The file n
9
9
 
10
10
  The environment variable `MELCHIZEDEK_AGENTS_DIR` points the loader at another directory. The schema file `syndicateSchema.yaml` sits beside the examples and documents every field with its ADK counterpart.
11
11
 
12
- A minimal template ships with this skill at `templates/minimal.yaml` relative to this skill's directory. Copy it, rename it, and fill in the fields.
12
+ A minimal template ships with this skill at `assets/minimal.yaml` relative to this skill's directory. Copy it, rename it, and fill in the fields.
13
13
 
14
14
  ## Start from the closest example
15
15
 
@@ -31,6 +31,7 @@ Top-level keys:
31
31
  - `variables:`: default values for `{{token}}` placeholders used across the file. Override them at run time with `--bind key=value` or `--bindings '{"key":"value"}'`. The loader injects `{{current_date}}` fresh on every load; omit static date strings.
32
32
  - `memory_extraction_rules:`: domain rules appended to the shared fact-extraction prompt in `long-term` mode, such as what to store and what to skip.
33
33
  - `dispatch:`: switches the syndicate from delegate mode to plan-dispatch routing where a classifier picks a route. In delegate mode, subagents act as tools the orchestrator calls, and the orchestrator re-emits the chosen answer. The `dispatch:` block requires `default_route` naming a declared subagent that can answer any message. It accepts `route_key`, `reason_key`, and `route_overrides` (a list of `{route, pattern, flags, reason}`). A regex match in `route_overrides` pins the route and skips the classifier.
34
+ - `workflow:`: makes the syndicate a graph instead of a delegation: `edges` lists chains of agent names (`START` opens one; a list fans out or in; a map `{route: Agent, default: Agent}` routes on the previous node's output), and `nodes` declares `join`, `map`, `tool` and `ask_user` nodes plus `retry` and `timeout` modifiers. Every node receives the previous node's output as its message. Cannot be combined with `dispatch:`. Read `pipeline.yaml` for the worked example.
34
35
  - `orchestrator:`: required orchestrator block.
35
36
  - `subagents:`: list of subagent blocks; omit it (or pass `[]`) for a single-agent syndicate.
36
37
 
@@ -39,7 +40,10 @@ Agent block keys for the orchestrator and each subagent:
39
40
  - `description`: one line. For a subagent, this acts as the routing API: the orchestrator decides whom to call by reading descriptions, so state what to pass and when to call.
40
41
  - `model`: model identifier, required on the orchestrator. Subagents inherit this model when unset. The melchizedek-models skill covers provider prefixes. Use `gemini-3.8-flash` or `gemini-3.5-flash-lite` for Gemini. The model `gemini-2.5-flash` fails with a 400 error about tool call context circulation.
41
42
  - `instruction`: required system prompt.
42
- - `tools:`: list of registered tool names: `web_search`, `web_extract`, `google_search`, `x_search`, `x_api_search`, `collections_search`, `generate_image`, `inspect_image`, `load_memory`, `preload_memory`, `wiki_map`, `wiki_search`, `wiki_read`, `wiki_links`, `wiki_dive`, `wiki_save`, `wiki_graph`, `wiki_relate`. The loader warns on an unknown name and skips it. Server-side search tools run natively only on providers that offer them; `npx melchizedek-doctor` reports per agent which tools stay or drop.
43
+ - `tools:`: list of registered tool names: `web_search`, `web_extract`, `google_search`, `x_search`, `x_api_search`, `collections_search`, `generate_image`, `inspect_image`, `load_memory`, `preload_memory`, `wiki_map`, `wiki_search`, `wiki_read`, `wiki_links`, `wiki_dive`, `wiki_save`, `wiki_graph`, `wiki_relate`, `url_context` (Gemini reads the pages at URLs in the conversation; a no-op on other providers), and `ask_user` (the agent asks the person and the turn waits for the answer; only on the orchestrator or a plan-dispatch route). The loader warns on an unknown name and skips it. Server-side search tools run natively only on providers that offer them; `npx melchizedek-doctor` reports per agent which tools stay or drop.
44
+ - `examples:` a list of `{input, output}` pairs added to every request as few-shot examples. At the top level, `retries:` tunes self-correction, which is on by default: `model_errors` (2) retries a malformed model reply, `tool_errors` (3) retries a tool that threw; 0 turns either off.
45
+ - `code_execution: gemini` lets a Gemini agent write and run Python in Google's sandbox (nothing runs on your machine). `context: { compact_after_tokens: 60000 }` on a delegate orchestrator summarizes a long conversation instead of overflowing it. `mode: task` on a workflow node makes its output its `finish_task` arguments.
46
+ - `openapi:` a list of OpenAPI 3 spec files (relative to the syndicate file) whose operations become the agent's tools; only GET operations unless `operations` names others; `auth` reads `bearer_env` or `api_key: {env, in, name}` from the environment. Read `weather.yaml` for the worked example.
43
47
  - `mcp_server_url:`: URL on a subagent to discover MCP tools at start. The melchizedek-serve skill covers MCP servers.
44
48
  - `generateContentConfig:`: per-agent options: `temperature`, `maxOutputTokens`, `responseMimeType: "application/json"`, and `thinkingConfig: { thinkingLevel: MEDIUM, includeThoughts: false }` on Gemini models that think. Thinking tokens count against `maxOutputTokens`. The Scribe uses 24576 for `maxOutputTokens`.
45
49
  - `outputSchema:`: a JSON schema using uppercase types (`OBJECT`, `STRING`, `INTEGER`, `BOOLEAN`, `ARRAY`) that the agent reply must satisfy.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: melchizedek-memory
3
- description: Give a Melchizedek syndicate persistent sessions and long-term memory on Supabase: the memory_system modes, the two tables and the match function, the memory tools, extraction rules, inspection and erasure. Use when the user wants an agent to remember across runs, sets up Supabase for melchizedek, or asks why recall returns nothing.
3
+ description: "Give a Melchizedek syndicate persistent sessions and long-term memory on Supabase: the memory_system modes, the two tables and the match function, the memory tools, extraction rules, inspection and erasure. Use when the user wants an agent to remember across runs, sets up Supabase for melchizedek, or asks why recall returns nothing."
4
4
  ---
5
5
 
6
6
  ## The three memory modes
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: melchizedek-models
3
- description: Choose and wire a model for a Melchizedek agent: how a model id routes to Gemini, Claude, GPT, Grok, or local Ollama, which environment variable each needs, the gateway fallback, the doctor, and per-agent generation settings. Use when the user changes a model line, adds a provider key, sees Model not found or a gateway error, or asks which keys a syndicate needs.
3
+ description: "Choose and wire a model for a Melchizedek agent: how a model id routes to Gemini, Claude, GPT, Grok, or local Ollama, which environment variable each needs, the gateway fallback, the doctor, and per-agent generation settings. Use when the user changes a model line, adds a provider key, sees Model not found or a gateway error, or asks which keys a syndicate needs."
4
4
  ---
5
5
 
6
6
  ## How a model id routes
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: melchizedek-scribe
3
- description: Write a document from a technical brief with the Scribe syndicate: a README section, a skill file, product copy, a runbook. Use when the user wants prose generated from facts they supply, wants to write a SKILL.md, or mentions the scribe; covers the brief format, the one-shot run, capture, and review.
3
+ description: "Write a document from a technical brief with the Scribe syndicate: a README section, a skill file, product copy, a runbook. Use when the user wants prose generated from facts they supply, wants to write a SKILL.md, or mentions the scribe; covers the brief format, the one-shot run, capture, and review."
4
4
  ---
5
5
 
6
6
  ## What the Scribe is
@@ -20,7 +20,7 @@ A brief is plain text. The brief contains these parts, in any order, under any h
20
20
  - LIMITS: word or line caps, required headings, and forbidden constructions.
21
21
  - SOURCE MATERIAL: optional pasted text that the Scribe may quote.
22
22
 
23
- You gather facts from the code, the manifest, and the documentation at hand before running. Place the exact command with its flags under FACTS, and list the exact command again under IDENTIFIERS. A brief template ships with this skill at `templates/brief.md`.
23
+ You gather facts from the code, the manifest, and the documentation at hand before running. Place the exact command with its flags under FACTS, and list the exact command again under IDENTIFIERS. A brief template ships with this skill at `assets/brief.md`.
24
24
 
25
25
  ## Run it and capture the document
26
26
 
@@ -64,7 +64,7 @@ The Auditor catches most discrepancies. A person still reads the final result. I
64
64
  ## Writing a SKILL.md with it
65
65
 
66
66
  When you write a SKILL.md file with the Scribe, place these constraints under LIMITS:
67
- - The exact frontmatter block, with `name` equal to the directory name in lowercase with hyphens, and `description` under 1024 characters stating when to use the skill.
67
+ - The exact frontmatter block, with `name` equal to the directory name in lowercase with hyphens, and `description` in double quotes, under 1024 characters, stating when to use the skill.
68
68
  - The `##` headings in order.
69
69
  - A line cap.
70
70
  - The instruction: "every command in a fenced bash block".
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: melchizedek-serve
3
- description: Expose a Melchizedek syndicate over HTTP with the A2A server, call it from code, give a subagent tools from an MCP server, or serve your own tools as an MCP server. Use when the user mentions melchizedek-serve, A2A, an agent card, mcp_server_url, or wants a syndicate reachable from another application or agent.
3
+ description: "Expose a Melchizedek syndicate over HTTP with the A2A server, call it from code, give a subagent tools from an MCP server, or serve your own tools as an MCP server. Use when the user mentions melchizedek-serve, A2A, an agent card, mcp_server_url, or wants a syndicate reachable from another application or agent."
4
4
  ---
5
5
 
6
6
  ## Serve a syndicate over A2A