agentopology 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +450 -0
  3. package/dist/analyzer/__tests__/analyzer.test.d.ts +2 -0
  4. package/dist/analyzer/__tests__/analyzer.test.d.ts.map +1 -0
  5. package/dist/analyzer/__tests__/analyzer.test.js +258 -0
  6. package/dist/analyzer/__tests__/analyzer.test.js.map +1 -0
  7. package/dist/analyzer/index.d.ts +44 -0
  8. package/dist/analyzer/index.d.ts.map +1 -0
  9. package/dist/analyzer/index.js +308 -0
  10. package/dist/analyzer/index.js.map +1 -0
  11. package/dist/bindings/__tests__/bindings.test.d.ts +2 -0
  12. package/dist/bindings/__tests__/bindings.test.d.ts.map +1 -0
  13. package/dist/bindings/__tests__/bindings.test.js +2089 -0
  14. package/dist/bindings/__tests__/bindings.test.js.map +1 -0
  15. package/dist/bindings/claude-code.d.ts +12 -0
  16. package/dist/bindings/claude-code.d.ts.map +1 -0
  17. package/dist/bindings/claude-code.js +2063 -0
  18. package/dist/bindings/claude-code.js.map +1 -0
  19. package/dist/bindings/codex.d.ts +18 -0
  20. package/dist/bindings/codex.d.ts.map +1 -0
  21. package/dist/bindings/codex.js +1633 -0
  22. package/dist/bindings/codex.js.map +1 -0
  23. package/dist/bindings/copilot-cli.d.ts +20 -0
  24. package/dist/bindings/copilot-cli.d.ts.map +1 -0
  25. package/dist/bindings/copilot-cli.js +1515 -0
  26. package/dist/bindings/copilot-cli.js.map +1 -0
  27. package/dist/bindings/cursor.d.ts +17 -0
  28. package/dist/bindings/cursor.d.ts.map +1 -0
  29. package/dist/bindings/cursor.js +1715 -0
  30. package/dist/bindings/cursor.js.map +1 -0
  31. package/dist/bindings/gemini-cli.d.ts +18 -0
  32. package/dist/bindings/gemini-cli.d.ts.map +1 -0
  33. package/dist/bindings/gemini-cli.js +1327 -0
  34. package/dist/bindings/gemini-cli.js.map +1 -0
  35. package/dist/bindings/index.d.ts +20 -0
  36. package/dist/bindings/index.d.ts.map +1 -0
  37. package/dist/bindings/index.js +33 -0
  38. package/dist/bindings/index.js.map +1 -0
  39. package/dist/bindings/kiro.d.ts +17 -0
  40. package/dist/bindings/kiro.d.ts.map +1 -0
  41. package/dist/bindings/kiro.js +1624 -0
  42. package/dist/bindings/kiro.js.map +1 -0
  43. package/dist/bindings/openclaw.d.ts +18 -0
  44. package/dist/bindings/openclaw.d.ts.map +1 -0
  45. package/dist/bindings/openclaw.js +1578 -0
  46. package/dist/bindings/openclaw.js.map +1 -0
  47. package/dist/bindings/types.d.ts +33 -0
  48. package/dist/bindings/types.d.ts.map +1 -0
  49. package/dist/bindings/types.js +23 -0
  50. package/dist/bindings/types.js.map +1 -0
  51. package/dist/cli/index.d.ts +19 -0
  52. package/dist/cli/index.d.ts.map +1 -0
  53. package/dist/cli/index.js +679 -0
  54. package/dist/cli/index.js.map +1 -0
  55. package/dist/docs/__tests__/docs.test.d.ts +2 -0
  56. package/dist/docs/__tests__/docs.test.d.ts.map +1 -0
  57. package/dist/docs/__tests__/docs.test.js +438 -0
  58. package/dist/docs/__tests__/docs.test.js.map +1 -0
  59. package/dist/docs/content.d.ts +16 -0
  60. package/dist/docs/content.d.ts.map +1 -0
  61. package/dist/docs/content.js +3273 -0
  62. package/dist/docs/content.js.map +1 -0
  63. package/dist/docs/index.d.ts +17 -0
  64. package/dist/docs/index.d.ts.map +1 -0
  65. package/dist/docs/index.js +117 -0
  66. package/dist/docs/index.js.map +1 -0
  67. package/dist/exporters/__tests__/exporters.test.d.ts +2 -0
  68. package/dist/exporters/__tests__/exporters.test.d.ts.map +1 -0
  69. package/dist/exporters/__tests__/exporters.test.js +731 -0
  70. package/dist/exporters/__tests__/exporters.test.js.map +1 -0
  71. package/dist/exporters/index.d.ts +13 -0
  72. package/dist/exporters/index.d.ts.map +1 -0
  73. package/dist/exporters/index.js +18 -0
  74. package/dist/exporters/index.js.map +1 -0
  75. package/dist/exporters/json.d.ts +8 -0
  76. package/dist/exporters/json.d.ts.map +1 -0
  77. package/dist/exporters/json.js +25 -0
  78. package/dist/exporters/json.js.map +1 -0
  79. package/dist/exporters/markdown.d.ts +9 -0
  80. package/dist/exporters/markdown.d.ts.map +1 -0
  81. package/dist/exporters/markdown.js +686 -0
  82. package/dist/exporters/markdown.js.map +1 -0
  83. package/dist/exporters/mermaid.d.ts +11 -0
  84. package/dist/exporters/mermaid.d.ts.map +1 -0
  85. package/dist/exporters/mermaid.js +161 -0
  86. package/dist/exporters/mermaid.js.map +1 -0
  87. package/dist/exporters/types.d.ts +22 -0
  88. package/dist/exporters/types.d.ts.map +1 -0
  89. package/dist/exporters/types.js +10 -0
  90. package/dist/exporters/types.js.map +1 -0
  91. package/dist/import/__tests__/import.test.d.ts +2 -0
  92. package/dist/import/__tests__/import.test.d.ts.map +1 -0
  93. package/dist/import/__tests__/import.test.js +781 -0
  94. package/dist/import/__tests__/import.test.js.map +1 -0
  95. package/dist/import/claude-code.d.ts +38 -0
  96. package/dist/import/claude-code.d.ts.map +1 -0
  97. package/dist/import/claude-code.js +897 -0
  98. package/dist/import/claude-code.js.map +1 -0
  99. package/dist/import/index.d.ts +18 -0
  100. package/dist/import/index.d.ts.map +1 -0
  101. package/dist/import/index.js +28 -0
  102. package/dist/import/index.js.map +1 -0
  103. package/dist/import/serializer.d.ts +11 -0
  104. package/dist/import/serializer.d.ts.map +1 -0
  105. package/dist/import/serializer.js +960 -0
  106. package/dist/import/serializer.js.map +1 -0
  107. package/dist/index.d.ts +26 -0
  108. package/dist/index.d.ts.map +1 -0
  109. package/dist/index.js +21 -0
  110. package/dist/index.js.map +1 -0
  111. package/dist/parser/__tests__/parser.test.d.ts +2 -0
  112. package/dist/parser/__tests__/parser.test.d.ts.map +1 -0
  113. package/dist/parser/__tests__/parser.test.js +6514 -0
  114. package/dist/parser/__tests__/parser.test.js.map +1 -0
  115. package/dist/parser/ast.d.ts +708 -0
  116. package/dist/parser/ast.d.ts.map +1 -0
  117. package/dist/parser/ast.js +12 -0
  118. package/dist/parser/ast.js.map +1 -0
  119. package/dist/parser/index.d.ts +253 -0
  120. package/dist/parser/index.d.ts.map +1 -0
  121. package/dist/parser/index.js +1985 -0
  122. package/dist/parser/index.js.map +1 -0
  123. package/dist/parser/lexer.d.ts +100 -0
  124. package/dist/parser/lexer.d.ts.map +1 -0
  125. package/dist/parser/lexer.js +304 -0
  126. package/dist/parser/lexer.js.map +1 -0
  127. package/dist/parser/validator.d.ts +42 -0
  128. package/dist/parser/validator.d.ts.map +1 -0
  129. package/dist/parser/validator.js +2568 -0
  130. package/dist/parser/validator.js.map +1 -0
  131. package/dist/scaffold/__tests__/scaffold.test.d.ts +7 -0
  132. package/dist/scaffold/__tests__/scaffold.test.d.ts.map +1 -0
  133. package/dist/scaffold/__tests__/scaffold.test.js +295 -0
  134. package/dist/scaffold/__tests__/scaffold.test.js.map +1 -0
  135. package/dist/scaffold/incremental.d.ts +43 -0
  136. package/dist/scaffold/incremental.d.ts.map +1 -0
  137. package/dist/scaffold/incremental.js +185 -0
  138. package/dist/scaffold/incremental.js.map +1 -0
  139. package/dist/scaffold/index.d.ts +13 -0
  140. package/dist/scaffold/index.d.ts.map +1 -0
  141. package/dist/scaffold/index.js +13 -0
  142. package/dist/scaffold/index.js.map +1 -0
  143. package/dist/scaffold/manifest.d.ts +30 -0
  144. package/dist/scaffold/manifest.d.ts.map +1 -0
  145. package/dist/scaffold/manifest.js +71 -0
  146. package/dist/scaffold/manifest.js.map +1 -0
  147. package/dist/scaffold/merge.d.ts +52 -0
  148. package/dist/scaffold/merge.d.ts.map +1 -0
  149. package/dist/scaffold/merge.js +134 -0
  150. package/dist/scaffold/merge.js.map +1 -0
  151. package/dist/scaffold/types.d.ts +51 -0
  152. package/dist/scaffold/types.d.ts.map +1 -0
  153. package/dist/scaffold/types.js +10 -0
  154. package/dist/scaffold/types.js.map +1 -0
  155. package/dist/sync/index.d.ts +34 -0
  156. package/dist/sync/index.d.ts.map +1 -0
  157. package/dist/sync/index.js +392 -0
  158. package/dist/sync/index.js.map +1 -0
  159. package/dist/visualizer/index.d.ts +17 -0
  160. package/dist/visualizer/index.d.ts.map +1 -0
  161. package/dist/visualizer/index.js +1976 -0
  162. package/dist/visualizer/index.js.map +1 -0
  163. package/examples/code-review.at +167 -0
  164. package/examples/data-processing.at +296 -0
  165. package/examples/openclaw-assistant.at +142 -0
  166. package/examples/scheduled-monitor.at +193 -0
  167. package/examples/simple-pipeline.at +163 -0
  168. package/package.json +77 -0
  169. package/skill/SKILL.md +403 -0
  170. package/skill/scripts/emit.ts +853 -0
  171. package/skill/scripts/visualize.ts +89 -0
  172. package/spec/grammar.md +1466 -0
  173. package/spec/reserved-keywords.md +147 -0
  174. package/spec/validation.md +535 -0
