@tangle-network/agent-runtime / agent
Thrown when defineAgent finds a required surface missing on disk.
Error
new AgentManifestError(
message,agentId,issues?):AgentManifestError
string
string
readonly unknown[] = []
Error.constructor
readonlyagentId:string
readonlyissues: readonlyunknown[] =[]
The full agent manifest. Each agent ships ONE of these.
Generics:
TPersona — the agent's persona shape (loaded from
surfaces.personas). Defaults to unknown so the substrate's
persona discovery (loadPersonas) can accept anything; per-agent
code re-narrows when it matters.
TRunOutput — the shape runtime.act returns. Used by the rubric
scorers and emitted into the trace.
TPersona = unknown
TRunOutput = unknown
id:
string
Stable identifier — used as projectId in traces, as the analyst
loop's runId prefix, and as the namespace under which findings
are persisted. MUST match the agent's repo name to keep
cross-repo telemetry joinable.
repoRoot:
string
Filesystem root the substrate resolves surface paths against.
Typically process.cwd() or a fixed absolute path. Use an
absolute path when the agent's tests may run from subdirectories
(vitest sometimes shifts cwd).
surfaces:
AgentSurfaces
Map of mutable surfaces the self-improvement loop can edit. See
AgentSurfaces — required: systemPrompt, tools, rubric,
knowledge, personas. Optional: scaffolding, memory, rag,
outputSchema.
Every required path is validated at defineAgent time. Missing
paths throw with the full list of offenders.
rubric:
AgentRubric<TRunOutput>
Rubric the substrate uses to score each run. Dimensions × weights × judges. The substrate computes the weighted composite and stamps it into the RunRecord.
runtime:
AgentRuntime<TPersona,TRunOutput>
Runtime adapter — how the substrate INVOKES the agent against a
persona. The act function takes a persona + a context (with the
tracer the substrate threads through for span emission) and
returns the run output the rubric will score.
The agent's existing production runtime goes in here; the substrate is intentionally thin around it.
personas: () =>
Promise<readonlyTPersona[]>
Persona discovery — the substrate loads personas via this function
at eval start. Can read from surfaces.personas, an API, or be
hardcoded. The substrate calls it once per runAgentEval call;
persona ordering is preserved.
Promise<readonly TPersona[]>
analystKinds: readonly
TraceAnalystDefinition[]
Analyst kinds the substrate runs against each persona's trace.
Defaults to DEFAULT_TRACE_ANALYST_KINDS from agent-eval. Per-agent
authors can prune (e.g. skip knowledge-poisoning when there's no
knowledge base) or extend (custom domain kinds).
Empty array disables the loop — useful for pnpm eval --no-analyst.
analyst:
AnalystConfig
Analyst LLM configuration. The substrate uses these for all four
kinds (override per-kind via analystKinds if needed).
@tangle-network/agent-runtime/agent — declarative agent manifest +
substrate-default adapters.
Every vertical agent (tax / legal / gtm / creative / N future
verticals) ships ONE defineAgent({...}) call + a thin invocation
of runAnalystLoop wired through the substrate-default adapters.
No per-vertical glue. No fabricated paths. No theater.
TRunOutput
dimensions: readonly
RubricDimension<TRunOutput>[]
Dimensions composing the weighted score. Weights sum to 1.0 by convention.
optionaljudges?: readonlyJudgeConfig<TRunOutput>[]
Optional judges layered on top of deterministic dimensions. Each judge returns a score per dimension; the substrate averages judges (mean by default) for the LLM contribution.
@tangle-network/agent-runtime/agent — declarative agent manifest +
substrate-default adapters.
Every vertical agent (tax / legal / gtm / creative / N future
verticals) ships ONE defineAgent({...}) call + a thin invocation
of runAnalystLoop wired through the substrate-default adapters.
No per-vertical glue. No fabricated paths. No theater.
TRunOutput
id:
string
Unique identifier — appears in finding subjects (rubric:<id>).
weight:
number
0..1 — weight in the composite.
score: (
input) =>number
Deterministic scorer: given the persona + run output, returns a 0..1 score. The substrate sums weight × score across dimensions for the deterministic composite; judges supplement subjective dims.
unknown
TRunOutput
number
optionallabel?:string
Optional human-readable label for reports.
@tangle-network/agent-runtime/agent — declarative agent manifest +
substrate-default adapters.
Every vertical agent (tax / legal / gtm / creative / N future
verticals) ships ONE defineAgent({...}) call + a thin invocation
of runAnalystLoop wired through the substrate-default adapters.
No per-vertical glue. No fabricated paths. No theater.
TRunOutput
id:
string
Judge identifier — appears in trace spans + manifest.
model:
string
Model snapshot to invoke. Pin the snapshot (claude-sonnet-4-6@2025-04-15); the validator rejects bare aliases.
dimensions: readonly
string[]
Dimensions this judge scores.
optionalanchors?: readonlyobject[]
Optional rubric anchors — text examples the judge sees as a few-shot prompt to calibrate. STRONGLY recommended for subjective dimensions; required by the calibration gate (Pearson ≥0.7).
@tangle-network/agent-runtime/agent — declarative agent manifest +
substrate-default adapters.
Every vertical agent (tax / legal / gtm / creative / N future
verticals) ships ONE defineAgent({...}) call + a thin invocation
of runAnalystLoop wired through the substrate-default adapters.
No per-vertical glue. No fabricated paths. No theater.
TPersona
TRunOutput
act: (
persona,ctx) =>AgentRunInvocation<TRunOutput>
Invoke the agent against one persona. Returns BOTH:
events: anAsyncIterable<RuntimeStreamEvent>the chat-centric product consumes verbatim (SSE / WebSocket / inline render). Streaming is mandatory — never collapse this to a single Promise. The agent's existingrunChatTurn(or equivalent async generator) plugs in here directly.output: aPromise<TRunOutput>resolved AFTER the event stream drains. The eval substrate awaits this for rubric scoring; chat products usually ignore it (they already rendered incrementally).
Implementation contract:
actMUST return immediately (synchronous construction of theeventsiterator + theoutputpromise).- Iterating
eventsdrives the underlying LLM/tool calls — the caller chooses when to consume. outputresolves only after the iterator yields its terminal event (typicallytask_end); seecollectAgentRunhelper.
ctx.emitter is the substrate-threaded TraceEmitter — runtimes
SHOULD record LLM/tool spans through it for capture integrity.
ctx.deadlineMs is wall-clock; the runtime SHOULD honour for graceful
cancel. ctx.signal is the standard abort signal.
TPersona
AgentRunInvocation<TRunOutput>
@tangle-network/agent-runtime/agent — declarative agent manifest +
substrate-default adapters.
Every vertical agent (tax / legal / gtm / creative / N future
verticals) ships ONE defineAgent({...}) call + a thin invocation
of runAnalystLoop wired through the substrate-default adapters.
No per-vertical glue. No fabricated paths. No theater.
TRunOutput
events:
AsyncIterable<RuntimeStreamEvent>
Live stream of typed runtime events. Consumed by chat UX directly.
output:
Promise<TRunOutput>
Final structured output the rubric scores. Resolves after events drains.
@tangle-network/agent-runtime/agent — declarative agent manifest +
substrate-default adapters.
Every vertical agent (tax / legal / gtm / creative / N future
verticals) ships ONE defineAgent({...}) call + a thin invocation
of runAnalystLoop wired through the substrate-default adapters.
No per-vertical glue. No fabricated paths. No theater.
emitter:
TraceEmitter
Substrate-managed trace emitter.
runId:
string
Stable run id for this persona × variant cell.
optionalvariantId?:string
Variant the runtime is exercising (e.g. 'baseline', 'source-grounded').
optionaldeadlineMs?:number
Wall-clock deadline (epoch ms). The runtime SHOULD honour for graceful cancel.
optionalsignal?:AbortSignal
Optional abort signal.
@tangle-network/agent-runtime/agent — declarative agent manifest +
substrate-default adapters.
Every vertical agent (tax / legal / gtm / creative / N future
verticals) ships ONE defineAgent({...}) call + a thin invocation
of runAnalystLoop wired through the substrate-default adapters.
No per-vertical glue. No fabricated paths. No theater.
model:
string
Model the analyst kinds use. Override per-kind via analystKinds[i].cost.models.
optionalbudgetUsd?:number
Optional total budget across all kinds for one run. Substrate enforces via BudgetGuard.
optionalbackend?:object
Backend hint for the AxAIService factory — same shape every kind uses.
optionalname?:"router"|"openai"
optionalapiKey?:string
optionalbaseUrl?:string
id:
string
Stable id derived from the source finding so re-proposals are idempotent.
sourceFindingId:
string
The finding that produced this edit — for revert + audit trail.
subject:
FindingSubject
Parsed subject; included so the apply step doesn't re-parse.
target:
ResolvedSurface
Resolved on-disk target.
baseSha256:
string
SHA-256 of the current file content the patch was drafted against.
patch:
string
Unified-diff patch the LLM drafted (relative to target.absolutePath).
summary:
string
One-line summary the operator sees in the report / PR title.
rationale:
string
Multi-line rationale for the PR body — finding context + LLM reasoning.
confidence:
number
Carry-forward from the finding so the apply gate can check the threshold.
severity:
"medium"|"low"|"high"|"info"|"critical"
Carry-forward severity for prioritization.
surfaces:
AgentSurfaces
repoRoot:
string
draftPatch: (
input) =>Promise<DraftPatchOutput>
LLM-draft callback. Given a finding + current file content + the resolved target, returns a unified-diff patch + summary + rationale.
Required — the substrate doesn't ship a hardcoded prompt; the agent author picks the model (Haiku for cheap routine drafts, Sonnet for substantive prompt rewrites, etc.) via this callback.
Promise<DraftPatchOutput>
optionalallowCreateForKinds?: readonly ("mcp"|"code"|"memory"|"agent-profile"|"rollout-policy"|"knowledge.wiki"|"knowledge.claim"|"knowledge.raw"|"knowledge.stale"|"system-prompt"|"skill"|"tool-doc"|"new-tool"|"hook"|"subagent"|"workflow"|"rag"|"scaffolding"|"output-schema"|"websearch.outdated"|"prior-run-summary"|"cluster")[]
When the resolved target doesn't exist, allow the substrate to
CREATE the file (for knowledge.wiki, new-tool subjects). Default
true for those kinds, false for system-prompt / rubric / etc.
(named sections that don't exist are a contract violation, not a
scaffolding opportunity).
finding:
AnalystFinding
subject:
FindingSubject
target:
ResolvedSurface
currentContent:
string
Current file content (empty string when intent === 'create-new').
patch:
string
Unified diff against the current file content. Empty string skips this finding.
summary:
string
One-line summary for the operator.
rationale:
string
Multi-line rationale for the PR body.
Declares which AgentProfile axes a concrete run path really carries.
name:
string
Human-readable run path, e.g. createSandboxAct or prompt-only-message.
axes: readonly
AgentProfileMaterializationAxis[]
Profile axes this run path actually carries into execution.
One changed AgentProfile axis that would be dropped by a run path.
contract:
string
reason:
"unsupported-axis"
supportedAxes: readonly
AgentProfileMaterializationAxis[]
Input for declaring a run path's profile-axis support.
name:
string
axes: readonly
AgentProfileMaterializationAxis[]
Input for checking a candidate diff against a run path.
contract:
ProfileMaterializationContract
changedAxes: readonly
AgentProfileMaterializationAxis[]
Input for throwing on dropped profile axes.
contract:
ProfileMaterializationContract
ValidateProfileMaterializationOptions.contract
changedAxes: readonly
AgentProfileMaterializationAxis[]
ValidateProfileMaterializationOptions.changedAxes
optionalcontext?:string
Extra label included in the thrown error, usually the caller or run id.
Per-persona profile-merge slots applied over the base profile (§1.5: the caller authors the per-persona profile). Each slot overlays the base; an absent slot leaves the base untouched.
optionalsystemPrompt?:string
Replace the base profile's system prompt (e.g. a workspace-augmented prompt).
optionalextraFiles?:AgentProfileFileMount[]
Extra file mounts layered after the base profile's resources.files.
optionalname?:string
Override the profile name. Defaults to the base profile's name.
optionaltools?:Record<string,boolean>
Box built-in tool ON/OFF flags merged over the base profile's tools (overlay wins per key).
optionalmcpConnections?:Record<string,AgentProfileMcpServer>
MCP connections merged over the base profile's mcp (overlay wins per key).
TPersona
TRunOutput
baseProfile:
AgentProfile
Canonical agent profile — the same one the prod chat turn uses.
sandboxClient:
SandboxClient
Sandbox client used to boot the per-run sandbox.
buildPrompt: (
persona) =>string
Persona → prompt. Pure; the eval cell's input.
TPersona
string
output:
OutputAdapter<TRunOutput>
Sandbox event stream → typed output the rubric scores.
optionalcompose?: (persona) =>SandboxActComposeOverrides
Per-persona profile overrides (workspace-augmented system prompt, extra
file mounts, tool flags, MCP connections). Overlaid onto baseProfile.
TPersona
optionalsandboxOverrides?:Partial<Omit<CreateSandboxOptions,"backend">> &object
Sandbox-SDK overrides forwarded to createSandboxForSpec.
optionalbackend?:Omit<BackendConfig,"profile">
optionalrequiredProfileAxes?: readonlyAgentProfileMaterializationAxis[]
Optional changed axes the caller expects this path to carry.
optionalname?:string
Stable run name surfaced in mapped llm_call events.
optionalmapEvent?: (event,opts) =>RuntimeStreamEvent|undefined
Override the SandboxEvent → RuntimeStreamEvent mapper.
SandboxEvent
string
RuntimeStreamEvent | undefined
Surface declarations. Every path is repo-relative (or absolute) at
defineAgent time. At resolution time, paths are joined against the
agent's repoRoot.
systemPrompt, tools, personas are DIRECTORIES; the loop appends
<section>.md, <tool>/README.md, <persona-id>.yaml etc.
rubric, outputSchema are SINGLE FILES; the loop edits them in
place.
knowledge is the agent-knowledge root (typically .agent-knowledge);
applyKnowledgeWriteBlocks writes pages relative to it.
Optional surfaces (scaffolding, memory, rag, outputSchema)
can be omitted — the loop will reject findings targeting them with a
clear log message instead of fabricating a path.
systemPrompt:
string
Directory containing one markdown file per system-prompt section.
tools:
string
Directory containing one subdir per tool (<tool>/README.md).
rubric:
string
Single file (TypeScript module) defining the rubric weights + dimensions.
knowledge:
string
Knowledge-base root; typically .agent-knowledge.
personas:
string
Directory containing one YAML/JSON file per persona.
optionalscaffolding?:string
Optional: directory containing scaffolding rules (precondition checks, retry policies).
optionalmemory?:string
Optional: memory store path (JSONL / SQLite / DB).
optionalrag?:string
Optional: directory containing RAG corpora (<corpus>/<doc-id>.md).
optionaloutputSchema?:string
Optional: single file defining the output schema (Zod / JSON Schema).
optionalskills?:string
Optional: directory containing Agent Skill packages.
optionalmcp?:string
Optional: directory containing MCP server/tool configuration.
optionalhooks?:string
Optional: directory containing hook definitions.
optionalsubagents?:string
Optional: directory containing subagent definitions.
optionalworkflows?:string
Optional: directory containing orchestration/workflow policies.
optionalrolloutPolicy?:string
Optional: single file containing rollout-policy settings.
optionalagentProfile?:string
Optional: single canonical AgentProfile file.
optionalcode?:string
Optional: source root for code findings.
absolutePath:
string
Absolute filesystem path the operator can cat / vim.
repoRelativePath:
string
Repo-relative path for PR descriptions, diffs, audit logs.
exists:
boolean
Whether the path currently exists on disk.
intent:
"edit-existing"|"create-new"
The substrate's intent: edit an existing file or create a new one.
Validate that every declared surface exists on disk under repoRoot.
Returns an array of SurfaceValidationIssue — empty when all required
surfaces resolve. defineAgent throws with the issues rendered, so
a misconfigured manifest fails at startup (not at the first finding
the loop produces 20 minutes later).
surface: keyof
AgentSurfaces
path:
string
reason:
"missing"|"not-directory"|"not-file"
KnownAgentProfileMaterializationAxis =
CanonicalAgentProfileMaterializationAxis
AgentProfileMaterializationAxis =
KnownAgentProfileMaterializationAxis|`custom:${string}`
AgentProfile axis name, with custom:<name> reserved for caller-owned extensions.
constfullProfileMaterialization:ProfileMaterializationContract
Materialization contract for a run path that executes every canonical AgentProfile leaf.
constpromptModelProfileMaterialization:ProfileMaterializationContract
Materialization contract for an intentionally limited prompt-and-model execution path. Identity, harness, and metadata are control fields consumed for naming, placement, authorization, and durable attribution; they are carried without adding worker behavior. Every behavioral axis other than prompt and model remains unsupported.
constworktreeCliProfileMaterialization:ProfileMaterializationContract
Materialization contract for a local coding CLI in an isolated git worktree.
The shared workspace materializer carries native tools, permissions, MCP, hooks, subagents,
modes, and file-backed resources when the selected CLI supports their exact values.
resourceFailOnError is carried: it is the fail-closed policy the pre-worktree resource
RESOLUTION step (resolveAgentProfileResources) applies to remote profile resources. Runtime
placement concerns (hub connections and confidential execution), provider-native extensions,
and unused model hints are deliberately absent so they fail before a worktree or executor is
created rather than being mistaken for an effective candidate change.
constcontrolProfileMaterialization:ProfileMaterializationContract
Materialization contract for a raw process path that carries only control/identity fields.
constpromptControlProfileMaterialization:ProfileMaterializationContract
Materialization contract for an injected inference function whose surrounding driver still applies the profile prompt, name, placement, and metadata, but not model selection.
constsandboxActProfileMaterialization:ProfileMaterializationContract
Materialization contract for createSandboxAct.
createSandboxAct hands the whole AgentProfile to the sandbox as backend.profile, so every
profile leaf crosses the boundary. buildBackendOptions resolves the runner only from
profile.harness; an explicit sandboxOverrides.backend.type may confirm that choice but cannot
replace it. A candidate declaring a harness the sandbox cannot run throws rather than running
elsewhere and reporting success.
constpromptOnlyProfileMaterialization:ProfileMaterializationContract
Materialization contract for a run path that only injects prompt text.
constpromptResourceProfileMaterialization:ProfileMaterializationContract
Materialization contract for a run path that injects prompt text plus inline resources.
resourceFailOnError is absent: it is a resolution POLICY the attaching path would have to
enforce, and inlining resource content does not carry it.
unimplementedAgentRun<
TRunOutput>(reason?):AgentRunInvocation<TRunOutput>
Stub for agents whose runtime.act is not yet wired to the substrate's
eval path. Preserves the streaming contract (empty event stream + a
rejected output promise that tells the caller exactly what to fix).
Per-vertical manifests usually start with this stub and replace it with
the agent's real streaming runtime (runChatTurn or equivalent) once
the eval path consumes the manifest end-to-end.
TRunOutput = unknown
string = 'AgentRuntime.act is not yet wired for this manifest'
AgentRunInvocation<TRunOutput>
collectAgentRun<
TRunOutput>(invocation):Promise<{events: readonlyRuntimeStreamEvent[];output:TRunOutput; }>
Drain act's events into an array AND await its output. Useful for
eval / outcome-measurement code paths that don't care about live
rendering. The events array is preserved so the substrate can inspect
tool calls / readiness / questions retrospectively.
IMPORTANT: chat-centric UX MUST NOT call this — it defeats streaming
(no incremental render). Use for await (const ev of invocation.events)
directly in the chat surface.
TRunOutput
AgentRunInvocation<TRunOutput>
Promise<{ events: readonly RuntimeStreamEvent[]; output: TRunOutput; }>
defineAgent<
TPersona,TRunOutput>(manifest):AgentManifest<TPersona,TRunOutput>
Construct a validated agent manifest. Throws AgentManifestError
if any required surface is missing on disk.
Generics: pass your persona / output types if you want narrowed
runtime.act signatures:
defineAgent<TaxPersona, TaxRunOutput>({ ... })
Most callers don't need the generics — the substrate operates on
unknown payloads internally and the manifest's score /
runtime.act see the typed shapes via TypeScript inference at
the call site.
TPersona = unknown
TRunOutput = unknown
AgentManifest<TPersona, TRunOutput>
AgentManifest<TPersona, TRunOutput>
createSurfaceImprovementProposer(
opts):ImprovementProposalSource<SurfaceImprovementEdit>
Resolve each finding to a real surface and draft a detached patch candidate.
CreateSurfaceImprovementProposerOptions
ImprovementProposalSource<SurfaceImprovementEdit>
defineProfileMaterializationContract(
options):ProfileMaterializationContract
Define the profile axes a concrete run path actually carries into execution.
DefineProfileMaterializationContractOptions
ProfileMaterializationContract
validateProfileMaterialization(
options): readonlyProfileMaterializationIssue[]
Return every changed profile axis that the selected run path would drop.
ValidateProfileMaterializationOptions
readonly ProfileMaterializationIssue[]
assertProfileMaterialization(
options):void
Throw when a candidate changes axes the selected run path cannot carry.
AssertProfileMaterializationOptions
void
renderProfileMaterializationIssues(
issues,context?):string
Format profile-axis drop issues into a concise operator-facing error.
readonly ProfileMaterializationIssue[]
string
string
createSandboxAct<
TPersona,TRunOutput>(options): (persona,ctx) =>AgentRunInvocation<TRunOutput>
Build an AgentRuntime.act implementation backed by a single prod-profile
sandbox run. The returned function honours the act contract: it returns
synchronously with a live events iterator and an output promise that
resolves only after the iterator drains.
TPersona
TRunOutput
CreateSandboxActOptions<TPersona, TRunOutput>
(persona, ctx) => AgentRunInvocation<TRunOutput>
resolveSubjectPath(
subject,surfaces,repoRoot):ResolvedSurface|null
Resolve a parsed FindingSubject to the file path the substrate
should edit (or create) on disk.
Returns null when:
- the subject targets a surface the agent didn't declare
(e.g.
rag:*whensurfaces.ragis undefined), OR - the subject is a
cluster(failure-mode emits these as evidence, not actionable mutations — they don't route to a file).
Returns a ResolvedSurface with intent: 'create-new' when the
subject names a path that doesn't yet exist (e.g. a new wiki page).
The caller chooses whether to honour the create — for tightly-managed
surfaces like systemPrompt it's usually a contract violation
(the analyst named a section that doesn't exist); for knowledge
it's the whole point.
FindingSubject
string
ResolvedSurface | null
validateSurfaces(
surfaces,repoRoot): readonlySurfaceValidationIssue[]
Validate an AgentSurfaces map on disk — missing paths fail loud at defineAgent time instead of silently skipping self-improvement edits.
string
readonly SurfaceValidationIssue[]
renderSurfaceIssues(
issues,repoRoot):string
Format a list of surface validation issues into a human-readable error string.
readonly SurfaceValidationIssue[]
string
string