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.
- package/LICENSE +191 -0
- package/README.md +450 -0
- package/dist/analyzer/__tests__/analyzer.test.d.ts +2 -0
- package/dist/analyzer/__tests__/analyzer.test.d.ts.map +1 -0
- package/dist/analyzer/__tests__/analyzer.test.js +258 -0
- package/dist/analyzer/__tests__/analyzer.test.js.map +1 -0
- package/dist/analyzer/index.d.ts +44 -0
- package/dist/analyzer/index.d.ts.map +1 -0
- package/dist/analyzer/index.js +308 -0
- package/dist/analyzer/index.js.map +1 -0
- package/dist/bindings/__tests__/bindings.test.d.ts +2 -0
- package/dist/bindings/__tests__/bindings.test.d.ts.map +1 -0
- package/dist/bindings/__tests__/bindings.test.js +2089 -0
- package/dist/bindings/__tests__/bindings.test.js.map +1 -0
- package/dist/bindings/claude-code.d.ts +12 -0
- package/dist/bindings/claude-code.d.ts.map +1 -0
- package/dist/bindings/claude-code.js +2063 -0
- package/dist/bindings/claude-code.js.map +1 -0
- package/dist/bindings/codex.d.ts +18 -0
- package/dist/bindings/codex.d.ts.map +1 -0
- package/dist/bindings/codex.js +1633 -0
- package/dist/bindings/codex.js.map +1 -0
- package/dist/bindings/copilot-cli.d.ts +20 -0
- package/dist/bindings/copilot-cli.d.ts.map +1 -0
- package/dist/bindings/copilot-cli.js +1515 -0
- package/dist/bindings/copilot-cli.js.map +1 -0
- package/dist/bindings/cursor.d.ts +17 -0
- package/dist/bindings/cursor.d.ts.map +1 -0
- package/dist/bindings/cursor.js +1715 -0
- package/dist/bindings/cursor.js.map +1 -0
- package/dist/bindings/gemini-cli.d.ts +18 -0
- package/dist/bindings/gemini-cli.d.ts.map +1 -0
- package/dist/bindings/gemini-cli.js +1327 -0
- package/dist/bindings/gemini-cli.js.map +1 -0
- package/dist/bindings/index.d.ts +20 -0
- package/dist/bindings/index.d.ts.map +1 -0
- package/dist/bindings/index.js +33 -0
- package/dist/bindings/index.js.map +1 -0
- package/dist/bindings/kiro.d.ts +17 -0
- package/dist/bindings/kiro.d.ts.map +1 -0
- package/dist/bindings/kiro.js +1624 -0
- package/dist/bindings/kiro.js.map +1 -0
- package/dist/bindings/openclaw.d.ts +18 -0
- package/dist/bindings/openclaw.d.ts.map +1 -0
- package/dist/bindings/openclaw.js +1578 -0
- package/dist/bindings/openclaw.js.map +1 -0
- package/dist/bindings/types.d.ts +33 -0
- package/dist/bindings/types.d.ts.map +1 -0
- package/dist/bindings/types.js +23 -0
- package/dist/bindings/types.js.map +1 -0
- package/dist/cli/index.d.ts +19 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +679 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/docs/__tests__/docs.test.d.ts +2 -0
- package/dist/docs/__tests__/docs.test.d.ts.map +1 -0
- package/dist/docs/__tests__/docs.test.js +438 -0
- package/dist/docs/__tests__/docs.test.js.map +1 -0
- package/dist/docs/content.d.ts +16 -0
- package/dist/docs/content.d.ts.map +1 -0
- package/dist/docs/content.js +3273 -0
- package/dist/docs/content.js.map +1 -0
- package/dist/docs/index.d.ts +17 -0
- package/dist/docs/index.d.ts.map +1 -0
- package/dist/docs/index.js +117 -0
- package/dist/docs/index.js.map +1 -0
- package/dist/exporters/__tests__/exporters.test.d.ts +2 -0
- package/dist/exporters/__tests__/exporters.test.d.ts.map +1 -0
- package/dist/exporters/__tests__/exporters.test.js +731 -0
- package/dist/exporters/__tests__/exporters.test.js.map +1 -0
- package/dist/exporters/index.d.ts +13 -0
- package/dist/exporters/index.d.ts.map +1 -0
- package/dist/exporters/index.js +18 -0
- package/dist/exporters/index.js.map +1 -0
- package/dist/exporters/json.d.ts +8 -0
- package/dist/exporters/json.d.ts.map +1 -0
- package/dist/exporters/json.js +25 -0
- package/dist/exporters/json.js.map +1 -0
- package/dist/exporters/markdown.d.ts +9 -0
- package/dist/exporters/markdown.d.ts.map +1 -0
- package/dist/exporters/markdown.js +686 -0
- package/dist/exporters/markdown.js.map +1 -0
- package/dist/exporters/mermaid.d.ts +11 -0
- package/dist/exporters/mermaid.d.ts.map +1 -0
- package/dist/exporters/mermaid.js +161 -0
- package/dist/exporters/mermaid.js.map +1 -0
- package/dist/exporters/types.d.ts +22 -0
- package/dist/exporters/types.d.ts.map +1 -0
- package/dist/exporters/types.js +10 -0
- package/dist/exporters/types.js.map +1 -0
- package/dist/import/__tests__/import.test.d.ts +2 -0
- package/dist/import/__tests__/import.test.d.ts.map +1 -0
- package/dist/import/__tests__/import.test.js +781 -0
- package/dist/import/__tests__/import.test.js.map +1 -0
- package/dist/import/claude-code.d.ts +38 -0
- package/dist/import/claude-code.d.ts.map +1 -0
- package/dist/import/claude-code.js +897 -0
- package/dist/import/claude-code.js.map +1 -0
- package/dist/import/index.d.ts +18 -0
- package/dist/import/index.d.ts.map +1 -0
- package/dist/import/index.js +28 -0
- package/dist/import/index.js.map +1 -0
- package/dist/import/serializer.d.ts +11 -0
- package/dist/import/serializer.d.ts.map +1 -0
- package/dist/import/serializer.js +960 -0
- package/dist/import/serializer.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/__tests__/parser.test.d.ts +2 -0
- package/dist/parser/__tests__/parser.test.d.ts.map +1 -0
- package/dist/parser/__tests__/parser.test.js +6514 -0
- package/dist/parser/__tests__/parser.test.js.map +1 -0
- package/dist/parser/ast.d.ts +708 -0
- package/dist/parser/ast.d.ts.map +1 -0
- package/dist/parser/ast.js +12 -0
- package/dist/parser/ast.js.map +1 -0
- package/dist/parser/index.d.ts +253 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +1985 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/lexer.d.ts +100 -0
- package/dist/parser/lexer.d.ts.map +1 -0
- package/dist/parser/lexer.js +304 -0
- package/dist/parser/lexer.js.map +1 -0
- package/dist/parser/validator.d.ts +42 -0
- package/dist/parser/validator.d.ts.map +1 -0
- package/dist/parser/validator.js +2568 -0
- package/dist/parser/validator.js.map +1 -0
- package/dist/scaffold/__tests__/scaffold.test.d.ts +7 -0
- package/dist/scaffold/__tests__/scaffold.test.d.ts.map +1 -0
- package/dist/scaffold/__tests__/scaffold.test.js +295 -0
- package/dist/scaffold/__tests__/scaffold.test.js.map +1 -0
- package/dist/scaffold/incremental.d.ts +43 -0
- package/dist/scaffold/incremental.d.ts.map +1 -0
- package/dist/scaffold/incremental.js +185 -0
- package/dist/scaffold/incremental.js.map +1 -0
- package/dist/scaffold/index.d.ts +13 -0
- package/dist/scaffold/index.d.ts.map +1 -0
- package/dist/scaffold/index.js +13 -0
- package/dist/scaffold/index.js.map +1 -0
- package/dist/scaffold/manifest.d.ts +30 -0
- package/dist/scaffold/manifest.d.ts.map +1 -0
- package/dist/scaffold/manifest.js +71 -0
- package/dist/scaffold/manifest.js.map +1 -0
- package/dist/scaffold/merge.d.ts +52 -0
- package/dist/scaffold/merge.d.ts.map +1 -0
- package/dist/scaffold/merge.js +134 -0
- package/dist/scaffold/merge.js.map +1 -0
- package/dist/scaffold/types.d.ts +51 -0
- package/dist/scaffold/types.d.ts.map +1 -0
- package/dist/scaffold/types.js +10 -0
- package/dist/scaffold/types.js.map +1 -0
- package/dist/sync/index.d.ts +34 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +392 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/visualizer/index.d.ts +17 -0
- package/dist/visualizer/index.d.ts.map +1 -0
- package/dist/visualizer/index.js +1976 -0
- package/dist/visualizer/index.js.map +1 -0
- package/examples/code-review.at +167 -0
- package/examples/data-processing.at +296 -0
- package/examples/openclaw-assistant.at +142 -0
- package/examples/scheduled-monitor.at +193 -0
- package/examples/simple-pipeline.at +163 -0
- package/package.json +77 -0
- package/skill/SKILL.md +403 -0
- package/skill/scripts/emit.ts +853 -0
- package/skill/scripts/visualize.ts +89 -0
- package/spec/grammar.md +1466 -0
- package/spec/reserved-keywords.md +147 -0
- 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 |
|