Skip to main content

Advanced 16 - Self-correction loop with built-in diagnostics

The lsp module ships five built-in validators that need no external binary installed on the host: JSON, YAML, HTML, XML, and Mermaid. Everything else - Python, Go, TypeScript, Rust, LaTeX, and the rest - needs a real language server binary present on the machine (pyright, gopls, texlab, ...); the module starts it and speaks LSP to it, but doesn't bundle it.

Wire the lsp_diagnose hook to turn either into a self-correction loop: after every file write, the agent gets the diagnostics back in the tool result and can read them before its next move.

Built-in validators (no install needed)​

ExtensionsCatches
.json, .jsonc, .excalidrawJSON syntax errors, with line + column
.yaml, .ymlYAML syntax errors - and if the file is part of an app bundle (the manifest itself, or any file under a fragments//behavior/-style bundle folder), the real Digitorn compiler runs instead of a plain syntax check, so a bad include: or a schema error surfaces the same diagnostic digitorn install would give
.html, .htmMalformed HTML tokens
.xml, .xsd, .xsl, .svgXML syntax errors
.mmd, .mermaidMermaid-specific issues: missing diagram header, unbalanced subgraph/end, reserved words used as node ids

These five need nothing beyond the daemon itself. Everything else - including TOML, which has no validator at all, built-in or otherwise - needs a real external language server wired under tools.modules.lsp.config.servers, covered in LSP.

The YAML​

app.yaml
app:
app_id: json-selfcorrect
name: JSON Self-Correction Loop
version: "1.0"

runtime:
mode: conversation
workdir_mode: auto
max_turns: 6
timeout: 180

agents:
- id: main
role: assistant
brain:
provider: openai
backend: openai_compat
model: gpt-5-mini
config:
api_key: placeholder
base_url: https://api.openai.com/v1
temperature: 0.2
max_tokens: 4096
system_prompt: |
You author JSON config files inside the workspace.

Use Write to create files, Edit to fix them. After each
write, call lsp.notify_change on the same path to get
diagnostics.

Workflow:
1. Write the file.
2. Call lsp.notify_change(path=<the file>).
3. If any diagnostic has severity "error", Edit to fix the
most pressing one and repeat from step 2.
4. Once diagnostics are empty, reply with one short
confirmation line.

tools:
modules:
filesystem: {}
lsp: {}
capabilities:
default_policy: auto
grant:
- module: filesystem
tools: [read, write, edit]
- module: lsp

Sample flow​

Turn 1: write a broken file, then check it.

json
Write(path="config.json", content="{\"name\": \"demo\",}")
json
lsp.notify_change(path="config.json")
→ {
"diagnostics": [
{
"line": 1,
"column": 19,
"severity": "error",
"message": "invalid character '}' looking for beginning of object key string"
}
]
}

Turn 2: fix it.

json
Edit(path="config.json", old_string="\"demo\",}", new_string="\"demo\"}")
json
lsp.notify_change(path="config.json")
→ { "diagnostics": [] }

Wiring it as an automatic hook​

Rather than teaching the agent to call lsp.notify_change itself, wire lsp_diagnose to fire automatically after every write and inject the diagnostics straight into the write's own tool result:

yaml
runtime:
hooks:
- id: lint_after_write
"on": tool_end
condition:
type: tool_name
match: [filesystem.write, filesystem.edit]
action:
type: lsp_diagnose
inject_result: true
cooldown: 0.5

inject_result: true appends the diagnostics text to the write's own result instead of pushing a separate message, so the agent sees "wrote the file, here's what's wrong with it" in one place. The hook resolves which file changed on its own - it checks path, file_path, filename, file, and tool.result.path on the triggering call, in that order, so it works across filesystem, mcp servers, and custom writers without extra configuration in the common case.

When to reach for this​

  • Any workflow where the agent generates structured files (configs, JSON payloads, app bundles).
  • Editing a Digitorn app bundle itself - the YAML validator's compiler-backed path means a broken include: or a bad field surfaces the same compiler diagnostic digitorn install would give, automatically, after every edit.
  • A safe floor under real language-server wiring: even before you install pyright or gopls on the host, JSON/YAML/HTML/XML/ Mermaid files already get real syntax checking.

For type-level diagnostics, style rules, or anything beyond what the five built-ins cover, install and configure a real LSP server in the lsp: module - see LSP.