Scoping and Capabilities¶
Agent state follows lexical source scope. Capability metadata determines whether the selected adapter can honor the resulting contract.
Lexical Agent State¶
> adapter: pydantic
> model: default-model
@quick(text: str) -> str:
> effort: low
>> A summary of <text> is [summary: str].
= <summary>
The effort override exists only inside quick; the outer adapter and model are
inherited. On return, the prior state is restored.
Top-Level Capture¶
Top-level directives are captured by procedures declared after them. A later top-level change does not retroactively change a previously declared procedure:
> model: first-model
@first() -> str:
>> A brief answer is [answer: str].
= <answer>
> model: second-model
@second() -> str:
>> A brief answer is [answer: str].
= <answer>
This source-order rule also applies to tools, MCP, instructions, and profiles.
Precedence¶
Start with the configured defaults and the captured lexical state. Then apply profile applications and direct directives in source order in the current scope. They are not separate priority tiers:
> profile: concise:
> system: Return one sentence.
> system: Return a paragraph.
> use: concise
Here the profile's one-sentence instruction wins because the profile is applied last. Reversing those last two statements makes the paragraph instruction win. Collection members follow the profile merge rules.
Calling a previously defined procedure does not recapture the caller's model or tools. To make a procedure use different configuration, declare the override in its body or define it under that configuration.
Tool Frames¶
Tool registration is block-scoped. Inner registrations can shadow an outer tool with the same name; leaving the block restores the previous binding. A procedure tool receives its schema from that procedure's signature and docstring.
The same profile used in two scopes does not make mutable tool state global. Each invocation materializes its active tool surface.
Configuration Scope and Value Scope¶
Agent configuration and variable bindings are related but separate. An if or
loop body has its own scope: newly initialized local values do not leak to the
outer environment. Mutation of an existing outer binding follows the language's
assignment rules; changing a model directive does not change those rules.
Likewise, a procedure captures agent configuration at definition time, not a promise that all referenced mutable Python objects are deep-copied. Child-agent conversation isolation does not sandbox arbitrary shared host objects. See Outputs and Assignment for binding semantics and Subagent Isolation for the child boundary.
Capability Metadata¶
Adapters advertise kind and capabilities such as:
- structured outputs;
- dynamic Kedi/Python tools;
- MCP servers;
- skills;
- subagent foreground or background execution;
- approval mediation.
- event-specific lifecycle hooks.
The parser and LSP combine literal backend selection with this metadata. Dynamic backend expressions defer some checks to runtime.
Errors versus Warnings¶
Structured output is central to >> output capture. If the selected adapter
does not support it, the LSP reports an error and execution raises rather than
falling back to manual JSON prompting.
Tool and MCP support is currently reported as a capability warning for adapters that cannot register them, allowing the same source to become valid when the adapter gains support. Do not ignore the warning in production: the intended capability is not active.
Subagent delegation and other required runtime seams fail explicitly when the adapter lacks child execution. Kedi never pretends that delegated work ran.
Adapter Switching¶
Nested scopes may switch to another framework or harness:
> adapter: pydantic
@repository_task(task: str) -> str:
> agent: codex
>> Complete this repository task: <task>. The result is [answer: str].
= <answer>
The nested scope is a new selection boundary. A single scope still cannot mix both kinds.
Production Guidance¶
Treat every capability warning as an unmet contract, test literal profiles with their production adapter, and keep dynamic backend selection at application boundaries. Static profiles give the LSP enough information to detect schema, tool, and transport mismatches before a paid model call.