Merged
Size
XL
Change Breakdown
Feature50%
Refactor30%
Security10%
Dependencies10%
#28339feat: use JSON for agent configuration

Agent builder switches from code to JSON configuration

Agent builder switches from code to JSON configuration
YE
yehorkardash
·Apr 13, 2026

The n8n agent builder now writes agent configurations as JSON instead of TypeScript code, with a new sandboxed execution environment for custom tools.

The agent builder's internal workflow has been completely reimagined. Previously, the builder LLM generated TypeScript code that defined agents using the SDK's fluent API. Now, the builder writes and patches agent configurations directly as JSON strings.

This shift eliminates a fragile code-generation step. The builder LLM receives two primary tools: write_config for complete configuration replacement, and patch_config for incremental updates using RFC 6902 JSON Patch operations. Both tools validate against a Zod schema before persisting, with structured error messages returned when validation fails so the LLM can self-correct.

Custom tools remain TypeScript, but their execution now happens inside V8 isolates. A new AgentSecureRuntime uses esbuild to bundle the necessary libraries (@n8n/agents and zod) into a single string that gets injected into sandbox contexts. This allows untrusted tool code to run safely without access to the filesystem, network, or other Node.js built-ins.

The agents database table loses its code column and gains a tools column that stores custom tool code alongside lightweight descriptors. The frontend's code editor tab is replaced with a JSON editor that syncs changes back to the API.

This is part of a broader initiative to make the agent builder more reliable and easier to maintain.

View Original GitHub Description

Summary

Introduces a JSON-based builder mode for the agent builder. The builder LLM now writes and patches the agent configuration as raw JSON strings rather than through writing typescript code. Custom tools are still written using typescript.

The builder prompt includes examples of using different features and simplified json schema of the agent config. There's a custom json schema serializer that reduces token size of schema by around ~40%

<details> <summary>Serialized agent schema</summary>
  name: string [1..128 chars] (required)
  description?: string [max 512 chars]
  model: string [min 1 chars, pattern: ^[a-z0-9-]+\\/[a-z0-9._-]+$] (required)
  credential: string [min 1 chars] (required)
  instructions: string (required)
  memory?: object
    enabled: boolean (required)
    storage: \"n8n\" | \"sqlite\" | \"postgres\" (required)
    connection?: Record<string, unknown>
    lastMessages?: integer [1..200]
    semanticRecall?: object
      topK: integer [1..100] (required)
      scope?: \"thread\" | \"resource\"
      messageRange?: object
        before: integer [min 0] (required)
        after: integer [min 0] (required)
      embedder?: string
  tools?: array with items any of:
    | (type = \"custom\")
      id: string [min 1 chars, pattern: ^[a-z0-9_-]+$] (required)
      requireApproval?: boolean
    | (type = \"workflow\")
      workflow: string [min 1 chars] (required)
      name?: string
      description?: string
      requireApproval?: boolean
      allOutputs?: boolean
    | (type = \"node\")
      name: string [min 1 chars] (required)
      description?: string
      node: object (required)
        nodeType: string [min 1 chars] (required)
        nodeTypeVersion: number (required)
        nodeParameters?: Record<string, unknown>
        credentials?: Record<string, { id: string, name: string }>
      inputSchema: object (required)
        type?: \"object\"
        properties?: Record<string, unknown>
        required?: array of <string>
      requireApproval?: boolean
  providerTools?: Record<string, Record<string, unknown>>
  config?: object
    thinking?: object
      provider: \"anthropic\" | \"openai\" (required)
      budgetTokens?: integer
      reasoningEffort?: string
    toolCallConcurrency?: integer [1..20]
    requireToolApproval?: boolean
</details>

The builder has access to two groups of tools:

Config tools (JSON mode)

ToolWhat it does
write_configFull replace — accepts a complete agent config as a JSON string, validates it, and persists it
patch_configIncremental update — accepts RFC 6902 JSON Patch operations, applies them to the current config via fast-json-patch, validates the result, and persists it

Both tools return { ok: true } on success or { ok: false, errors } with structured path/message/expected/received fields on failure. patch_config additionally returns a stage ("parse", "patch", or "schema") indicating where the failure occurred.

Shared tools (always present)

ToolWhat it does
build_custom_toolWrites or updates a custom TypeScript tool using the Tool builder API; validates the code in a sandbox before saving
list_credentialsLists credentials available in the project — call this before generating config
list_workflowsLists project workflows with compatible trigger types (manual, chat, schedule, etc.)
search_nodesSearches for n8n integration nodes by name or service
get_node_typesReturns the full parameter schema for specific node IDs found via search_nodes

Validation pipeline

write_config and patch_config pass every config through the same pipeline:

  1. tryParseConfigJson — catches JSON.parse failures with position info
  2. AgentJsonConfigSchema.safeParse (Zod) — validates schema shape and field constraints
  3. agentsService.updateConfig — persists to the database

Zod errors are normalized by formatZodErrors into { path, message, expected, received } objects so the LLM can self-correct.

Related Linear tickets, Github issues, and Community forum posts

<!-- Include links to **Linear ticket** or Github issue or Community forum post. Important in order to close *automatically* and provide context to reviewers. https://linear.app/n8n/issue/[TICKET-ID] --> <!-- Use "closes #<issue-number>", "fixes #<issue-number>", or "resolves #<issue-number>" to automatically close issues when the PR is merged. -->

Review / Merge checklist

  • I have seen this code, I have run this code, and I take responsibility for this code.
  • PR title and summary are descriptive. (conventions) <!-- **Remember, the title automatically goes into the changelog. Use `(no-changelog)` otherwise.** -->
  • Docs updated or follow-up ticket created.
  • Tests included. <!-- A bug is not considered fixed, unless a test is added to prevent it from happening again. A feature is not complete without tests. -->
  • PR Labeled with Backport to Beta, Backport to Stable, or Backport to v1 (if the PR is an urgent fix that needs to be backported)
© 2026 · via Gitpulse