Skip to content

Embedding Glyph

Glyph depends on no agent framework. Astromesh consumes it through pattern: glyph, but the package is a plain library: give it a catalog of capabilities and a way to invoke them, and it will compile and run programs.

Terminal window
uv add astromesh-glyph # from the monorepo path source — see the install note

Two methods. Glyph does not know what a tool, an agent or a model is — it knows there are named capabilities with a schema and a way to call them.

from typing import Any, Protocol, runtime_checkable
@runtime_checkable
class CapabilityProvider(Protocol):
def list_capabilities(self) -> list[CapabilitySpec]: ...
async def invoke(self, name: str, args: dict[str, Any]) -> Any: ...
@dataclass(frozen=True)
class CapabilitySpec:
name: str
description: str
parameters: dict[str, Any] = {} # JSON Schema, object type
is_semantic: bool = False
returns: str = ""
FieldWhy it exists
parametersA JSON Schema object — the same shape OpenAI function calling uses, so an existing tool definition drops in
is_semanticMarks capabilities that call a model. The host counts these separately, because each one is a round-trip the program chose to pay
returnsThe shape of what comes back, in one readable line: "list of {sku, kind, price}"
from astromesh_glyph import (
build_system_block, compile_program, execute, extract_program, parse,
)
caps = provider.list_capabilities()
# 1. Prompt side — the grammar and the catalog go into the system prompt.
block = build_system_block(caps)
# 2. The model answers. Pull the program out of whatever it wrapped it in.
source = extract_program(model_response)
# 3. Parse → compile. Nothing has executed yet.
program = parse(source)
graph = compile_program(program, caps, predefined=["query", "context"])
# 4. Execute.
result = await execute(graph, provider, initial_env={"query": q, "context": ctx})

Each step is separately usable. A host that ships fixed programs never calls build_system_block or extract_program — it parses and compiles at load time and only executes at run time. That is exactly what Astromesh does with spec.program.

compile_program(program, capabilities, predefined=())

Section titled “compile_program(program, capabilities, predefined=())”

Validates every invoked capability and its arguments against the catalog, and returns a PlanGraph — the dependency graph between statements.

predefined names the variables the host binds before the program runs. Without it, a fixed program that reads its invocation context would not compile, because the compiler would see undefined variables. Predefined names are still subject to the no-reassignment rule.

execute(graph, provider, *, node_timeout=None, max_fanout=16, initial_env=None)

Section titled “execute(graph, provider, *, node_timeout=None, max_fanout=16, initial_env=None)”

Runs the graph in topological waves; statements in the same wave run concurrently.

ParameterNotes
node_timeoutPer-node ceiling, in seconds. None means no timeout
max_fanoutCap on concurrent invocations, so a map over a thousand items does not fire a thousand requests
initial_envValues for the predefined names. Host values are wrapped like capability results, so context.field works the same either way

Returns an ExecutionResult carrying the value, the executed nodes and a CallRecord per invocation.

from astromesh_glyph import GlyphCompileError, GlyphExecutionError, GlyphSyntaxError
try:
result = await execute(graph, provider)
except GlyphExecutionError as exc:
# Tells the model which effects already happened, so it does not repeat them.
repair_prompt = exc.partial_state.to_prompt()
ExceptionRaised when
GlyphSyntaxErrorThe text is not a Glyph program — lexer or parser, with the line
GlyphCompileErrorIt parses but references an unknown capability or a bad argument, with the line
GlyphExecutionErrorA capability failed mid-run. Carries the partial state

All three inherit GlyphError.

The distinction matters for where you spend a retry. A syntax or compile error means the model wrote something wrong and a repair costs one model call with a precise error message. An execution error means the world pushed back, and re-running from the top may re-apply effects that already landed — which is why the partial state is serialised rather than discarded.

  • Cap the repairs. Every repair is a full model call. Astromesh defaults to two.
  • Fail loudly on a fixed program. A pinned program that does not compile should stop the agent from loading, not silently fall back to a tool-calling loop — the fallback costs two orders of magnitude more, exactly when nobody is watching.
  • Measure validity before rolling out. The rate of programs that compile on the first try is the metric that decides. Below 50% a model pays repairs constantly and no saving survives it; models that write code well without deliberating at length score 80%+.