@@ -0,0 +1,147 @@
1
+ # AgenTopology Reserved Keywords
2
+
3
+ Created by Nadav Naveh
4
+
5
+ Reserved keywords are names that **cannot** be used as agent, action, or gate identifiers.
6
+
7
+ ---
8
+
9
+ ## Block Keywords
10
+
11
+ These introduce grammar constructs:
12
+
13
+ ```
14
+ topology, library, import, from, use,
15
+ agent, action, orchestrator, meta, roles, memory, flow, gates, gate,
16
+ depth, batch, environments, triggers, command, event, level,
17
+ hooks, hook, settings, mcp-servers, metering, tools, tool, scale, skill,
18
+ context, env, extensions, providers, schedule, job, interfaces,
19
+ defaults, schemas, schema, observability, fragment, interface, params
20
+ ```
21
+
22
+ ---
23
+
24
+ ## Field Keywords
25
+
26
+ These are used as field names or enum values:
27
+
28
+ ```
29
+ model, tools, disallowed-tools, reads, writes, outputs, skip, retry, isolation,
30
+ phase, kind, role, version, description, permissions, prompt,
31
+ generates, handles, argument, factors, behavior, invocation, omit,
32
+ when, max, parallel, per, manual, advisory, blocking,
33
+ min, batch-size, batch-count, doc-count, token-volume, source-count, fixed, config,
34
+ track, tokens-in, tokens-out, cost, wall-time, agent-count, format, pricing,
35
+ anthropic-current, custom, none, json, jsonl, csv,
36
+ pass, fail, plan-gap, bounce-back, halt,
37
+ inherit,
38
+ autonomous, supervised, interactive, unrestricted,
39
+ worktree, append-only, background, skills,
40
+ user, project, local, on, matcher, timeout,
41
+ AgentStart, AgentStop, ToolUse, Error, SessionStart, SessionEnd,
42
+ PreToolUse, PostToolUse, PostToolUseFailure,
43
+ SubagentStart, SubagentStop, Stop, UserPromptSubmit,
44
+ InstructionsLoaded, PermissionRequest, Notification,
45
+ TeammateIdle, TaskCompleted, ConfigChange,
46
+ PreCompact, WorktreeCreate, WorktreeRemove,
47
+ command, prompt,
48
+ allow, deny, ask, http, stdio, sse, args, env, url, script, lang, bash, python, node,
49
+ on-fail, after, before, run, checks, load-when,
50
+ path, mode, files, routing, protocol, structure, blueprints,
51
+ domains, references, external-docs, metrics, workspace, conflicts,
52
+ detect, resolve, sequential-rebase, source, commands,
53
+ external, git, decision, inline, report, not, ticket, true, false,
54
+ max-turns, description, disable-model-invocation, user-invocable, allowed-tools,
55
+ domain, fork, api-key, base-url, default,
56
+ cron, every, enabled, webhook, channel, auth, port,
57
+ sandbox, docker, network-only, fallback-chain,
58
+ pipeline, supervisor, blackboard, orchestrator-worker, debate,
59
+ market-routing, consensus, fan-out, event-driven, human-gate
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Wave 1 Keywords (Error Handling, Model Config, Secrets)
65
+
66
+ ```
67
+ backoff, interval, max-interval, jitter,
68
+ non-retryable, exponential, linear,
69
+ temperature, max-tokens, top-p, top-k, stop, seed,
70
+ thinking, thinking-budget, off, low, medium, high,
71
+ sensitive,
72
+ log-level, debug, info, warn, error,
73
+ output-format, json-schema, text
74
+ ```
75
+
76
+ ---
77
+
78
+ ## Wave 2 Keywords (Flow Enhancements)
79
+
80
+ ```
81
+ join, all, any, all-done, none-failed,
82
+ tolerance, race, wait, weight,
83
+ error-handler
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Wave 3 Keywords (Infrastructure)
89
+
90
+ ```
91
+ input-schema, output-schema,
92
+ array, of, optional,
93
+ exporter, endpoint, service,
94
+ sample-rate, capture, prompts, completions, tool-args,
95
+ tool-results, spans, agents,
96
+ otlp, langsmith, datadog, stdout,
97
+ secret, vault, op, awssm, ssm, gcpsm, azurekv
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Wave 4 Keywords (Composition)
103
+
104
+ ```
105
+ as, with, include,
106
+ entry, exit, sha256
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Wave 5 Keywords (Advanced Patterns)
112
+
113
+ ```
114
+ circuit-breaker, threshold, window, cooldown,
115
+ compensates, human, checkpoint, durable
116
+ ```
117
+
118
+ ---
119
+
120
+ ## Wave 7 Keywords (Group Chat, Reflection, Rate Limiting)
121
+
122
+ ```
123
+ group, members, speaker-selection, max-rounds, termination,
124
+ round-robin, random, reflection, rate-limit
125
+ ```
126
+
127
+ ---
128
+
129
+ ## Not Reserved
130
+
131
+ These are free-form values and can be used as names:
132
+
133
+ ```
134
+ branch, render, supabase, target-branch
135
+ ```
136
+
137
+ Environment block field names, custom role names, and user-defined enum values are not reserved.
138
+
139
+ ---
140
+
141
+ ## Roadmap Reserved
142
+
143
+ Reserved for future use, not yet in grammar:
144
+
145
+ ```
146
+ event
147
+ ```
@@ -0,0 +1,535 @@
1
+ # AgenTopology Validation Rules
2
+
3
+ Created by Nadav Naveh
4
+
5
+ These 29 rules are enforced by the `.at` compiler at parse time. A topology that violates any rule is rejected before scaffold generation.
6
+
7
+ ---
8
+
9
+ ## Rule 1: Unique Names
10
+
11
+ All agent, action, and gate names must be globally unique within a topology. You cannot have an agent and an action with the same name.
12
+
13
+ ```agenttopology
14
+ # INVALID -- duplicate name "intake"
15
+ agent intake { ... }
16
+ action intake { ... }
17
+ ```
18
+
19
+ ---
20
+
21
+ ## Rule 2: No Keyword Names
22
+
23
+ No agent, action, or gate name may match a reserved keyword. See `reserved-keywords.md` for the full list.
24
+
25
+ ```agenttopology
26
+ # INVALID -- "flow" is a reserved keyword
27
+ agent flow { ... }
28
+ ```
29
+
30
+ ---
31
+
32
+ ## Rule 3: Flow Resolves
33
+
34
+ Every node name used in the `flow` block must correspond to a declared `agent`, `action`, or `gate`. No dangling references.
35
+
36
+ ```agenttopology
37
+ # INVALID -- "analyzer" is not declared anywhere
38
+ flow {
39
+ intake -> analyzer
40
+ }
41
+ ```
42
+
43
+ ---
44
+
45
+ ## Rule 4: No Orphans
46
+
47
+ Every declared agent must appear in the `flow` block or have `invocation: manual`. An agent that exists but is unreachable from the flow graph is an error.
48
+
49
+ ```agenttopology
50
+ # INVALID -- "helper" is declared but never used in flow and not manual
51
+ agent helper {
52
+ model: sonnet
53
+ }
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Rule 5: Outputs Exist
59
+
60
+ Every condition in a `[when x.y == z]` edge attribute must reference a declared `outputs` field on the named agent or orchestrator.
61
+
62
+ ```agenttopology
63
+ # INVALID -- "reviewer" has no output named "score"
64
+ reviewer -> builder [when reviewer.score == high]
65
+ ```
66
+
67
+ ---
68
+
69
+ ## Rule 6: Bounded Loops
70
+
71
+ Every back-edge (a flow edge that goes "backward" to an earlier node in the graph) must have `max N`. Unbounded loops are not allowed.
72
+
73
+ ```agenttopology
74
+ # INVALID -- back-edge without max
75
+ reviewer -> writer [when reviewer.verdict == revise]
76
+
77
+ # VALID
78
+ reviewer -> writer [when reviewer.verdict == revise, max 2]
79
+ ```
80
+
81
+ ---
82
+
83
+ ## Rule 7: Model Required
84
+
85
+ Every agent must have a `model` field. There is no default model.
86
+
87
+ ```agenttopology
88
+ # INVALID -- no model specified
89
+ agent writer {
90
+ tools: [Read, Write]
91
+ }
92
+ ```
93
+
94
+ ---
95
+
96
+ ## Rule 8: Imports Resolve
97
+
98
+ Every `import` statement must point to an existing `.at` file that contains the named agent definition.
99
+
100
+ ```agenttopology
101
+ # INVALID -- file does not exist
102
+ import reviewer from ./nonexistent.at
103
+ ```
104
+
105
+ ---
106
+
107
+ ## Rule 9: Actions Handled
108
+
109
+ Every action that appears in the `flow` block must also appear in `orchestrator.handles`. The orchestrator must know about every action it needs to run.
110
+
111
+ ```agenttopology
112
+ # INVALID -- "intake" is in flow but not in handles
113
+ orchestrator {
114
+ model: opus
115
+ handles: [classify]
116
+ }
117
+
118
+ flow {
119
+ intake -> classify
120
+ }
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Rule 10: Prompts Exist
126
+
127
+ Every `prompt:` path must resolve to an existing file on the filesystem. This is a filesystem validation performed after parsing.
128
+
129
+ ```agenttopology
130
+ # INVALID -- file does not exist
131
+ agent writer {
132
+ model: sonnet
133
+ prompt: "prompts/nonexistent.md"
134
+ }
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Rule 11: Reads/Writes Consistent
140
+
141
+ If agent A writes to a path and agent B reads from that path, there must be a flow path from A to B. This ensures data dependencies match the execution order.
142
+
143
+ ```agenttopology
144
+ # INVALID -- writer produces "output.md" but reader runs before writer
145
+ agent reader {
146
+ phase: 1
147
+ reads: ["output.md"]
148
+ }
149
+
150
+ agent writer {
151
+ phase: 2
152
+ writes: ["output.md"]
153
+ }
154
+
155
+ flow {
156
+ reader -> writer # reader runs first but depends on writer's output
157
+ }
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Rule 12: Edge Attribute Order
163
+
164
+ Edge attributes must appear in the order: `when`, then `max`, then `per`. Any other order is a parser error.
165
+
166
+ ```agenttopology
167
+ # INVALID -- max before when
168
+ qa -> builder [max 2, when qa.verdict == revise]
169
+
170
+ # VALID
171
+ qa -> builder [when qa.verdict == revise, max 2]
172
+ ```
173
+
174
+ ---
175
+
176
+ ## Rule 13: Gate Placement
177
+
178
+ Every gate's `after` field must reference a declared agent or action. If `before` is specified, it must also reference a declared agent or action.
179
+
180
+ ```agenttopology
181
+ # INVALID -- "nonexistent" is not a declared node
182
+ gates {
183
+ gate check {
184
+ after: nonexistent
185
+ run: "scripts/check.sh"
186
+ }
187
+ }
188
+ ```
189
+
190
+ ---
191
+
192
+ ## Rule 14: Tool Exclusivity
193
+
194
+ An agent cannot have both `tools` (allowlist) and `disallowed-tools` (denylist). Pick one approach.
195
+
196
+ ```agenttopology
197
+ # INVALID -- both tools and disallowed-tools
198
+ agent writer {
199
+ model: sonnet
200
+ tools: [Read, Write]
201
+ disallowed-tools: [Bash]
202
+ }
203
+ ```
204
+
205
+ ---
206
+
207
+ ## Rule 15: Exhaustive Conditions
208
+
209
+ When a node has **only** conditional outgoing edges, the conditions must cover every possible value of the referenced output that is **reachable** at that node.
210
+
211
+ A value is unreachable if all flow paths to the node require a condition that excludes it. The compiler accounts for upstream routing when checking exhaustiveness.
212
+
213
+ ```agenttopology
214
+ # INVALID -- "reject" is not covered
215
+ agent reviewer {
216
+ outputs: {
217
+ verdict: approve | revise | reject
218
+ }
219
+ }
220
+
221
+ flow {
222
+ reviewer -> publisher [when reviewer.verdict == approve]
223
+ reviewer -> writer [when reviewer.verdict == revise, max 2]
224
+ # Missing: reviewer -> ??? [when reviewer.verdict == reject]
225
+ }
226
+
227
+ # VALID -- all three values covered
228
+ flow {
229
+ reviewer -> publisher [when reviewer.verdict == approve]
230
+ reviewer -> writer [when reviewer.verdict == revise, max 2]
231
+ reviewer -> researcher [when reviewer.verdict == reject, max 1]
232
+ }
233
+ ```
234
+
235
+ ---
236
+
237
+ ## Rule 16: API Key Environment Variables
238
+
239
+ Provider `api-key` values must be environment variable references using `${ENV_VAR}` syntax. Literal API keys in `.at` files are a security risk and always a validation error.
240
+
241
+ ```agenttopology
242
+ # INVALID -- literal API key
243
+ providers {
244
+ anthropic {
245
+ api-key: "sk-ant-api03-..."
246
+ models: [opus, sonnet]
247
+ }
248
+ }
249
+
250
+ # VALID -- environment variable reference
251
+ providers {
252
+ anthropic {
253
+ api-key: "${ANTHROPIC_API_KEY}"
254
+ models: [opus, sonnet]
255
+ }
256
+ }
257
+ ```
258
+
259
+ ---
260
+
261
+ ## Rule 17: Single Default Provider
262
+
263
+ At most one provider may have `default: true`. When multiple providers serve the same model, the default provider is preferred for routing.
264
+
265
+ ```agenttopology
266
+ # INVALID -- two defaults
267
+ providers {
268
+ anthropic {
269
+ api-key: "${ANTHROPIC_API_KEY}"
270
+ models: [opus, sonnet]
271
+ default: true
272
+ }
273
+ openrouter {
274
+ api-key: "${OPENROUTER_API_KEY}"
275
+ models: [opus, sonnet]
276
+ default: true
277
+ }
278
+ }
279
+ ```
280
+
281
+ ---
282
+
283
+ ## Rule 18: Model in Provider (Warning)
284
+
285
+ When a `providers` block is present, every model referenced by an agent or orchestrator should exist in at least one provider's `models` list. This is a **warning**, not an error — the topology is still valid but may indicate a misconfiguration.
286
+
287
+ ```agenttopology
288
+ # WARNING -- agent uses "gpt-4o" but no provider lists it
289
+ providers {
290
+ anthropic {
291
+ api-key: "${ANTHROPIC_API_KEY}"
292
+ models: [opus, sonnet]
293
+ }
294
+ }
295
+
296
+ agent writer {
297
+ model: gpt-4o # warning: not in any provider's models
298
+ tools: [Read, Write]
299
+ }
300
+ ```
301
+
302
+ ---
303
+
304
+ ## Rule 19: Unique Provider Names
305
+
306
+ Provider names must be unique within the `providers` block. Duplicate names are an error.
307
+
308
+ ```agenttopology
309
+ # INVALID -- duplicate "anthropic"
310
+ providers {
311
+ anthropic {
312
+ api-key: "${ANTHROPIC_API_KEY}"
313
+ models: [opus]
314
+ }
315
+ anthropic {
316
+ api-key: "${ANTHROPIC_BACKUP_KEY}"
317
+ models: [sonnet]
318
+ }
319
+ }
320
+ ```
321
+
322
+ ---
323
+
324
+ ## Rule 20: Schedule Job References
325
+
326
+ Every schedule job must reference a declared agent or action. The `cron` and `every` fields are mutually exclusive -- a job cannot have both.
327
+
328
+ ```agenttopology
329
+ # INVALID -- "ghost-agent" is not declared
330
+ schedule {
331
+ job nightly-run {
332
+ cron: "0 2 * * *"
333
+ agent: ghost-agent
334
+ }
335
+ }
336
+
337
+ # INVALID -- both cron and every specified
338
+ schedule {
339
+ job conflicting {
340
+ cron: "0 9 * * *"
341
+ every: "daily"
342
+ agent: summarizer
343
+ }
344
+ }
345
+ ```
346
+
347
+ ---
348
+
349
+ ## Rule 21: Interface Secret Detection
350
+
351
+ Interface fields named `webhook`, `auth`, `token`, or `secret` must use `${ENV_VAR}` syntax. Literal values are a validation error, preventing accidental secret exposure in `.at` files.
352
+
353
+ ```agenttopology
354
+ # INVALID -- literal webhook URL
355
+ interfaces {
356
+ slack {
357
+ type: webhook
358
+ webhook: "https://hooks.slack.com/services/T00/B00/xxxx"
359
+ }
360
+ }
361
+
362
+ # VALID
363
+ interfaces {
364
+ slack {
365
+ type: webhook
366
+ webhook: "${SLACK_WEBHOOK_URL}"
367
+ }
368
+ }
369
+ ```
370
+
371
+ ---
372
+
373
+ ## Rule 22: Fallback Chain Model Validation
374
+
375
+ When providers are declared, every model in a `fallback-chain` should exist in at least one provider's `models` list. This is a **warning** (not error) since model availability may vary at runtime.
376
+
377
+ ```agenttopology
378
+ providers {
379
+ anthropic {
380
+ api-key: "${ANTHROPIC_API_KEY}"
381
+ models: [opus, sonnet]
382
+ }
383
+ }
384
+
385
+ settings {
386
+ fallback-chain: [opus, sonnet, haiku] # warning: haiku not in any provider
387
+ }
388
+ ```
389
+
390
+ ---
391
+
392
+ ## Rule 23: Duplicate Sections (Warning)
393
+
394
+ Singleton top-level sections (`meta`, `flow`, `memory`, `gates`, `depth`, `batch`, `environments`, `triggers`, `hooks`, `settings`, `mcp-servers`, `metering`, `tools`, `schedule`, `interfaces`) may appear at most once. When duplicates are found, only the first occurrence is used by the parser and a **warning** is emitted.
395
+
396
+ ```agenttopology
397
+ # WARNING -- duplicate memory block
398
+ memory {
399
+ workspace { path: "workspace/" }
400
+ }
401
+
402
+ memory {
403
+ domains { path: "domains/" }
404
+ }
405
+ ```
406
+
407
+ ---
408
+
409
+ ## Rule 24: Unknown Memory Sub-Blocks (Warning)
410
+
411
+ Only known sub-blocks are expected inside the `memory` section: `domains`, `references`, `external-docs`, `metrics`, and `workspace`. Any other named sub-block is parsed but flagged as a **warning**.
412
+
413
+ ```agenttopology
414
+ # WARNING -- "custom-store" is not a recognized memory sub-block
415
+ memory {
416
+ workspace { path: "workspace/" }
417
+ custom-store { path: "store/" }
418
+ }
419
+ ```
420
+
421
+ ---
422
+
423
+ ## Rule 25: Bounce-Back Advisory (Warning)
424
+
425
+ The `on-fail: bounce-back` gate behavior is advisory on all CLI bindings. It requires orchestrator cooperation or a framework binding for enforcement. This is a **warning** to inform topology authors that bounce-back is not guaranteed to be enforced at runtime.
426
+
427
+ ```agenttopology
428
+ # WARNING -- bounce-back is advisory
429
+ gates {
430
+ gate quality-check {
431
+ after: writer
432
+ before: reviewer
433
+ run: "scripts/check.sh"
434
+ on-fail: bounce-back
435
+ }
436
+ }
437
+ ```
438
+
439
+ ---
440
+
441
+ ## Rule 26: Action Kind Enum
442
+
443
+ Every `action.kind` must be one of the allowed values: `external`, `git`, `decision`, `inline`, or `report`. Any other value is an error.
444
+
445
+ ```agenttopology
446
+ # INVALID -- "webhook" is not a recognized action kind
447
+ action notify {
448
+ kind: webhook
449
+ description: "Send notification"
450
+ }
451
+ ```
452
+
453
+ ---
454
+
455
+ ## Rule 27: Agent Permissions Enum (Warning)
456
+
457
+ Agent `permissions` values should be one of the known values: `autonomous`, `supervised`, `interactive`, `unrestricted`, `plan`, `auto`, `confirm`, `bypass`. Unrecognized values produce a **warning** (not error) since new permission modes may be added.
458
+
459
+ ```agenttopology
460
+ # WARNING -- "restricted" is not a recognized permission mode
461
+ agent writer {
462
+ model: sonnet
463
+ permissions: restricted
464
+ }
465
+ ```
466
+
467
+ ---
468
+
469
+ ## Rule 28: Metering Format Enum
470
+
471
+ The `metering.format` field must be one of: `json`, `jsonl`, or `csv`. Any other value is an error.
472
+
473
+ ```agenttopology
474
+ # INVALID -- "xml" is not a recognized metering format
475
+ metering {
476
+ track: [tokens-in, tokens-out]
477
+ per: [agent]
478
+ output: "metrics/"
479
+ format: xml
480
+ pricing: none
481
+ }
482
+ ```
483
+
484
+ ---
485
+
486
+ ## Rule 29: Metering Pricing Enum (Warning)
487
+
488
+ The `metering.pricing` field should be one of the known values: `anthropic-current`, `custom`, or `none`. Unrecognized values produce a **warning** since custom pricing integrations may exist.
489
+
490
+ ```agenttopology
491
+ # WARNING -- "openai-current" is not a recognized pricing model
492
+ metering {
493
+ track: [tokens-in, tokens-out]
494
+ per: [agent]
495
+ output: "metrics/"
496
+ format: jsonl
497
+ pricing: openai-current
498
+ }
499
+ ```
500
+
501
+ ---
502
+
503
+ ## Summary Table
504
+
505
+ | Rule | Severity | Description |
506
+ |------|----------|-------------|
507
+ | V1 | error | Unique names — all agent, action, and gate names must be globally unique |
508
+ | V2 | error | No keyword names — names cannot match reserved keywords |
509
+ | V3 | error | Flow resolves — every flow reference must be a declared node |
510
+ | V4 | error | No orphans — every agent must appear in flow or have `invocation: manual` |
511
+ | V5 | error | Outputs exist — `[when x.y]` must reference a declared output |
512
+ | V6 | error | Bounded loops — every back-edge must have `[max N]` |
513
+ | V7 | error | Model required — every agent and orchestrator must have a model |
514
+ | V8 | error | Imports resolve — import paths must point to existing files |
515
+ | V9 | error | Actions handled — flow actions must appear in `orchestrator.handles` |
516
+ | V10 | warning | Prompts exist — prompt blocks should not be empty |
517
+ | V11 | error | Reads/writes consistent — data dependencies must match flow order |
518
+ | V12 | error | Edge attribute order — must be `[when, max, per]` |
519
+ | V13 | error | Gate placement — `after` and `before` must reference declared nodes |
520
+ | V14 | error | Tool exclusivity — cannot have both `tools` and `disallowed-tools` |
521
+ | V15 | error | Exhaustive conditions — conditional edges must cover all output values |
522
+ | V16 | error | API key env vars — provider `api-key` must use `${ENV_VAR}` syntax |
523
+ | V17 | error | Single default provider — at most one provider may be default |
524
+ | V18 | warning | Model in provider — agent models should exist in a provider's list |
525
+ | V19 | error | Unique provider names — no duplicate provider names |
526
+ | V20 | error | Schedule job references — jobs must reference declared nodes; cron/every exclusive |
527
+ | V21 | error | Interface secret detection — sensitive fields must use `${ENV_VAR}` syntax |
528
+ | V22 | warning | Fallback chain models — fallback models should exist in a provider's list |
529
+ | V23 | warning | Duplicate sections — singleton sections should appear at most once |
530
+ | V24 | warning | Unknown memory sub-blocks — only known sub-blocks are expected |
531
+ | V25 | warning | Bounce-back advisory — `on-fail: bounce-back` is advisory on CLI bindings |
532
+ | V26 | error | Action kind enum — must be external, git, decision, inline, or report |
533
+ | V27 | warning | Agent permissions enum — should be a recognized permission mode |
534
+ | V28 | error | Metering format enum — must be json, jsonl, or csv |
535
+ | V29 | warning | Metering pricing enum — should be a recognized pricing model |