1package main
2
3import (
4 "encoding/json"
5 "fmt"
6 "os"
7
8 "github.com/opencode-ai/opencode/internal/config"
9 "github.com/opencode-ai/opencode/internal/llm/models"
10)
11
12// JSONSchemaType represents a JSON Schema type
13type JSONSchemaType struct {
14 Type string `json:"type,omitempty"`
15 Description string `json:"description,omitempty"`
16 Properties map[string]any `json:"properties,omitempty"`
17 Required []string `json:"required,omitempty"`
18 AdditionalProperties any `json:"additionalProperties,omitempty"`
19 Enum []any `json:"enum,omitempty"`
20 Items map[string]any `json:"items,omitempty"`
21 OneOf []map[string]any `json:"oneOf,omitempty"`
22 AnyOf []map[string]any `json:"anyOf,omitempty"`
23 Default any `json:"default,omitempty"`
24}
25
26func main() {
27 schema := generateSchema()
28
29 // Pretty print the schema
30 encoder := json.NewEncoder(os.Stdout)
31 encoder.SetIndent("", " ")
32 if err := encoder.Encode(schema); err != nil {
33 fmt.Fprintf(os.Stderr, "Error encoding schema: %v\n", err)
34 os.Exit(1)
35 }
36}
37
38func generateSchema() map[string]any {
39 schema := map[string]any{
40 "$schema": "http://json-schema.org/draft-07/schema#",
41 "title": "OpenCode Configuration",
42 "description": "Configuration schema for the OpenCode application",
43 "type": "object",
44 "properties": map[string]any{},
45 }
46
47 // Add Data configuration
48 schema["properties"].(map[string]any)["data"] = map[string]any{
49 "type": "object",
50 "description": "Storage configuration",
51 "properties": map[string]any{
52 "directory": map[string]any{
53 "type": "string",
54 "description": "Directory where application data is stored",
55 "default": ".opencode",
56 },
57 },
58 "required": []string{"directory"},
59 }
60
61 // Add working directory
62 schema["properties"].(map[string]any)["wd"] = map[string]any{
63 "type": "string",
64 "description": "Working directory for the application",
65 }
66
67 // Add debug flags
68 schema["properties"].(map[string]any)["debug"] = map[string]any{
69 "type": "boolean",
70 "description": "Enable debug mode",
71 "default": false,
72 }
73
74 schema["properties"].(map[string]any)["debugLSP"] = map[string]any{
75 "type": "boolean",
76 "description": "Enable LSP debug mode",
77 "default": false,
78 }
79
80 schema["properties"].(map[string]any)["contextPaths"] = map[string]any{
81 "type": "array",
82 "description": "Context paths for the application",
83 "items": map[string]any{
84 "type": "string",
85 },
86 "default": []string{
87 ".github/copilot-instructions.md",
88 ".cursorrules",
89 ".cursor/rules/",
90 "CLAUDE.md",
91 "CLAUDE.local.md",
92 "opencode.md",
93 "opencode.local.md",
94 "OpenCode.md",
95 "OpenCode.local.md",
96 "OPENCODE.md",
97 "OPENCODE.local.md",
98 },
99 }
100
101 schema["properties"].(map[string]any)["tui"] = map[string]any{
102 "type": "object",
103 "description": "Terminal User Interface configuration",
104 "properties": map[string]any{
105 "theme": map[string]any{
106 "type": "string",
107 "description": "TUI theme name",
108 "default": "opencode",
109 "enum": []string{
110 "opencode",
111 "catppuccin",
112 "dracula",
113 "flexoki",
114 "gruvbox",
115 "monokai",
116 "onedark",
117 "tokyonight",
118 "tron",
119 },
120 },
121 },
122 }
123
124 // Add MCP servers
125 schema["properties"].(map[string]any)["mcpServers"] = map[string]any{
126 "type": "object",
127 "description": "Model Control Protocol server configurations",
128 "additionalProperties": map[string]any{
129 "type": "object",
130 "description": "MCP server configuration",
131 "properties": map[string]any{
132 "command": map[string]any{
133 "type": "string",
134 "description": "Command to execute for the MCP server",
135 },
136 "env": map[string]any{
137 "type": "array",
138 "description": "Environment variables for the MCP server",
139 "items": map[string]any{
140 "type": "string",
141 },
142 },
143 "args": map[string]any{
144 "type": "array",
145 "description": "Command arguments for the MCP server",
146 "items": map[string]any{
147 "type": "string",
148 },
149 },
150 "type": map[string]any{
151 "type": "string",
152 "description": "Type of MCP server",
153 "enum": []string{"stdio", "sse"},
154 "default": "stdio",
155 },
156 "url": map[string]any{
157 "type": "string",
158 "description": "URL for SSE type MCP servers",
159 },
160 "headers": map[string]any{
161 "type": "object",
162 "description": "HTTP headers for SSE type MCP servers",
163 "additionalProperties": map[string]any{
164 "type": "string",
165 },
166 },
167 },
168 "required": []string{"command"},
169 },
170 }
171
172 // Add providers
173 providerSchema := map[string]any{
174 "type": "object",
175 "description": "LLM provider configurations",
176 "additionalProperties": map[string]any{
177 "type": "object",
178 "description": "Provider configuration",
179 "properties": map[string]any{
180 "apiKey": map[string]any{
181 "type": "string",
182 "description": "API key for the provider",
183 },
184 "disabled": map[string]any{
185 "type": "boolean",
186 "description": "Whether the provider is disabled",
187 "default": false,
188 },
189 },
190 },
191 }
192
193 // Add known providers
194 knownProviders := []string{
195 string(models.ProviderAnthropic),
196 string(models.ProviderOpenAI),
197 string(models.ProviderGemini),
198 string(models.ProviderGROQ),
199 string(models.ProviderOpenRouter),
200 string(models.ProviderBedrock),
201 string(models.ProviderAzure),
202 string(models.ProviderVertexAI),
203 }
204
205 providerSchema["additionalProperties"].(map[string]any)["properties"].(map[string]any)["provider"] = map[string]any{
206 "type": "string",
207 "description": "Provider type",
208 "enum": knownProviders,
209 }
210
211 schema["properties"].(map[string]any)["providers"] = providerSchema
212
213 // Add agents
214 agentSchema := map[string]any{
215 "type": "object",
216 "description": "Agent configurations",
217 "additionalProperties": map[string]any{
218 "type": "object",
219 "description": "Agent configuration",
220 "properties": map[string]any{
221 "model": map[string]any{
222 "type": "string",
223 "description": "Model ID for the agent",
224 },
225 "maxTokens": map[string]any{
226 "type": "integer",
227 "description": "Maximum tokens for the agent",
228 "minimum": 1,
229 },
230 "reasoningEffort": map[string]any{
231 "type": "string",
232 "description": "Reasoning effort for models that support it (OpenAI, Anthropic)",
233 "enum": []string{"low", "medium", "high"},
234 },
235 },
236 "required": []string{"model"},
237 },
238 }
239
240 // Add model enum
241 modelEnum := []string{}
242 for modelID := range models.SupportedModels {
243 modelEnum = append(modelEnum, string(modelID))
244 }
245 agentSchema["additionalProperties"].(map[string]any)["properties"].(map[string]any)["model"].(map[string]any)["enum"] = modelEnum
246
247 // Add specific agent properties
248 agentProperties := map[string]any{}
249 knownAgents := []string{
250 string(config.AgentCoder),
251 string(config.AgentTask),
252 string(config.AgentTitle),
253 }
254
255 for _, agentName := range knownAgents {
256 agentProperties[agentName] = map[string]any{
257 "$ref": "#/definitions/agent",
258 }
259 }
260
261 // Create a combined schema that allows both specific agents and additional ones
262 combinedAgentSchema := map[string]any{
263 "type": "object",
264 "description": "Agent configurations",
265 "properties": agentProperties,
266 "additionalProperties": agentSchema["additionalProperties"],
267 }
268
269 schema["properties"].(map[string]any)["agents"] = combinedAgentSchema
270 schema["definitions"] = map[string]any{
271 "agent": agentSchema["additionalProperties"],
272 }
273
274 // Add LSP configuration
275 schema["properties"].(map[string]any)["lsp"] = map[string]any{
276 "type": "object",
277 "description": "Language Server Protocol configurations",
278 "additionalProperties": map[string]any{
279 "type": "object",
280 "description": "LSP configuration for a language",
281 "properties": map[string]any{
282 "disabled": map[string]any{
283 "type": "boolean",
284 "description": "Whether the LSP is disabled",
285 "default": false,
286 },
287 "command": map[string]any{
288 "type": "string",
289 "description": "Command to execute for the LSP server",
290 },
291 "args": map[string]any{
292 "type": "array",
293 "description": "Command arguments for the LSP server",
294 "items": map[string]any{
295 "type": "string",
296 },
297 },
298 "options": map[string]any{
299 "type": "object",
300 "description": "Additional options for the LSP server",
301 },
302 },
303 "required": []string{"command"},
304 },
305 }
306
307 return schema
308}