{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "title": "Vally Project Configuration",
    "description": "Schema for .vally.yaml project configuration files",
    "type": "object",
    "$defs": {
        "Duration": {
            "type": "string",
            "pattern": "^\\s*\\d+\\.?\\d*\\s*(ms|s|m|h|d)\\s*$",
            "description": "Duration string with a unit suffix (ms, s, m, h, d), e.g. \"5m\", \"300s\", \"500ms\""
        },
        "EnvironmentConfig": {
            "type": "object",
            "description": "Named environment — skills, seed files, and setup commands",
            "properties": {
                "skills": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "description": "Skill names to load"
                },
                "files": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "src": {
                                "type": "string"
                            },
                            "dest": {
                                "type": "string"
                            },
                            "dest_root": {
                                "type": "string",
                                "enum": ["workdir", "assets"],
                                "description": "Root the dest is resolved against: the graded workspace (default) or the managed assets directory staged outside it"
                            }
                        },
                        "required": ["src", "dest"],
                        "additionalProperties": false
                    },
                    "description": "Files to copy into the workspace"
                },
                "commands": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "description": "Setup commands to run before evaluation"
                },
                "commandTimeout": {
                    "$ref": "#/$defs/Duration",
                    "description": "Per-command timeout for setup commands with unit suffix (e.g. \"2m\", \"90s\"). Must be a positive duration; 0 is rejected because it would disable the timeout. Defaults to 60s when unset."
                },
                "git": {
                    "description": "Git configuration for fixture data: a local worktree or a remote clone",
                    "oneOf": [
                        {
                            "type": "object",
                            "description": "Local worktree of a source repository",
                            "properties": {
                                "type": {
                                    "type": "string",
                                    "const": "worktree"
                                },
                                "ref": {
                                    "type": "string",
                                    "minLength": 1,
                                    "description": "A commit-ish value (tag, commit, branch)"
                                },
                                "source": {
                                    "type": "string",
                                    "minLength": 1,
                                    "description": "Path to the local repo used as worktree source"
                                },
                                "timeout": {
                                    "$ref": "#/$defs/Duration",
                                    "description": "Timeout for the local git steps that materialize the worktree (add, remove), with unit suffix (e.g. \"5m\", \"300s\"). Raise it for very large repos. Must be a positive duration; 0 is rejected. Defaults to 5m when unset."
                                }
                            },
                            "required": ["type", "ref", "source"],
                            "additionalProperties": false
                        },
                        {
                            "type": "object",
                            "description": "Clone of a remote repository at a given ref",
                            "properties": {
                                "type": {
                                    "type": "string",
                                    "const": "clone"
                                },
                                "url": {
                                    "type": "string",
                                    "minLength": 1,
                                    "description": "Remote repository URL to clone: http(s), ssh, git, file://, or scp-style git@host:path"
                                },
                                "ref": {
                                    "type": "string",
                                    "minLength": 1,
                                    "description": "A commit-ish value (tag, commit, branch) to check out; defaults to the remote's default branch"
                                },
                                "shallow": {
                                    "oneOf": [{ "type": "boolean" }, { "type": "integer", "minimum": 1 }],
                                    "description": "Shallow-clone depth: true for depth 1, or an explicit positive integer"
                                },
                                "sparse": {
                                    "type": "array",
                                    "items": {
                                        "type": "string",
                                        "minLength": 1
                                    },
                                    "description": "Sparse-checkout cone paths to materialize"
                                },
                                "timeout": {
                                    "$ref": "#/$defs/Duration",
                                    "description": "Timeout for each local git step of the clone (init, remote add, sparse-checkout, checkout), with unit suffix (e.g. \"5m\", \"300s\"). Does not apply to the network fetch, which keeps its own budget. Must be a positive duration; 0 is rejected. Defaults to 5m when unset."
                                }
                            },
                            "required": ["type", "url"],
                            "additionalProperties": false
                        }
                    ]
                },
                "mcpServers": {
                    "type": "object",
                    "description": "Named MCP server configurations to attach to the session",
                    "additionalProperties": {
                        "oneOf": [
                            {
                                "type": "object",
                                "description": "MCP server launched as a child process (stdio transport)",
                                "properties": {
                                    "type": {
                                        "type": "string",
                                        "const": "stdio"
                                    },
                                    "command": {
                                        "type": "string",
                                        "description": "Executable to run"
                                    },
                                    "args": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        },
                                        "description": "Arguments passed to the command"
                                    },
                                    "env": {
                                        "type": "object",
                                        "additionalProperties": {
                                            "type": "string"
                                        },
                                        "description": "Extra environment variables for the child process"
                                    },
                                    "cwd": {
                                        "type": "string",
                                        "description": "Working directory for the child process"
                                    },
                                    "timeout": {
                                        "type": "string",
                                        "description": "Timeout with unit suffix (e.g. \"30s\", \"5000ms\", \"1m\")"
                                    }
                                },
                                "required": ["type", "command"],
                                "additionalProperties": false
                            },
                            {
                                "type": "object",
                                "description": "MCP server accessed over HTTP or SSE",
                                "properties": {
                                    "type": {
                                        "type": "string",
                                        "enum": ["http", "sse"]
                                    },
                                    "url": {
                                        "type": "string",
                                        "description": "Server endpoint URL"
                                    },
                                    "headers": {
                                        "type": "object",
                                        "additionalProperties": {
                                            "type": "string"
                                        },
                                        "description": "Extra HTTP headers (e.g. auth tokens)"
                                    },
                                    "timeout": {
                                        "type": "string",
                                        "description": "Timeout with unit suffix (e.g. \"30s\", \"5000ms\", \"1m\")"
                                    }
                                },
                                "required": ["type", "url"],
                                "additionalProperties": false
                            }
                        ]
                    }
                },
                "env": {
                    "type": "object",
                    "propertyNames": {
                        "pattern": "^[^=\\s\\u0000-\\u001F\\u007F-\\u009F]+$"
                    },
                    "additionalProperties": {
                        "type": "string",
                        "pattern": "^[^\\u0000]*$"
                    },
                    "description": "Environment variables to set on the agent process"
                }
            },
            "additionalProperties": false
        },
        "SuiteConfig": {
            "type": "object",
            "description": "Named suite — scopes evals by file patterns and/or tag-based filters",
            "properties": {
                "description": {
                    "type": "string"
                },
                "filter": {
                    "type": "object",
                    "additionalProperties": {
                        "oneOf": [
                            {
                                "type": "string"
                            },
                            {
                                "type": "array",
                                "items": {
                                    "type": "string"
                                }
                            }
                        ]
                    }
                },
                "evals": {
                    "description": "Eval file paths or glob patterns to include in this suite (resolved relative to project root)",
                    "oneOf": [
                        {
                            "type": "string"
                        },
                        {
                            "type": "array",
                            "items": {
                                "type": "string"
                            },
                            "minItems": 1
                        }
                    ]
                }
            },
            "anyOf": [
                {
                    "required": ["filter"]
                },
                {
                    "required": ["evals"]
                }
            ],
            "additionalProperties": false
        }
    },
    "properties": {
        "paths": {
            "type": "object",
            "description": "Where to find skills, evals, and results",
            "properties": {
                "skills": {
                    "description": "Skill directory or directories",
                    "oneOf": [
                        {
                            "type": "string"
                        },
                        {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        }
                    ]
                },
                "evals": {
                    "description": "Evals directory or directories",
                    "oneOf": [
                        {
                            "type": "string"
                        },
                        {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        }
                    ]
                },
                "results": {
                    "type": "string",
                    "description": "Results output directory"
                },
                "evalFilenames": {
                    "description": "Filename patterns for eval file discovery (default: [\"eval.yaml\", \"eval.yml\"])",
                    "oneOf": [
                        {
                            "type": "string"
                        },
                        {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        }
                    ]
                }
            },
            "additionalProperties": false
        },
        "environments": {
            "type": "object",
            "description": "Named environments that can be referenced from eval YAML files",
            "additionalProperties": {
                "$ref": "#/$defs/EnvironmentConfig"
            }
        },
        "suites": {
            "type": "object",
            "description": "Named suites — tag-based filters for selecting evals and stimuli to run",
            "additionalProperties": {
                "$ref": "#/$defs/SuiteConfig"
            }
        },
        "params": {
            "type": "object",
            "description": "Project-wide parameter defaults. Values defined here are available to all evals via ${KEY} placeholders. Eval-level params files override these.",
            "propertyNames": { "pattern": "^[A-Za-z_]\\w*$" },
            "additionalProperties": {
                "oneOf": [
                    {
                        "type": "string"
                    },
                    {
                        "type": "number"
                    },
                    {
                        "type": "boolean"
                    },
                    {
                        "type": "array",
                        "items": {
                            "oneOf": [{ "type": "string" }, { "type": "number" }, { "type": "boolean" }]
                        },
                        "minItems": 1
                    }
                ]
            }
        }
    },
    "additionalProperties": false
}
