{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "maxConcurrentBuilds": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "langfuse": {
      "type": "object",
      "properties": {
        "enabled": {
          "type": "boolean"
        },
        "publicKey": {
          "type": "string"
        },
        "secretKey": {
          "type": "string"
        },
        "host": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "agents": {
      "type": "object",
      "properties": {
        "maxTurns": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 9007199254740991
        },
        "maxContinuations": {
          "type": "integer",
          "minimum": 0,
          "maximum": 9007199254740991
        },
        "permissionMode": {
          "type": "string",
          "enum": [
            "bypass",
            "default"
          ]
        },
        "settingSources": {
          "minItems": 1,
          "type": "array",
          "items": {
            "type": "string",
            "enum": [
              "user",
              "project",
              "local"
            ]
          }
        },
        "bare": {
          "type": "boolean"
        },
        "promptDir": {
          "description": "Directory of .md files that shadow bundled prompts by name match",
          "type": "string"
        },
        "tiers": {
          "description": "Tier recipes — every tier referenced by any role must be declared",
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {
            "type": "object",
            "properties": {
              "harness": {
                "type": "string",
                "enum": [
                  "claude-sdk",
                  "pi"
                ],
                "description": "Which harness to run for roles in this tier"
              },
              "pi": {
                "description": "Pi-specific configuration (only when harness === \"pi\")",
                "type": "object",
                "properties": {
                  "provider": {
                    "description": "Pi provider name (required when used in a pi tier)",
                    "type": "string"
                  },
                  "apiKey": {
                    "description": "API key for the Pi provider",
                    "type": "string"
                  },
                  "thinkingLevel": {
                    "description": "Thinking level for Pi agents",
                    "type": "string",
                    "enum": [
                      "off",
                      "low",
                      "medium",
                      "high",
                      "xhigh"
                    ]
                  },
                  "resources": {
                    "description": "Whether ambient Pi resources (project/user/global extensions, skills, prompts, themes) are loaded into eforge agent sessions. Default 'isolated' suppresses all ambient resources; 'ambient' opts in to loading them (use with care — project-local Pi extensions must guard TUI state access for headless SDK contexts).",
                    "type": "string",
                    "enum": [
                      "isolated",
                      "ambient"
                    ]
                  },
                  "extensions": {
                    "description": "Pi extension configuration",
                    "type": "object",
                    "properties": {
                      "autoDiscover": {
                        "description": "Automatically discover Pi extensions",
                        "type": "boolean"
                      },
                      "include": {
                        "description": "Extension names to include",
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "exclude": {
                        "description": "Extension names to exclude",
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "paths": {
                        "description": "Explicit extension directory paths to load",
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    },
                    "additionalProperties": false
                  },
                  "compaction": {
                    "description": "Context compaction settings",
                    "type": "object",
                    "properties": {
                      "enabled": {
                        "description": "Enable context compaction",
                        "type": "boolean"
                      },
                      "threshold": {
                        "description": "Token threshold before compaction triggers",
                        "type": "integer",
                        "exclusiveMinimum": 0,
                        "maximum": 9007199254740991
                      }
                    },
                    "additionalProperties": false
                  },
                  "retry": {
                    "description": "Retry configuration for Pi API calls",
                    "type": "object",
                    "properties": {
                      "maxRetries": {
                        "description": "Maximum retry attempts",
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9007199254740991
                      },
                      "backoffMs": {
                        "description": "Initial backoff in milliseconds",
                        "type": "integer",
                        "exclusiveMinimum": 0,
                        "maximum": 9007199254740991
                      }
                    },
                    "additionalProperties": false
                  }
                },
                "additionalProperties": false
              },
              "claudeSdk": {
                "description": "Claude SDK-specific configuration (only when harness === \"claude-sdk\")",
                "type": "object",
                "properties": {
                  "disableSubagents": {
                    "description": "Disable the Task tool so agents cannot spawn subagents. Defaults to true. Claude SDK harness only.",
                    "type": "boolean"
                  }
                },
                "additionalProperties": false
              },
              "model": {
                "type": "string",
                "description": "Model identifier for this tier (provider is taken from pi.provider for pi)"
              },
              "effort": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high",
                  "xhigh",
                  "max"
                ],
                "description": "Effort level for roles in this tier"
              },
              "thinking": {
                "description": "When true, request thinking; coerced to adaptive for adaptive-only models",
                "type": "boolean"
              },
              "fallbackModel": {
                "description": "Fallback model id when primary is unavailable",
                "type": "string"
              },
              "maxTurns": {
                "description": "Default maxTurns for roles in this tier",
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              "allowedTools": {
                "description": "Whitelist of allowed tool names",
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "disallowedTools": {
                "description": "Blacklist of disallowed tool names",
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "promptAppend": {
                "description": "Text appended to every agent prompt in this tier after variable substitution",
                "type": "string"
              },
              "toolbelt": {
                "description": "Toolbelt name to activate for roles in this tier (must be declared in tools.toolbelts, or \"none\" to disable)",
                "type": "string"
              },
              "choices": {
                "type": "object",
                "propertyNames": {
                  "type": "string",
                  "pattern": "^[a-z][a-z0-9-]{0,63}$"
                },
                "additionalProperties": {
                  "type": "object",
                  "properties": {
                    "harness": {
                      "type": "string",
                      "enum": [
                        "claude-sdk",
                        "pi"
                      ],
                      "description": "Which harness to run for roles in this tier"
                    },
                    "pi": {
                      "description": "Pi-specific configuration (only when harness === \"pi\")",
                      "type": "object",
                      "properties": {
                        "provider": {
                          "description": "Pi provider name (required when used in a pi tier)",
                          "type": "string"
                        },
                        "apiKey": {
                          "description": "API key for the Pi provider",
                          "type": "string"
                        },
                        "thinkingLevel": {
                          "description": "Thinking level for Pi agents",
                          "type": "string",
                          "enum": [
                            "off",
                            "low",
                            "medium",
                            "high",
                            "xhigh"
                          ]
                        },
                        "resources": {
                          "description": "Whether ambient Pi resources (project/user/global extensions, skills, prompts, themes) are loaded into eforge agent sessions. Default 'isolated' suppresses all ambient resources; 'ambient' opts in to loading them (use with care — project-local Pi extensions must guard TUI state access for headless SDK contexts).",
                          "type": "string",
                          "enum": [
                            "isolated",
                            "ambient"
                          ]
                        },
                        "extensions": {
                          "description": "Pi extension configuration",
                          "type": "object",
                          "properties": {
                            "autoDiscover": {
                              "description": "Automatically discover Pi extensions",
                              "type": "boolean"
                            },
                            "include": {
                              "description": "Extension names to include",
                              "type": "array",
                              "items": {
                                "type": "string"
                              }
                            },
                            "exclude": {
                              "description": "Extension names to exclude",
                              "type": "array",
                              "items": {
                                "type": "string"
                              }
                            },
                            "paths": {
                              "description": "Explicit extension directory paths to load",
                              "type": "array",
                              "items": {
                                "type": "string"
                              }
                            }
                          },
                          "additionalProperties": false
                        },
                        "compaction": {
                          "description": "Context compaction settings",
                          "type": "object",
                          "properties": {
                            "enabled": {
                              "description": "Enable context compaction",
                              "type": "boolean"
                            },
                            "threshold": {
                              "description": "Token threshold before compaction triggers",
                              "type": "integer",
                              "exclusiveMinimum": 0,
                              "maximum": 9007199254740991
                            }
                          },
                          "additionalProperties": false
                        },
                        "retry": {
                          "description": "Retry configuration for Pi API calls",
                          "type": "object",
                          "properties": {
                            "maxRetries": {
                              "description": "Maximum retry attempts",
                              "type": "integer",
                              "minimum": 0,
                              "maximum": 9007199254740991
                            },
                            "backoffMs": {
                              "description": "Initial backoff in milliseconds",
                              "type": "integer",
                              "exclusiveMinimum": 0,
                              "maximum": 9007199254740991
                            }
                          },
                          "additionalProperties": false
                        }
                      },
                      "additionalProperties": false
                    },
                    "claudeSdk": {
                      "description": "Claude SDK-specific configuration (only when harness === \"claude-sdk\")",
                      "type": "object",
                      "properties": {
                        "disableSubagents": {
                          "description": "Disable the Task tool so agents cannot spawn subagents. Defaults to true. Claude SDK harness only.",
                          "type": "boolean"
                        }
                      },
                      "additionalProperties": false
                    },
                    "model": {
                      "type": "string",
                      "description": "Model identifier for this tier (provider is taken from pi.provider for pi)"
                    },
                    "effort": {
                      "type": "string",
                      "enum": [
                        "low",
                        "medium",
                        "high",
                        "xhigh",
                        "max"
                      ],
                      "description": "Effort level for roles in this tier"
                    },
                    "thinking": {
                      "description": "When true, request thinking; coerced to adaptive for adaptive-only models",
                      "type": "boolean"
                    },
                    "fallbackModel": {
                      "description": "Fallback model id when primary is unavailable",
                      "type": "string"
                    },
                    "maxTurns": {
                      "description": "Default maxTurns for roles in this tier",
                      "type": "integer",
                      "exclusiveMinimum": 0,
                      "maximum": 9007199254740991
                    },
                    "allowedTools": {
                      "description": "Whitelist of allowed tool names",
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "disallowedTools": {
                      "description": "Blacklist of disallowed tool names",
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "promptAppend": {
                      "description": "Text appended to every agent prompt in this tier after variable substitution",
                      "type": "string"
                    },
                    "toolbelt": {
                      "description": "Toolbelt name to activate for roles in this tier (must be declared in tools.toolbelts, or \"none\" to disable)",
                      "type": "string"
                    }
                  },
                  "additionalProperties": false
                }
              },
              "routing": {
                "type": "object",
                "properties": {
                  "rules": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string",
                          "minLength": 1
                        },
                        "choice": {
                          "type": "string",
                          "minLength": 1
                        },
                        "when": {
                          "type": "object",
                          "properties": {
                            "roles": {
                              "minItems": 1,
                              "type": "array",
                              "items": {
                                "type": "string",
                                "enum": [
                                  "planner",
                                  "builder",
                                  "reviewer",
                                  "review-fixer",
                                  "evaluator",
                                  "plan-reviewer",
                                  "plan-evaluator",
                                  "validation-fixer",
                                  "merge-conflict-resolver",
                                  "staleness-assessor",
                                  "formatter",
                                  "doc-author",
                                  "doc-syncer",
                                  "test-writer",
                                  "tester",
                                  "prd-validator",
                                  "dependency-detector",
                                  "gap-closer",
                                  "recovery-analyst"
                                ]
                              }
                            },
                            "phase": {
                              "minItems": 1,
                              "type": "array",
                              "items": {
                                "type": "string",
                                "minLength": 1
                              }
                            },
                            "stage": {
                              "minItems": 1,
                              "type": "array",
                              "items": {
                                "type": "string",
                                "minLength": 1
                              }
                            },
                            "pathGlobs": {
                              "minItems": 1,
                              "type": "array",
                              "items": {
                                "type": "string",
                                "minLength": 1
                              }
                            },
                            "keywords": {
                              "minItems": 1,
                              "type": "array",
                              "items": {
                                "type": "string",
                                "minLength": 1
                              }
                            },
                            "shardIds": {
                              "minItems": 1,
                              "type": "array",
                              "items": {
                                "type": "string",
                                "minLength": 1
                              }
                            },
                            "shardRoots": {
                              "minItems": 1,
                              "type": "array",
                              "items": {
                                "type": "string",
                                "minLength": 1
                              }
                            }
                          },
                          "additionalProperties": false
                        }
                      },
                      "required": [
                        "name",
                        "choice",
                        "when"
                      ],
                      "additionalProperties": false
                    }
                  }
                },
                "required": [
                  "rules"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "harness",
              "model",
              "effort"
            ],
            "additionalProperties": false,
            "description": "A self-contained tier recipe (harness + model + effort + tuning) with optional runtime choices"
          }
        },
        "roles": {
          "description": "Per-agent role overrides",
          "type": "object",
          "propertyNames": {
            "type": "string",
            "enum": [
              "planner",
              "builder",
              "reviewer",
              "review-fixer",
              "evaluator",
              "plan-reviewer",
              "plan-evaluator",
              "validation-fixer",
              "merge-conflict-resolver",
              "staleness-assessor",
              "formatter",
              "doc-author",
              "doc-syncer",
              "test-writer",
              "tester",
              "prd-validator",
              "dependency-detector",
              "gap-closer",
              "recovery-analyst"
            ]
          },
          "additionalProperties": {
            "type": "object",
            "properties": {
              "tier": {
                "description": "Override the tier assignment for this role",
                "type": "string",
                "enum": [
                  "planning",
                  "implementation",
                  "review",
                  "evaluation"
                ]
              },
              "effort": {
                "description": "Override effort for this role",
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high",
                  "xhigh",
                  "max"
                ]
              },
              "thinking": {
                "description": "Override thinking for this role",
                "type": "boolean"
              },
              "maxTurns": {
                "description": "Override maxTurns for this role",
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              "allowedTools": {
                "description": "Override allowedTools for this role",
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "disallowedTools": {
                "description": "Override disallowedTools for this role",
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "promptAppend": {
                "description": "Text appended to this role's prompt after variable substitution",
                "type": "string"
              },
              "shards": {
                "description": "Parallel implementation shards (builder role only)",
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "minLength": 1,
                      "description": "Unique shard identifier within the plan"
                    },
                    "roots": {
                      "description": "Directory roots claimed by this shard (matched via path prefix)",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "minLength": 1
                      }
                    },
                    "files": {
                      "description": "Explicit file paths claimed by this shard",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "minLength": 1
                      }
                    }
                  },
                  "required": [
                    "id"
                  ],
                  "additionalProperties": false,
                  "description": "Scope definition for a single implementation shard"
                }
              }
            },
            "additionalProperties": false
          },
          "required": [
            "planner",
            "builder",
            "reviewer",
            "review-fixer",
            "evaluator",
            "plan-reviewer",
            "plan-evaluator",
            "validation-fixer",
            "merge-conflict-resolver",
            "staleness-assessor",
            "formatter",
            "doc-author",
            "doc-syncer",
            "test-writer",
            "tester",
            "prd-validator",
            "dependency-detector",
            "gap-closer",
            "recovery-analyst"
          ]
        }
      },
      "additionalProperties": false
    },
    "compile": {
      "type": "object",
      "properties": {
        "planningUnitParallelism": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 16
        },
        "planningUnitMaxDepth": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 8
        },
        "planningUnitMaxPromptSourceBytes": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 250000
        },
        "planningUnitMaxPromptBytes": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 500000
        },
        "planningUnitMaxObservedInputTokens": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 1000000
        },
        "planningUnitMaxObservedTurns": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 200
        },
        "planningUnitMaxCompactHandoffBytes": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 100000
        },
        "planningUnitMaxLocalExplorationToolUses": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 256
        },
        "planningUnitMaxCriteriaPerUnit": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 64
        },
        "planningUnitMaxSubsystemsPerUnit": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 32
        },
        "planningUnitMaxSplitAttemptsPerUnit": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 8
        },
        "planningSharedBriefMaxTotalBytes": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 200000
        },
        "planningSharedBriefMaxSectionBytes": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 50000
        },
        "planningSharedBriefMaxSectionsPerAtom": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 64
        },
        "directPrBaseSyncConflictAttempts": {
          "description": "Compatibility fallback for the direct non-stacked PR base-sync conflict-resolution attempt budget; clamped after landing.directPrBaseSync.conflictAttempts precedence is resolved.",
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 9007199254740991
        }
      },
      "additionalProperties": false,
      "description": "Compile planning-unit limits; direct PR base-sync budget fallback remains available for compatibility"
    },
    "build": {
      "type": "object",
      "properties": {
        "worktreeDir": {
          "type": "string"
        },
        "postMergeCommands": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "postMergeCommandTimeoutMs": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 9007199254740991
        },
        "maxValidationRetries": {
          "type": "integer",
          "minimum": 0,
          "maximum": 9007199254740991
        },
        "cleanupPlanFiles": {
          "type": "boolean"
        },
        "onSuccess": {
          "not": {}
        },
        "trunkBranch": {
          "type": "string"
        },
        "allowLocalMergeToTrunk": {
          "type": "boolean"
        },
        "validation": {
          "type": "object",
          "properties": {
            "allowNoCommands": {
              "description": "Allow builds with zero combined validation commands to pass instead of failing. Requires noCommandsReason.",
              "type": "boolean"
            },
            "noCommandsReason": {
              "description": "Required human-readable reason when allowNoCommands is true.",
              "type": "string"
            },
            "allowEmptyPrdDiff": {
              "description": "Allow PRD validation to pass when the diff is empty (no changes detected). Requires emptyPrdDiffReason.",
              "type": "boolean"
            },
            "emptyPrdDiffReason": {
              "description": "Required human-readable reason when allowEmptyPrdDiff is true.",
              "type": "string"
            },
            "allowNoAcceptanceCriteria": {
              "description": "Allow builds with no extractable acceptance criteria to pass instead of failing. Requires noAcceptanceCriteriaReason.",
              "type": "boolean"
            },
            "noAcceptanceCriteriaReason": {
              "description": "Required human-readable reason when allowNoAcceptanceCriteria is true.",
              "type": "string"
            },
            "acceptanceConflictPolicy": {
              "description": "Handle validator-reported acceptance criteria conflicts. Default: \"manual\".",
              "type": "string",
              "enum": [
                "fail",
                "manual",
                "auto-waive-narrow"
              ]
            },
            "allowNoCommittedChanges": {
              "description": "Allow builds that produce no committed changes to pass instead of failing. Requires noCommittedChangesReason.",
              "type": "boolean"
            },
            "noCommittedChangesReason": {
              "description": "Required human-readable reason when allowNoCommittedChanges is true.",
              "type": "string"
            }
          },
          "additionalProperties": false,
          "description": "Explicit validation waivers. Each waiver boolean requires a non-empty reason string."
        },
        "trunkSync": {
          "description": "Pre-compile trunk freshness gate. Fetches remote trunk before compile and selects a reproducible base SHA when the remote is ahead of the local trunk.",
          "type": "object",
          "properties": {
            "enabled": {
              "description": "Enable pre-compile trunk freshness gate. When true (default), fetches remote trunk before compile and uses the fetched SHA as the compile base when remote is ahead. Set false to disable for offline or local-only workflows.",
              "type": "boolean"
            },
            "remote": {
              "description": "Git remote to fetch the trunk branch from. Default: \"origin\".",
              "type": "string"
            },
            "strategy": {
              "description": "Base selection strategy. Only \"fetchedRemoteRef\" is supported: use the exact fetched commit SHA so the compile base is reproducible if the remote branch moves during the run. Default: \"fetchedRemoteRef\".",
              "type": "string",
              "const": "fetchedRemoteRef"
            },
            "onDiverged": {
              "description": "Policy when local and remote trunk have diverged (neither is an ancestor of the other). \"warn\": emit a diagnostic and fall back to local trunk (default). \"fail\": fail the build before compile. \"use-remote\": use the fetched remote SHA with a diagnostic.",
              "type": "string",
              "enum": [
                "warn",
                "fail",
                "use-remote"
              ]
            }
          },
          "additionalProperties": false
        }
      },
      "additionalProperties": false
    },
    "plan": {
      "type": "object",
      "properties": {
        "outputDir": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "plugins": {
      "type": "object",
      "properties": {
        "enabled": {
          "type": "boolean"
        },
        "include": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "exclude": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "paths": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "extensions": {
      "type": "object",
      "properties": {
        "enabled": {
          "description": "Enable native eforge extension discovery and loading",
          "type": "boolean"
        },
        "include": {
          "description": "Native extension names to include during auto-discovery",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "exclude": {
          "description": "Native extension names to exclude during auto-discovery",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "paths": {
          "description": "Explicit native extension module paths to load",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "eventHookTimeoutMs": {
          "description": "Default timeout in milliseconds for native extension event-hook handlers",
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 9007199254740991
        },
        "agentContextHookTimeoutMs": {
          "description": "Timeout in milliseconds for agent-context hook handlers (defaults to eventHookTimeoutMs)",
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 9007199254740991
        },
        "policyGateTimeoutMs": {
          "description": "Timeout in milliseconds for policy gate handlers (defaults to eventHookTimeoutMs)",
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 9007199254740991
        },
        "policyGateFailurePolicy": {
          "description": "Failure policy for thrown, timed-out, or invalid policy gate handlers",
          "type": "string",
          "enum": [
            "fail-open",
            "fail-closed"
          ]
        },
        "profileRouterTimeoutMs": {
          "description": "Timeout in milliseconds for profile router handlers (defaults to eventHookTimeoutMs)",
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 9007199254740991
        },
        "validationProviderTimeoutMs": {
          "description": "Timeout in milliseconds for validation provider handlers and commands (defaults to eventHookTimeoutMs)",
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 9007199254740991
        }
      },
      "additionalProperties": false,
      "description": "Native eforge extension configuration"
    },
    "prdQueue": {
      "type": "object",
      "properties": {
        "dir": {
          "type": "string"
        },
        "autoBuild": {
          "type": "boolean"
        },
        "watchPollIntervalMs": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 9007199254740991
        }
      },
      "additionalProperties": false
    },
    "daemon": {
      "type": "object",
      "properties": {
        "idleShutdownMs": {
          "type": "integer",
          "minimum": 0,
          "maximum": 9007199254740991
        }
      },
      "additionalProperties": false
    },
    "monitor": {
      "type": "object",
      "properties": {
        "retentionCount": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 9007199254740991
        }
      },
      "additionalProperties": false
    },
    "recovery": {
      "type": "object",
      "properties": {
        "autoResume": {
          "type": "object",
          "properties": {
            "enabled": {
              "description": "Opt in to daemon-owned bounded recovery auto-resume for high-confidence compiled-artifact continue-repair recommendations. Default: false; disabled policy consumers stop before mutation.",
              "type": "boolean"
            },
            "maxAttempts": {
              "description": "Maximum automatic continue-repair attempts per failed PRD before policy stops. Default: 1. Maximum: 3. Set 0 to audit decisions without mutation even when enabled.",
              "type": "integer",
              "minimum": 0,
              "maximum": 3
            }
          },
          "additionalProperties": false,
          "description": "Disabled-by-default bounded recovery auto-resume policy."
        }
      },
      "additionalProperties": false,
      "description": "Recovery automation settings. Manual recovery tools remain available regardless of this policy."
    },
    "hooks": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "event": {
            "type": "string"
          },
          "command": {
            "type": "string"
          },
          "timeout": {
            "default": 5000,
            "type": "number",
            "exclusiveMinimum": 0
          }
        },
        "required": [
          "event",
          "command",
          "timeout"
        ],
        "additionalProperties": false
      }
    },
    "tools": {
      "type": "object",
      "properties": {
        "toolbelts": {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {
            "type": "object",
            "properties": {
              "description": {
                "type": "string"
              },
              "mcpServers": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              }
            },
            "required": [
              "mcpServers"
            ],
            "additionalProperties": false
          }
        }
      },
      "additionalProperties": false
    },
    "stacking": {
      "type": "object",
      "properties": {
        "enabled": {
          "description": "Enable git-spice stacked PR support. When true, each build's artifact branch targets the parent artifact branch instead of the trunk, forming a linear stack of pull requests. Requires git-spice to be installed. Default: false.",
          "type": "boolean"
        },
        "provider": {
          "description": "Stack provider. Only \"git-spice\" is supported in v1.",
          "type": "string",
          "const": "git-spice"
        },
        "gitSpice": {
          "description": "git-spice provider settings.",
          "type": "object",
          "properties": {
            "command": {
              "description": "Path or name of the git-spice executable. Defaults to \"git-spice\" on PATH. Set this if git-spice is installed to a non-standard location or you use a wrapper script.",
              "type": "string"
            }
          },
          "additionalProperties": false
        },
        "sync": {
          "description": "Stack sync scheduling settings.",
          "type": "object",
          "properties": {
            "afterBuild": {
              "description": "When true and stacking is enabled, the daemon automatically triggers a stack sync after each successful build session completes. The sync runs as a daemon-owned operation with full active-build awareness. Default: false.",
              "type": "boolean"
            }
          },
          "additionalProperties": false
        }
      },
      "additionalProperties": false,
      "description": "Stacking configuration for git-spice backed stacked PRs. Set stacking.enabled: true to activate; each artifact branch PR then targets the parent artifact branch rather than trunk. PRD frontmatter fields stack_id (logical stack name) and stack_parent (parent PRD id) control the topology."
    },
    "landing": {
      "type": "object",
      "properties": {
        "action": {
          "description": "Landing action after a successful build. \"pr\" opens a GitHub pull request from the artifact branch targeting the resolved base branch (current base branch for non-stacked builds, parent artifact branch for stacked builds). \"merge\" merges the artifact branch into the base branch directly. \"leave\" commits to the artifact branch and exits without merging or opening a PR. Default: \"merge\".",
          "type": "string",
          "enum": [
            "pr",
            "merge",
            "leave"
          ]
        },
        "pr": {
          "type": "object",
          "properties": {
            "autoMerge": {
              "description": "GitHub PR auto-merge policy. \"always\": enable auto-merge on every PR unless the per-run landingAutoMerge flag is explicitly false. \"ask\": enable auto-merge only when the per-run landingAutoMerge flag is explicitly true. \"never\": never enable auto-merge and emit a skipped event. Default: \"ask\".",
              "type": "string",
              "enum": [
                "ask",
                "always",
                "never"
              ]
            }
          },
          "additionalProperties": false
        },
        "directPrBaseSync": {
          "type": "object",
          "properties": {
            "conflictAttempts": {
              "description": "Direct non-stacked PR base-sync conflict-resolution attempt budget; clamped to the supported range.",
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 9007199254740991
            }
          },
          "additionalProperties": false
        }
      },
      "additionalProperties": false,
      "description": "Publication action taken after all plans complete and validation passes."
    }
  },
  "additionalProperties": false
}
