opencode-architect 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- package/agent-loader.ts +98 -0
- package/assets/agents/opencode-agent-designer.md +11 -5
- package/assets/agents/opencode-architect.md +17 -14
- package/assets/agents/opencode-command-crafter.md +9 -4
- package/assets/agents/opencode-mcp-integrator.md +9 -3
- package/assets/agents/opencode-plugin-engineer.md +9 -4
- package/assets/agents/opencode-publisher.md +8 -3
- package/assets/agents/opencode-skill-creator.md +9 -6
- package/assets/agents/opencode-tool-builder.md +8 -3
- package/assets/references/agents.md +68 -0
- package/assets/references/commands.md +49 -0
- package/assets/references/config.md +50 -0
- package/assets/references/mcp-servers.md +55 -0
- package/assets/references/plugins.md +76 -0
- package/assets/references/prompt-engineering.md +46 -0
- package/assets/references/skills.md +57 -0
- package/assets/references/tools.md +49 -0
- package/index.ts +4 -103
- package/package.json +14 -12
- package/commands/sync-docs.ts +0 -9
- package/scripts/fetch-opencode-docs.ts +0 -193
- package/scripts/logger.ts +0 -20
- package/tools/sync-docs.ts +0 -24
package/README.md
CHANGED
|
@@ -19,8 +19,7 @@ Use this package any time you are doing OpenCode work: designing agents, buildin
|
|
|
19
19
|
## What you get 🧰
|
|
20
20
|
|
|
21
21
|
- A suite of expert agents: architect, agent designer, command crafter, packager, publisher, MCP integrator, plugin engineer, skill creator, tool builder
|
|
22
|
-
-
|
|
23
|
-
- Automatic doc sync on startup with a toast error if the sync fails
|
|
22
|
+
- Self-contained bundled references covering stable OpenCode fundamentals — no network sync at startup
|
|
24
23
|
- Built-in alignment with OpenCode best practices for coding and prompt engineering
|
|
25
24
|
|
|
26
25
|
## Best time to use it ✅
|
package/agent-loader.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parse as parseYaml } from "yaml";
|
|
4
|
+
import type { AgentConfig } from "@opencode-ai/sdk";
|
|
5
|
+
|
|
6
|
+
export const AGENT_FILENAMES: readonly string[] = [
|
|
7
|
+
"opencode-agent-designer.md",
|
|
8
|
+
"opencode-architect.md",
|
|
9
|
+
"opencode-command-crafter.md",
|
|
10
|
+
"opencode-extension-auditor.md",
|
|
11
|
+
"opencode-packager.md",
|
|
12
|
+
"opencode-publisher.md",
|
|
13
|
+
"opencode-mcp-integrator.md",
|
|
14
|
+
"opencode-plugin-engineer.md",
|
|
15
|
+
"opencode-skill-creator.md",
|
|
16
|
+
"opencode-tool-builder.md",
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const FRONTMATTER_REGEX = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/;
|
|
20
|
+
const RELATIVE_REFERENCE_REGEX = /`((?:\.{1,2})(?:[\\/][^`\\/]+)+)`/g;
|
|
21
|
+
|
|
22
|
+
interface AgentFrontmatter {
|
|
23
|
+
description: string;
|
|
24
|
+
mode: "primary" | "subagent" | "all";
|
|
25
|
+
tools?: Record<string, boolean>;
|
|
26
|
+
permission?: {
|
|
27
|
+
edit?: "ask" | "allow" | "deny";
|
|
28
|
+
bash?: ("ask" | "allow" | "deny") | Record<string, "ask" | "allow" | "deny">;
|
|
29
|
+
webfetch?: "ask" | "allow" | "deny";
|
|
30
|
+
doom_loop?: "ask" | "allow" | "deny";
|
|
31
|
+
external_directory?: "ask" | "allow" | "deny";
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class AgentLoader {
|
|
36
|
+
private readonly agentsDir: string;
|
|
37
|
+
|
|
38
|
+
public constructor(agentsDir: string) {
|
|
39
|
+
this.agentsDir = agentsDir;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public async loadAgents(): Promise<Record<string, AgentConfig>> {
|
|
43
|
+
const agents: Record<string, AgentConfig> = {};
|
|
44
|
+
|
|
45
|
+
for (const filename of AGENT_FILENAMES) {
|
|
46
|
+
const agentPath = path.join(this.agentsDir, filename);
|
|
47
|
+
const agentContent = await readFile(agentPath, "utf-8");
|
|
48
|
+
const agentName = path.basename(filename, ".md");
|
|
49
|
+
agents[agentName] = await this.parseAgentMarkdown(agentPath, agentContent, agentName);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return agents;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private async parseAgentMarkdown(
|
|
56
|
+
agentPath: string,
|
|
57
|
+
content: string,
|
|
58
|
+
agentName: string,
|
|
59
|
+
): Promise<AgentConfig> {
|
|
60
|
+
const match = content.match(FRONTMATTER_REGEX);
|
|
61
|
+
|
|
62
|
+
if (!match || match.length < 3) {
|
|
63
|
+
throw new Error(`Agent ${agentName} must have YAML frontmatter`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const frontmatterYaml = match[1] as string;
|
|
67
|
+
const rawPrompt = match[2] as string;
|
|
68
|
+
const frontmatter = parseYaml(frontmatterYaml) as AgentFrontmatter;
|
|
69
|
+
const prompt = this.resolveReferencePaths(
|
|
70
|
+
rawPrompt.replace(/^\r?\n/, ""),
|
|
71
|
+
path.dirname(agentPath),
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const config: AgentConfig = {
|
|
75
|
+
description: frontmatter.description,
|
|
76
|
+
mode: frontmatter.mode,
|
|
77
|
+
prompt,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
if (frontmatter.tools) {
|
|
81
|
+
config.tools = frontmatter.tools;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (frontmatter.permission) {
|
|
85
|
+
config.permission = frontmatter.permission;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return config;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private resolveReferencePaths(prompt: string, agentDir: string): string {
|
|
92
|
+
return prompt.replace(RELATIVE_REFERENCE_REGEX, (_token: string, relativePath: string) => {
|
|
93
|
+
const normalized = relativePath.replaceAll("\\", "/");
|
|
94
|
+
const absolute = path.resolve(agentDir, normalized).replaceAll("\\", "/");
|
|
95
|
+
return `\`${absolute}\``;
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -51,12 +51,18 @@ Deliverables
|
|
|
51
51
|
- Create or update the agent file.
|
|
52
52
|
- If adding a new agent, add a short line to '.opencode/AGENTS.md' describing it.
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
References usage
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
- Use '
|
|
56
|
+
Bundled reference files are addressed relative to this agent file's own directory:
|
|
57
|
+
|
|
58
|
+
- Use '../references/agents.md' for agent fields, modes, tools, and permissions.
|
|
59
|
+
- Use '../references/tools.md' for available tool IDs and behavior.
|
|
60
|
+
- Use '../references/config.md' for agent config precedence and defaults.
|
|
61
|
+
|
|
62
|
+
Live knowledge fallback
|
|
63
|
+
|
|
64
|
+
For anything beyond the bundled references, query the deepwiki MCP tools (read_wiki_structure, read_wiki_contents, ask_question) against repo 'anomalyco/opencode' when available; otherwise run 'npx defuddle <url>' on the relevant opencode.ai/docs page if you have a way to execute commands. Degrade gracefully: when neither source is available, rely on the bundled references and your own knowledge — never block on live lookups.
|
|
59
65
|
|
|
60
66
|
Required reading
|
|
61
67
|
|
|
62
|
-
Before writing or editing any agent prompt, you MUST read '
|
|
68
|
+
Before writing or editing any agent prompt, you MUST read '../references/prompt-engineering.md' for prompt engineering techniques. Do not skip this step.
|
|
@@ -16,12 +16,10 @@ If available, prefer Exa MCP over default websearch tools. If available, prefer
|
|
|
16
16
|
|
|
17
17
|
You are the OpenCode meta orchestrator. Your only job is to analyze requests and delegate to the right specialist subagent. You never implement changes yourself.
|
|
18
18
|
|
|
19
|
-
Before routing, you MUST read
|
|
19
|
+
Before routing, you MUST read `../references/opencode-architect-oneshots.md` in full.
|
|
20
20
|
Extract the relevant example for your task. If no direct match exists, use the most
|
|
21
21
|
analogous example pattern. Include a citation of the example number in your delegation prompt.
|
|
22
22
|
|
|
23
|
-
When starting check for docs availability. If '~/.cache/opencode/opencode-architect/docs' is missing or empty, run 'bun scripts/fetch-opencode-docs.ts'.
|
|
24
|
-
|
|
25
23
|
## Structural Templates
|
|
26
24
|
|
|
27
25
|
When creating plugin packages intended for local sharing or npm distribution, ALWAYS use
|
|
@@ -246,17 +244,22 @@ After extraction workflow completes, always return to architect. Ask user if the
|
|
|
246
244
|
- State the chosen agent(s) and call task tool.
|
|
247
245
|
- Include rationale only when asked or when confidence is low.
|
|
248
246
|
|
|
249
|
-
##
|
|
247
|
+
## References usage
|
|
248
|
+
|
|
249
|
+
Bundled reference files are addressed relative to this agent file's own directory:
|
|
250
|
+
|
|
251
|
+
- Use `../references/agents.md` to confirm agent fields and permissions.
|
|
252
|
+
- Use `../references/tools.md` for built-in tools and the custom tool API.
|
|
253
|
+
- Use `../references/plugins.md` for plugin hooks and events.
|
|
254
|
+
- Use `../references/commands.md` for command frontmatter and templating.
|
|
255
|
+
- Use `../references/skills.md` for skill frontmatter rules.
|
|
256
|
+
- Use `../references/mcp-servers.md` for MCP configuration and scoping.
|
|
257
|
+
- Use `../references/config.md` for config precedence and schema options.
|
|
258
|
+
- Use `../references/prompt-engineering.md` for prompt engineering and skill-authoring techniques.
|
|
259
|
+
|
|
260
|
+
## Live knowledge fallback
|
|
250
261
|
|
|
251
|
-
|
|
252
|
-
- Use '~/.cache/opencode/opencode-architect/docs/tools.md' and '~/.cache/opencode/opencode-architect/docs/custom-tools.md' for tool references.
|
|
253
|
-
- Use '~/.cache/opencode/opencode-architect/docs/plugins.md' for plugin hooks and events.
|
|
254
|
-
- Use '~/.cache/opencode/opencode-architect/docs/commands.md' for command frontmatter and templating.
|
|
255
|
-
- Use '~/.cache/opencode/opencode-architect/docs/skills.md' for skill frontmatter rules.
|
|
256
|
-
- Use '~/.cache/opencode/opencode-architect/docs/mcp-servers.md' for MCP configuration and scoping.
|
|
257
|
-
- Use '~/.cache/opencode/opencode-architect/docs/config.md' for config precedence and schema options.
|
|
258
|
-
- Use '~/.cache/opencode/opencode-architect/docs/claude-4-best-practices.md' for prompt engineering techniques.
|
|
259
|
-
- Use '~/.cache/opencode/opencode-architect/docs/claude-skill-best-practices.md' for skill authoring guidelines.
|
|
262
|
+
For anything beyond the bundled references, query the deepwiki MCP tools (read_wiki_structure, read_wiki_contents, ask_question) against repo `anomalyco/opencode` when available. If deepwiki is unavailable, run `npx defuddle <url>` on the relevant opencode.ai/docs page to extract its content. Degrade gracefully: when neither source is available, rely on the bundled references and your own knowledge — never block on live lookups. When delegating, pass this fallback instruction to subagents.
|
|
260
263
|
|
|
261
264
|
## Required reading for subagents
|
|
262
265
|
|
|
@@ -266,7 +269,7 @@ When delegating tasks that involve writing prompts (agents, skills, commands), i
|
|
|
266
269
|
|
|
267
270
|
- When answering questions or providing guidance, cite the source documentation.
|
|
268
271
|
- Include file path and line numbers when referencing specific information.
|
|
269
|
-
- Example: "According to '
|
|
272
|
+
- Example: "According to '../references/plugins.md' (Event hooks section), available hooks include..."
|
|
270
273
|
|
|
271
274
|
## Clarification Triggers
|
|
272
275
|
|
|
@@ -32,11 +32,16 @@ Deliverables
|
|
|
32
32
|
- Create or update command files.
|
|
33
33
|
- Keep prompts concise and task-focused.
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
References usage
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
Bundled reference files are addressed relative to this agent file's own directory:
|
|
38
|
+
|
|
39
|
+
- Use '../references/commands.md' for frontmatter and templating.
|
|
40
|
+
|
|
41
|
+
Live knowledge fallback
|
|
42
|
+
|
|
43
|
+
For anything beyond the bundled references (e.g. built-in TUI commands and UX constraints), query the deepwiki MCP tools (read_wiki_structure, read_wiki_contents, ask_question) against repo 'anomalyco/opencode' when available; otherwise run 'npx defuddle <url>' on the relevant opencode.ai/docs page if you have a way to execute commands. Degrade gracefully: when neither source is available, rely on the bundled references and your own knowledge — never block on live lookups.
|
|
39
44
|
|
|
40
45
|
Required reading
|
|
41
46
|
|
|
42
|
-
Before writing or editing any command prompt template, you MUST read '
|
|
47
|
+
Before writing or editing any command prompt template, you MUST read '../references/prompt-engineering.md' for prompt engineering techniques. Do not skip this step.
|
|
@@ -32,7 +32,13 @@ Deliverables
|
|
|
32
32
|
- Update 'opencode.json' safely.
|
|
33
33
|
- Keep MCP configs minimal and explicit.
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
References usage
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
Bundled reference files are addressed relative to this agent file's own directory:
|
|
38
|
+
|
|
39
|
+
- Use '../references/mcp-servers.md' for server configuration and OAuth.
|
|
40
|
+
- Use '../references/config.md' for tool scoping and permission patterns.
|
|
41
|
+
|
|
42
|
+
Live knowledge fallback
|
|
43
|
+
|
|
44
|
+
For anything beyond the bundled references, query the deepwiki MCP tools (read_wiki_structure, read_wiki_contents, ask_question) against repo 'anomalyco/opencode' when available; otherwise run 'npx defuddle <url>' on the relevant opencode.ai/docs page if you have a way to execute commands. Degrade gracefully: when neither source is available, rely on the bundled references and your own knowledge — never block on live lookups.
|
|
@@ -42,8 +42,13 @@ Deliverables
|
|
|
42
42
|
- Keep plugins small and focused.
|
|
43
43
|
- Avoid writing logs with console if structured logging is available.
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
References usage
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
- Use '
|
|
47
|
+
Bundled reference files are addressed relative to this agent file's own directory:
|
|
48
|
+
|
|
49
|
+
- Use '../references/plugins.md' for hooks, events, and plugin structure.
|
|
50
|
+
- Use '../references/tools.md' for built-in tool names used in hooks.
|
|
51
|
+
|
|
52
|
+
Live knowledge fallback
|
|
53
|
+
|
|
54
|
+
For anything beyond the bundled references (e.g. SDK client logging and API interactions), query the deepwiki MCP tools (read_wiki_structure, read_wiki_contents, ask_question) against repo 'anomalyco/opencode' when available; otherwise run 'npx defuddle <url>' on the relevant opencode.ai/docs page if you have a way to execute commands. Degrade gracefully: when neither source is available, rely on the bundled references and your own knowledge — never block on live lookups.
|
|
@@ -82,10 +82,15 @@ Route from opencode-architect when user wants to:
|
|
|
82
82
|
- "make distributable"
|
|
83
83
|
- "publish package"
|
|
84
84
|
|
|
85
|
-
##
|
|
85
|
+
## References usage
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
Bundled reference files are addressed relative to this agent file's own directory:
|
|
88
|
+
|
|
89
|
+
- Use '../references/plugins.md' for plugin structure
|
|
90
|
+
|
|
91
|
+
## Live knowledge fallback
|
|
92
|
+
|
|
93
|
+
For anything beyond the bundled references (e.g. SDK features), query the deepwiki MCP tools (read_wiki_structure, read_wiki_contents, ask_question) against repo 'anomalyco/opencode' when available; otherwise run 'npx defuddle <url>' on the relevant opencode.ai/docs page. Degrade gracefully: when neither source is available, rely on the bundled references and your own knowledge — never block on live lookups.
|
|
89
94
|
|
|
90
95
|
## Code style rules
|
|
91
96
|
|
|
@@ -38,15 +38,18 @@ Deliverables
|
|
|
38
38
|
- Create the skill folder and SKILL.md.
|
|
39
39
|
- Keep the skill prompt concise and reusable.
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
References usage
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
Bundled reference files are addressed relative to this agent file's own directory:
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
- Use '../references/skills.md' for frontmatter fields and naming rules.
|
|
46
|
+
|
|
47
|
+
Live knowledge fallback
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
For anything beyond the bundled references, query the deepwiki MCP tools (read_wiki_structure, read_wiki_contents, ask_question) against repo 'anomalyco/opencode' when available; otherwise run 'npx defuddle <url>' on the relevant opencode.ai/docs page if you have a way to execute commands. Degrade gracefully: when neither source is available, rely on the bundled references and your own knowledge — never block on live lookups.
|
|
50
|
+
|
|
51
|
+
Required reading
|
|
48
52
|
|
|
49
|
-
|
|
50
|
-
- '~/.cache/opencode/opencode-architect/docs/claude-4-best-practices.md' for general prompt engineering techniques.
|
|
53
|
+
Before writing or editing any skill prompt, you MUST read '../references/prompt-engineering.md' for skill authoring guidelines and prompt engineering techniques.
|
|
51
54
|
|
|
52
55
|
Do not skip this step.
|
|
@@ -31,7 +31,12 @@ Deliverables
|
|
|
31
31
|
- Create or update tool files.
|
|
32
32
|
- Keep tools narrowly scoped and documented.
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
References usage
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
Bundled reference files are addressed relative to this agent file's own directory:
|
|
37
|
+
|
|
38
|
+
- Use '../references/tools.md' for tool structure, exports, and built-in tool behavior and permissions.
|
|
39
|
+
|
|
40
|
+
Live knowledge fallback
|
|
41
|
+
|
|
42
|
+
For anything beyond the bundled references, query the deepwiki MCP tools (read_wiki_structure, read_wiki_contents, ask_question) against repo 'anomalyco/opencode' when available; otherwise run 'npx defuddle <url>' on the relevant opencode.ai/docs page if you have a way to execute commands. Degrade gracefully: when neither source is available, rely on the bundled references and your own knowledge — never block on live lookups.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# OpenCode agents — fundamentals
|
|
2
|
+
|
|
3
|
+
Agents are markdown-defined AI assistants. Locations (plural directory names):
|
|
4
|
+
|
|
5
|
+
- Project: `.opencode/agents/`
|
|
6
|
+
- Global: `~/.config/opencode/agents/`
|
|
7
|
+
|
|
8
|
+
The filename becomes the agent name (`review.md` → `review` agent). The markdown body is the system prompt.
|
|
9
|
+
|
|
10
|
+
## Types
|
|
11
|
+
|
|
12
|
+
- `primary` — main assistant the user interacts with (Tab to cycle).
|
|
13
|
+
- `subagent` — invoked by primary agents via the Task tool or by `@` mention.
|
|
14
|
+
- `mode` defaults to `all` if unspecified; set it explicitly.
|
|
15
|
+
|
|
16
|
+
## Frontmatter fields
|
|
17
|
+
|
|
18
|
+
| Field | Required | Notes |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| `description` | yes | What the agent does and when to use it. Drives subagent selection. |
|
|
21
|
+
| `mode` | no | `primary`, `subagent`, or `all` (default `all`). |
|
|
22
|
+
| `model` | no | `provider/model-id` (e.g. `anthropic/claude-sonnet-4-5`). Unset: primary uses the configured global model; subagents inherit the invoking agent's model. |
|
|
23
|
+
| `temperature` | no | 0.0–1.0. Low (0.0–0.2) focused/deterministic; high (0.6+) creative. Model-specific defaults apply if unset. |
|
|
24
|
+
| `steps` | no | Max agentic iterations before forced text-only summary. `maxSteps` is deprecated. |
|
|
25
|
+
| `tools` | no | **Deprecated** boolean map (`write: false`, `bash: false`, `mymcp_*: false`). Prefer `permission`. |
|
|
26
|
+
| `permission` | no | Allow/ask/deny control, per key or per glob pattern (see below). |
|
|
27
|
+
| `hidden` | no | `true` hides a `subagent` from the `@` menu; still invokable via Task tool. |
|
|
28
|
+
| `disable` | no | `true` disables the agent. |
|
|
29
|
+
| `color` | no | Hex (e.g. `#ff6b6b`) or theme color (`primary`, `accent`, ...). |
|
|
30
|
+
| `top_p` | no | Alternative randomness control, 0.0–1.0. |
|
|
31
|
+
| other keys | no | Passed through to the provider as model options (e.g. `reasoningEffort`). |
|
|
32
|
+
|
|
33
|
+
## Permissions
|
|
34
|
+
|
|
35
|
+
Values: `"allow"`, `"ask"`, `"deny"`. Either shorthand or an object of glob/pattern → action.
|
|
36
|
+
|
|
37
|
+
Keys: `read`, `edit`, `glob`, `grep`, `list`, `bash`, `task`, `webfetch`, `websearch`, `external_directory`, `todowrite`, `skill`, `lsp`, `question`, `doom_loop`.
|
|
38
|
+
|
|
39
|
+
- `edit` gates all file modifications: `write`, `edit`, `apply_patch`.
|
|
40
|
+
- `todowrite` gates `todowrite` and `todoread`.
|
|
41
|
+
- Shorthand-only keys: `webfetch`, `websearch`, `external_directory`, `question`, `doom_loop`, `lsp` (also accepts patterns — check schema when in doubt).
|
|
42
|
+
|
|
43
|
+
Bash command scoping (last matching rule wins; put `*` first, specific rules after):
|
|
44
|
+
|
|
45
|
+
```yaml
|
|
46
|
+
permission:
|
|
47
|
+
bash:
|
|
48
|
+
"*": ask
|
|
49
|
+
"git status *": allow
|
|
50
|
+
"git push": ask
|
|
51
|
+
webfetch: deny
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Task (subagent) scoping with globs — denied subagents are removed from the Task tool description:
|
|
55
|
+
|
|
56
|
+
```yaml
|
|
57
|
+
permission:
|
|
58
|
+
task:
|
|
59
|
+
"*": deny
|
|
60
|
+
"orchestrator-*": allow
|
|
61
|
+
"code-reviewer": ask
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Users can always invoke any subagent directly via `@` regardless of task permissions.
|
|
65
|
+
|
|
66
|
+
## JSON alternative
|
|
67
|
+
|
|
68
|
+
Agents can also be configured under the `agent` key in `opencode.json` with the same options plus `prompt` (inline string or `{file:./path}` relative to the config file). Markdown files are preferred for readability.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# OpenCode commands — fundamentals
|
|
2
|
+
|
|
3
|
+
Custom commands are prompt templates invoked as `/name` in the TUI, in addition to built-ins (`/init`, `/undo`, `/redo`, `/share`, `/help`).
|
|
4
|
+
|
|
5
|
+
Locations:
|
|
6
|
+
|
|
7
|
+
- Project: `.opencode/commands/`
|
|
8
|
+
- Global: `~/.config/opencode/commands/`
|
|
9
|
+
|
|
10
|
+
The filename becomes the command name (`test.md` → `/test`).
|
|
11
|
+
|
|
12
|
+
## Markdown format
|
|
13
|
+
|
|
14
|
+
The frontmatter defines properties; the body is the prompt template.
|
|
15
|
+
|
|
16
|
+
```markdown
|
|
17
|
+
---
|
|
18
|
+
description: Run tests with coverage
|
|
19
|
+
agent: build
|
|
20
|
+
model: anthropic/claude-haiku-4-5
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
Run the full test suite with coverage report and show any failures.
|
|
24
|
+
Focus on the failing tests and suggest fixes.
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Frontmatter keys
|
|
28
|
+
|
|
29
|
+
| Key | Required | Notes |
|
|
30
|
+
| --- | --- | --- |
|
|
31
|
+
| `description` | no* | Shown in the TUI command list. |
|
|
32
|
+
| `template` | no* | The prompt (JSON config only; in markdown the body is the template). |
|
|
33
|
+
| `agent` | no | Which agent executes it. Defaults to the current agent. |
|
|
34
|
+
| `model` | no | Overrides the default model. |
|
|
35
|
+
| `subtask` | no | `true` forces a subagent invocation (keeps primary context clean), even for `primary`-mode agents. |
|
|
36
|
+
|
|
37
|
+
*In JSON config (`command.<name>` in `opencode.json`), `template` is required and `description` identifies the command.
|
|
38
|
+
|
|
39
|
+
## Template features
|
|
40
|
+
|
|
41
|
+
- `$ARGUMENTS` — full argument string: `/component Button` → `Button`.
|
|
42
|
+
- `$1`, `$2`, `$3` — positional args: `/create-file config.json src "content"` → `$1`=`config.json`, `$2`=`src`, `$3`=`content`.
|
|
43
|
+
- `` !`command` `` — inject shell output into the prompt (runs in the project root), e.g. ``!`git log --oneline -10` ``.
|
|
44
|
+
- `@path/to/file` — include file content in the prompt.
|
|
45
|
+
|
|
46
|
+
## Notes
|
|
47
|
+
|
|
48
|
+
- A custom command with the same name as a built-in overrides it.
|
|
49
|
+
- Keep prompts concise and task-focused; the template is the whole instruction the model receives.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# OpenCode config — fundamentals
|
|
2
|
+
|
|
3
|
+
OpenCode is configured with `opencode.json` (or `.jsonc`). Schema: `https://opencode.ai/config.json`. TUI settings live in a separate `tui.json` (`https://opencode.ai/tui.json`).
|
|
4
|
+
|
|
5
|
+
## Locations and precedence
|
|
6
|
+
|
|
7
|
+
Configs are **merged, not replaced**; later sources override earlier ones only for conflicting keys:
|
|
8
|
+
|
|
9
|
+
1. Remote config (`.well-known/opencode`, organizational defaults)
|
|
10
|
+
2. Global config (`~/.config/opencode/opencode.json`)
|
|
11
|
+
3. Custom config (`OPENCODE_CONFIG` env var)
|
|
12
|
+
4. Project config (`opencode.json` at project root, searched up to the git root)
|
|
13
|
+
5. `.opencode/` directories (agents, commands, plugins, skills, tools)
|
|
14
|
+
6. Inline config (`OPENCODE_CONFIG_CONTENT` env var)
|
|
15
|
+
7. Managed files (`/etc/opencode/`, `%ProgramData%\opencode`, macOS app support) and macOS MDM preferences — highest, not user-overridable
|
|
16
|
+
|
|
17
|
+
So: defaults/remote < global < project; managed settings override everything.
|
|
18
|
+
|
|
19
|
+
## Key schema options
|
|
20
|
+
|
|
21
|
+
| Key | Purpose |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| `model` | Default model, `provider/model-id`. |
|
|
24
|
+
| `small_model` | Cheap model for lightweight tasks (titles, summaries). |
|
|
25
|
+
| `provider` | Provider config; `options` supports `timeout`, `headerTimeout`, `chunkTimeout`. |
|
|
26
|
+
| `enabled_providers` / `disabled_providers` | Provider allowlist/blocklist (`disabled_providers` wins). |
|
|
27
|
+
| `agent` | Inline agent definitions; `default_agent` picks the default primary agent. |
|
|
28
|
+
| `command` | Inline command definitions (`template`, `description`, `agent`, `model`). |
|
|
29
|
+
| `mode` | Inline mode/agent-group definitions. |
|
|
30
|
+
| `mcp` | MCP server config (see mcp-servers reference). |
|
|
31
|
+
| `plugin` | npm plugin packages to load. |
|
|
32
|
+
| `tools` | Global tool enable/disable map with globs (`"write": false`). |
|
|
33
|
+
| `permission` | Global `allow`/`ask`/`deny` map (see agents reference for keys). |
|
|
34
|
+
| `instructions` | Extra instruction files/globs (e.g. `["CONTRIBUTING.md", "docs/rules/*.md"]`). |
|
|
35
|
+
| `lsp` | LSP servers (`true` for defaults, or object with per-server overrides). |
|
|
36
|
+
| `formatter` | Formatters (`true` for defaults, or object; custom: `command`, `extensions`, `environment`). |
|
|
37
|
+
| `keybinds` | TUI shortcuts (in `tui.json`; merged with defaults). |
|
|
38
|
+
| `share` | `"manual"` (default) / `"auto"` / `"disabled"`. |
|
|
39
|
+
| `autoupdate` | `true` / `false` / `"notify"`. |
|
|
40
|
+
| `snapshot` | `false` disables undo snapshots. |
|
|
41
|
+
| `compaction` | `{ auto, prune, reserved }` context compaction behavior. |
|
|
42
|
+
| `watcher` | `{ ignore: [globs] }` file watcher exclusions. |
|
|
43
|
+
| `server` | `port`, `hostname`, `mdns`, `cors` for `opencode serve`/`web`. |
|
|
44
|
+
| `shell` | Shell for interactive terminal and tool calls (e.g. `pwsh`). |
|
|
45
|
+
| `subagent_depth` | Subagent nesting depth (default 1; 0 disables subagents). |
|
|
46
|
+
| `experimental` | Options under active development (e.g. `policies`). |
|
|
47
|
+
|
|
48
|
+
## Directory conventions
|
|
49
|
+
|
|
50
|
+
`.opencode/` and `~/.config/opencode/` use **plural** subdirectory names: `agents/`, `commands/`, `plugins/`, `skills/`, `tools/`, `themes/` (singular accepted for backwards compatibility). Configs are safe to check into git; `prompt` paths in agent config resolve relative to the config file.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# OpenCode MCP servers — fundamentals
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) servers add external tools alongside built-ins. Configure them under the `mcp` key in `opencode.json` with a unique name per server.
|
|
4
|
+
|
|
5
|
+
Caution: MCP tools add to context — enable only what you need.
|
|
6
|
+
|
|
7
|
+
## Local servers
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"mcp": {
|
|
12
|
+
"my-local-mcp": {
|
|
13
|
+
"type": "local",
|
|
14
|
+
"command": ["npx", "-y", "my-mcp-command"],
|
|
15
|
+
"enabled": true,
|
|
16
|
+
"environment": { "MY_ENV_VAR": "value" }
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Options: `type` (required, `"local"`), `command` (required array), `cwd`, `environment`, `enabled`, `timeout` (ms to fetch tools, default 5000).
|
|
23
|
+
|
|
24
|
+
## Remote servers
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"mcp": {
|
|
29
|
+
"my-remote-mcp": {
|
|
30
|
+
"type": "remote",
|
|
31
|
+
"url": "https://mcp.example.com/mcp",
|
|
32
|
+
"enabled": true,
|
|
33
|
+
"headers": { "Authorization": "Bearer {env:MY_API_KEY}" }
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Options: `type` (required, `"remote"`), `url` (required), `headers`, `oauth`, `enabled`, `timeout`.
|
|
40
|
+
|
|
41
|
+
## OAuth (remote)
|
|
42
|
+
|
|
43
|
+
- Automatic: OpenCode detects the 401, runs the OAuth flow (dynamic client registration, RFC 7591), and stores tokens. No config needed for most servers.
|
|
44
|
+
- Pre-registered credentials: `"oauth": { "clientId": "...", "clientSecret": "...", "scope": "tools:read" }` (use `{env:VAR}` for secrets).
|
|
45
|
+
- `"oauth": false` disables auto-OAuth (e.g. API-key servers).
|
|
46
|
+
- CLI: `opencode mcp auth <name>`, `opencode mcp list`, `opencode mcp logout <name>`, `opencode mcp debug <name>`.
|
|
47
|
+
|
|
48
|
+
## Tool scoping
|
|
49
|
+
|
|
50
|
+
MCP tools register as `<servername>_<toolname>`, so glob patterns control them like any tool:
|
|
51
|
+
|
|
52
|
+
- Disable globally: `"tools": { "my-mcp*": false }` or via permission `"my-mcp_*": "ask"` (permission patterns match built-ins, custom tools, and MCP tools alike).
|
|
53
|
+
- Enable per agent only: disable globally in `tools`, then set `"tools": { "my-mcp*": true }` inside the agent's config.
|
|
54
|
+
- Glob syntax: `*` (any chars), `?` (one char); last matching permission rule wins.
|
|
55
|
+
- Per-server enable/disable: `"enabled": false` on the server entry hides all its tools without deleting config.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# OpenCode plugins — fundamentals
|
|
2
|
+
|
|
3
|
+
Plugins are JS/TS modules that hook into OpenCode events and customize behavior.
|
|
4
|
+
|
|
5
|
+
Locations:
|
|
6
|
+
|
|
7
|
+
- Project: `.opencode/plugins/`
|
|
8
|
+
- Global: `~/.config/opencode/plugins/`
|
|
9
|
+
|
|
10
|
+
Files in these directories load automatically at startup. npm packages can be loaded via the `plugin` array in `opencode.json`. Load order: global config → project config → global plugin dir → project plugin dir.
|
|
11
|
+
|
|
12
|
+
## Plugin shape
|
|
13
|
+
|
|
14
|
+
A plugin exports one or more async functions. Each receives a context and returns a hooks object:
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import type { Plugin } from "@opencode-ai/plugin"
|
|
18
|
+
|
|
19
|
+
export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
|
|
20
|
+
return {
|
|
21
|
+
// hook implementations
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Context: `project` (project info), `directory` (cwd), `worktree` (git worktree root), `client` (opencode SDK client), `$` (Bun shell API).
|
|
27
|
+
|
|
28
|
+
## Config hooks
|
|
29
|
+
|
|
30
|
+
Returning a `tool` object adds custom tools; a plugin tool that shares a built-in tool's name takes precedence:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { type Plugin, tool } from "@opencode-ai/plugin"
|
|
34
|
+
|
|
35
|
+
export const CustomToolsPlugin: Plugin = async (ctx) => {
|
|
36
|
+
return {
|
|
37
|
+
tool: {
|
|
38
|
+
mytool: tool({
|
|
39
|
+
description: "What the tool does",
|
|
40
|
+
args: { foo: tool.schema.string() },
|
|
41
|
+
async execute(args, context) {
|
|
42
|
+
const { directory, worktree } = context
|
|
43
|
+
return `Hello ${args.foo} from ${directory}`
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Event hooks
|
|
52
|
+
|
|
53
|
+
Hooks are named event handlers: `"<event>": async (input, output) => { ... }`.
|
|
54
|
+
|
|
55
|
+
Key events:
|
|
56
|
+
|
|
57
|
+
- Commands: `command.executed`
|
|
58
|
+
- Files: `file.edited`, `file.watcher.updated`
|
|
59
|
+
- Messages: `message.updated`, `message.part.updated`, `message.part.removed`, `message.removed`
|
|
60
|
+
- Permissions: `permission.asked`, `permission.replied`
|
|
61
|
+
- Sessions: `session.created`, `session.idle`, `session.updated`, `session.error`, `session.compacted`, `session.deleted`, `session.diff`, `session.status`
|
|
62
|
+
- Tools: `tool.execute.before`, `tool.execute.after`
|
|
63
|
+
- Shell: `shell.env`
|
|
64
|
+
- TUI: `tui.prompt.append`, `tui.command.execute`, `tui.toast.show`
|
|
65
|
+
- Other: `installation.updated`, `lsp.client.diagnostics`, `lsp.updated`, `server.connected`, `todo.updated`
|
|
66
|
+
|
|
67
|
+
A catch-all `event: async ({ event }) => {...}` hook receives every event (`event.type` switches on it).
|
|
68
|
+
|
|
69
|
+
`tool.execute.before` can inspect/modify `output.args` or throw to block; `shell.env` mutates `output.env`.
|
|
70
|
+
|
|
71
|
+
Compaction hook `experimental.session.compacting` can append via `output.context.push(...)` or fully replace the prompt via `output.prompt`.
|
|
72
|
+
|
|
73
|
+
## Dependencies and logging
|
|
74
|
+
|
|
75
|
+
- Local plugins can use npm packages: add a `package.json` to the config directory (`.opencode/package.json`); OpenCode runs `bun install` at startup.
|
|
76
|
+
- Prefer structured logging via `client.app.log({ body: { service, level, message, extra } })` over `console.log`. Levels: `debug`, `info`, `warn`, `error`.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Prompt engineering — distilled best practices
|
|
2
|
+
|
|
3
|
+
Distilled from Anthropic's Claude prompting best practices and skill-authoring best practices. Apply to agent prompts, skill bodies, and command templates.
|
|
4
|
+
|
|
5
|
+
## Core principles
|
|
6
|
+
|
|
7
|
+
- **Be clear and direct.** State the desired output, format, and constraints explicitly. If you want above-and-beyond behavior, ask for it. The colleague test: could someone with minimal context follow your prompt?
|
|
8
|
+
- **Explain why.** Give context/motivation for rules ("never use ellipses because a TTS engine reads this aloud"). The model generalizes from the explanation.
|
|
9
|
+
- **Sequence matters.** Use numbered steps or bullets when order or completeness matters. Put critical instructions at the end of long prompts.
|
|
10
|
+
- **Give a role.** A one-sentence persona in the system prompt focuses tone and behavior ("You are a code reviewer focused on security...").
|
|
11
|
+
|
|
12
|
+
## Examples and structure
|
|
13
|
+
|
|
14
|
+
- Few-shot examples (3–5) are the most reliable way to steer format, tone, and structure. Make them relevant, diverse, and wrapped in tags (`<example>` inside `<examples>`).
|
|
15
|
+
- Use XML tags to separate instructions, context, documents, and inputs in complex prompts (`<instructions>`, `<context>`, `<documents>`). Consistent, descriptive tag names.
|
|
16
|
+
- Long context: put longform data near the top and the query/instructions at the end; wrap each document in `<document>` tags with metadata; ask the model to quote relevant passages before answering.
|
|
17
|
+
|
|
18
|
+
## Output control
|
|
19
|
+
|
|
20
|
+
- Say what to do, not what not to do ("write flowing prose paragraphs" beats "don't use bullets").
|
|
21
|
+
- Match your prompt's style to the desired output style (markdown-heavy prompts yield markdown-heavy answers).
|
|
22
|
+
- Use structured outputs (JSON/XML schemas) when precise parsing is needed; request verbatim structure with an explicit template.
|
|
23
|
+
|
|
24
|
+
## Tool use and agentic behavior
|
|
25
|
+
|
|
26
|
+
- Models may suggest instead of act. Be explicit: "Change this function" vs "Can you suggest changes". Prompt blocks can set a default-to-action or do-not-act bias.
|
|
27
|
+
- Independent tool calls can run in parallel; this is steerable ("make all independent calls in parallel" / "execute sequentially").
|
|
28
|
+
- Prefer general guidance over aggressive over-prompting ("Use this tool when..." beats "CRITICAL: you MUST..."). Over-instruction causes overtriggering.
|
|
29
|
+
- Self-check: "Before you finish, verify your answer against the criteria" catches errors; ask for it only when quality demands it.
|
|
30
|
+
- Guard rails for agents: confirm before irreversible or shared-system actions; avoid over-engineering (only requested changes, no speculative abstractions); investigate files before answering (never speculate about unread code); write general solutions, don't hardcode to tests.
|
|
31
|
+
- Subagents: use for parallelizable, context-isolated workstreams; work directly for simple sequential tasks.
|
|
32
|
+
|
|
33
|
+
## Skill and instruction authoring
|
|
34
|
+
|
|
35
|
+
- **Concise is key** — the context window is a public good. Only add context the model doesn't already have; make every paragraph justify its tokens.
|
|
36
|
+
- **Set degrees of freedom** to match fragility: high freedom (heuristics) for flexible tasks; low freedom (exact scripts, "do not modify this command") for fragile operations.
|
|
37
|
+
- **Descriptions drive selection**: third person, what it does + when to use it, with specific trigger terms. Avoid vague names (`helper`, `utils`) and vague descriptions.
|
|
38
|
+
- **Progressive disclosure**: overview in the main file; details in separately linked files, one level deep (nested references cause partial reads). Table of contents for files over 100 lines.
|
|
39
|
+
- **Workflows and feedback loops**: numbered steps with copy-paste checklists for complex tasks; validate → fix → repeat loops for quality-critical operations; create verifiable intermediate outputs before destructive or batch operations.
|
|
40
|
+
- **Stability**: no time-sensitive information; consistent terminology (pick one term per concept); avoid Windows-style paths — always forward slashes.
|
|
41
|
+
- **Provide a default, not a menu**: one recommended approach with an escape hatch for exceptions, not five equivalent options.
|
|
42
|
+
|
|
43
|
+
## Iteration
|
|
44
|
+
|
|
45
|
+
- Test with real tasks and observe how the instructions are actually navigated; iterate on observed failures, not assumptions.
|
|
46
|
+
- Build evaluations before extensive documentation: identify gaps, write minimal instructions to close them, measure against baseline.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# OpenCode skills — fundamentals
|
|
2
|
+
|
|
3
|
+
Skills are reusable instruction packages discovered on-demand via the native `skill` tool. Agents see each skill's name and description in `<available_skills>` and load the full SKILL.md only when relevant.
|
|
4
|
+
|
|
5
|
+
Locations (one folder per skill):
|
|
6
|
+
|
|
7
|
+
- Project: `.opencode/skills/<name>/SKILL.md`
|
|
8
|
+
- Global: `~/.config/opencode/skills/<name>/SKILL.md`
|
|
9
|
+
- Compatible paths: `.claude/skills/<name>/SKILL.md`, `.agents/skills/<name>/SKILL.md` (project and home variants)
|
|
10
|
+
|
|
11
|
+
## Frontmatter rules
|
|
12
|
+
|
|
13
|
+
Only these fields are recognized; unknown fields are ignored:
|
|
14
|
+
|
|
15
|
+
| Field | Required | Rules |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| `name` | yes | 1–64 chars, lowercase alphanumeric with single hyphens (`^[a-z0-9]+(-[a-z0-9]+)*$`), no leading/trailing `-`, no `--`, must match the folder name. |
|
|
18
|
+
| `description` | yes | 1–1024 chars. Third person; state what the skill does AND when to use it. This drives skill selection — be specific and include key trigger terms. |
|
|
19
|
+
| `license` | no | e.g. `MIT`. |
|
|
20
|
+
| `compatibility` | no | e.g. `opencode`. |
|
|
21
|
+
| `metadata` | no | String-to-string map. |
|
|
22
|
+
|
|
23
|
+
If a skill does not show up: verify `SKILL.md` capitalization, required frontmatter, unique names across locations, and that permissions don't `deny` it.
|
|
24
|
+
|
|
25
|
+
## Progressive disclosure
|
|
26
|
+
|
|
27
|
+
- Metadata (name + description) is pre-loaded at startup; the body is read on demand; bundled files are read only as needed — no context penalty until accessed.
|
|
28
|
+
- Keep SKILL.md under ~500 lines; split deeper content into separate files.
|
|
29
|
+
- Default assumption: the model is already smart — only add context it doesn't have.
|
|
30
|
+
|
|
31
|
+
## Co-located references pattern
|
|
32
|
+
|
|
33
|
+
Bundle detail files next to SKILL.md in the skill folder:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
my-skill/
|
|
37
|
+
├── SKILL.md # overview + navigation (loaded when triggered)
|
|
38
|
+
├── reference.md # loaded as needed
|
|
39
|
+
├── examples.md # loaded as needed
|
|
40
|
+
└── scripts/tool.py # executed, not loaded
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- Keep references **one level deep** from SKILL.md — nested references cause partial reads. Link each file directly from SKILL.md.
|
|
44
|
+
- Add a table of contents at the top of reference files over 100 lines.
|
|
45
|
+
- Make execution intent explicit: "Run `scripts/foo.py`" (execute) vs "See `scripts/foo.py`" (read as reference).
|
|
46
|
+
|
|
47
|
+
## Base-directory convention
|
|
48
|
+
|
|
49
|
+
Address co-located files **relative to the skill's own directory** (its base directory), always with **forward slashes** (`reference/guide.md`, not `reference\guide.md` or absolute paths). Forward-slash relative paths work on every platform.
|
|
50
|
+
|
|
51
|
+
## Authoring quick rules
|
|
52
|
+
|
|
53
|
+
- Set degrees of freedom to match fragility: exact scripts for critical/fragile operations, heuristics for flexible tasks.
|
|
54
|
+
- Provide workflows as numbered steps with checklists; add feedback loops (validate → fix → repeat) for quality-critical tasks.
|
|
55
|
+
- No time-sensitive information; use consistent terminology throughout; avoid offering many equivalent options — pick a default with an escape hatch.
|
|
56
|
+
- Gerund names read well (`processing-pdfs`); avoid vague names (`helper`, `utils`).
|
|
57
|
+
- Gate access with `permission.skill` glob patterns (`"internal-*": "deny"`); disable entirely with `tools: { skill: false }`.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# OpenCode tools — fundamentals
|
|
2
|
+
|
|
3
|
+
By default all tools are enabled and need no permission to run. Control them via the `permission` config (global or per agent).
|
|
4
|
+
|
|
5
|
+
## Built-in tools
|
|
6
|
+
|
|
7
|
+
| Tool | Purpose | Permission key |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| `bash` | Execute shell commands | `bash` |
|
|
10
|
+
| `read` | Read files (supports line ranges) | `read` |
|
|
11
|
+
| `edit` | Exact string replacement in files | `edit` |
|
|
12
|
+
| `write` | Create/overwrite files | `edit` |
|
|
13
|
+
| `apply_patch` | Apply patch files | `edit` |
|
|
14
|
+
| `grep` | Regex content search | `grep` |
|
|
15
|
+
| `glob` | File pattern matching | `glob` |
|
|
16
|
+
| `skill` | Load a SKILL.md | `skill` |
|
|
17
|
+
| `todowrite` | Task lists (disabled for subagents by default) | `todowrite` |
|
|
18
|
+
| `webfetch` | Fetch a URL | `webfetch` |
|
|
19
|
+
| `websearch` | Web search (provider/env gated) | `websearch` |
|
|
20
|
+
| `question` | Ask the user structured questions | `question` |
|
|
21
|
+
| `lsp` | LSP intelligence (experimental) | `lsp` |
|
|
22
|
+
|
|
23
|
+
`edit`, `write`, and `apply_patch` share the single `edit` permission. `grep`/`glob` use ripgrep and respect `.gitignore` (a `.ignore` file can re-include paths). Hooks must check `input.tool === "apply_patch"` and use `output.args.patchText` (paths embedded in marker lines).
|
|
24
|
+
|
|
25
|
+
## Custom tools
|
|
26
|
+
|
|
27
|
+
Defined in `.opencode/tools/` (project) or `~/.config/opencode/tools/` (global). The filename becomes the tool name (`database.ts` → `database` tool).
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { tool } from "@opencode-ai/plugin"
|
|
31
|
+
|
|
32
|
+
export default tool({
|
|
33
|
+
description: "Query the project database",
|
|
34
|
+
args: {
|
|
35
|
+
query: tool.schema.string().describe("SQL query to execute"),
|
|
36
|
+
},
|
|
37
|
+
async execute(args, context) {
|
|
38
|
+
return `Executed: ${args.query}`
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Key API points:
|
|
44
|
+
|
|
45
|
+
- `tool.schema` is Zod (`tool.schema.string()`, `.number()`, `.describe(...)`); or import `zod` directly and export a plain object.
|
|
46
|
+
- `execute(args, context)` — context provides `agent`, `sessionID`, `messageID`, `directory` (session cwd), `worktree` (git worktree root). Use `context.worktree` for repo-root paths.
|
|
47
|
+
- Multiple named exports in one file become separate tools named `<filename>_<exportname>` (`math_add`, `math_multiply`).
|
|
48
|
+
- A custom tool with a built-in tool's name overrides it (prefer unique names; use permissions to just disable).
|
|
49
|
+
- The definition is TS/JS, but `execute` can invoke scripts in any language (e.g. via `Bun.$`).
|
package/index.ts
CHANGED
|
@@ -1,120 +1,21 @@
|
|
|
1
|
-
import type { Plugin
|
|
2
|
-
import { readFile } from "node:fs/promises";
|
|
1
|
+
import type { Plugin } from "@opencode-ai/plugin";
|
|
3
2
|
import path from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
import type { AgentConfig } from "@opencode-ai/sdk";
|
|
6
|
-
import { command as syncDocsCommand } from "./commands/sync-docs";
|
|
7
|
-
import { OpenCodeDocsFetcher } from "./scripts/fetch-opencode-docs";
|
|
8
|
-
import { SilentLogger } from "./scripts/logger";
|
|
9
|
-
import { createSyncDocsTool } from "./tools/sync-docs";
|
|
3
|
+
import { AgentLoader } from "./agent-loader";
|
|
10
4
|
|
|
11
5
|
const AGENTS_DIR = path.join(import.meta.dirname, "assets", "agents");
|
|
12
6
|
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
interface AgentFrontmatter {
|
|
16
|
-
description: string;
|
|
17
|
-
mode: "primary" | "subagent" | "all";
|
|
18
|
-
tools?: Record<string, boolean>;
|
|
19
|
-
permission?: {
|
|
20
|
-
edit?: "ask" | "allow" | "deny";
|
|
21
|
-
bash?: ("ask" | "allow" | "deny") | Record<string, "ask" | "allow" | "deny">;
|
|
22
|
-
webfetch?: "ask" | "allow" | "deny";
|
|
23
|
-
doom_loop?: "ask" | "allow" | "deny";
|
|
24
|
-
external_directory?: "ask" | "allow" | "deny";
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async function parseAgentMarkdown(content: string, agentName: string): Promise<AgentConfig> {
|
|
29
|
-
const match = content.match(FRONTMATTER_REGEX);
|
|
30
|
-
|
|
31
|
-
if (!match || match.length < 3) {
|
|
32
|
-
throw new Error(`Agent ${agentName} must have YAML frontmatter`);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const frontmatterYaml = match[1] as string;
|
|
36
|
-
const rawPrompt = match[2] as string;
|
|
37
|
-
const frontmatter = parseYaml(frontmatterYaml) as AgentFrontmatter;
|
|
38
|
-
const prompt = rawPrompt.replace(/^\r?\n/, "");
|
|
39
|
-
|
|
40
|
-
const config: AgentConfig = {
|
|
41
|
-
description: frontmatter.description,
|
|
42
|
-
mode: frontmatter.mode,
|
|
43
|
-
prompt,
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
if (frontmatter.tools) {
|
|
47
|
-
config.tools = frontmatter.tools;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (frontmatter.permission) {
|
|
51
|
-
config.permission = frontmatter.permission;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return config;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const OpencodeArchitect: Plugin = async (input) => {
|
|
58
|
-
const syncDocsTool = createSyncDocsTool();
|
|
59
|
-
|
|
60
|
-
syncDocsOnStartup(input.client);
|
|
61
|
-
|
|
62
|
-
const agents = await loadAgents();
|
|
7
|
+
const OpencodeArchitect: Plugin = async () => {
|
|
8
|
+
const agents = await new AgentLoader(AGENTS_DIR).loadAgents();
|
|
63
9
|
|
|
64
10
|
return {
|
|
65
11
|
config: async (config) => {
|
|
66
12
|
config.agent = config.agent || {};
|
|
67
|
-
config.command = config.command || {};
|
|
68
13
|
|
|
69
14
|
for (const [name, agentConfig] of Object.entries(agents)) {
|
|
70
15
|
config.agent[name] = agentConfig;
|
|
71
16
|
}
|
|
72
|
-
|
|
73
|
-
config.command["sync-docs"] = syncDocsCommand;
|
|
74
|
-
},
|
|
75
|
-
tool: {
|
|
76
|
-
"sync-docs": syncDocsTool,
|
|
77
17
|
},
|
|
78
18
|
};
|
|
79
19
|
};
|
|
80
20
|
|
|
81
21
|
export default OpencodeArchitect;
|
|
82
|
-
|
|
83
|
-
async function loadAgents(): Promise<Record<string, AgentConfig>> {
|
|
84
|
-
const agentFiles = [
|
|
85
|
-
"opencode-agent-designer.md",
|
|
86
|
-
"opencode-architect.md",
|
|
87
|
-
"opencode-command-crafter.md",
|
|
88
|
-
"opencode-extension-auditor.md",
|
|
89
|
-
"opencode-packager.md",
|
|
90
|
-
"opencode-publisher.md",
|
|
91
|
-
"opencode-mcp-integrator.md",
|
|
92
|
-
"opencode-plugin-engineer.md",
|
|
93
|
-
"opencode-skill-creator.md",
|
|
94
|
-
"opencode-tool-builder.md",
|
|
95
|
-
];
|
|
96
|
-
|
|
97
|
-
const agents: Record<string, AgentConfig> = {};
|
|
98
|
-
|
|
99
|
-
for (const filename of agentFiles) {
|
|
100
|
-
const agentPath = path.join(AGENTS_DIR, filename);
|
|
101
|
-
const agentContent = await readFile(agentPath, "utf-8");
|
|
102
|
-
const agentName = path.basename(filename, ".md");
|
|
103
|
-
agents[agentName] = await parseAgentMarkdown(agentContent, agentName);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return agents;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function syncDocsOnStartup(client: PluginInput["client"]): void {
|
|
110
|
-
const fetcher = new OpenCodeDocsFetcher(new SilentLogger());
|
|
111
|
-
fetcher.run().catch((error: unknown) => {
|
|
112
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
113
|
-
client.tui.showToast({
|
|
114
|
-
body: {
|
|
115
|
-
message: `Failed to sync OpenCode docs: ${message}`,
|
|
116
|
-
variant: "error",
|
|
117
|
-
},
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
}
|
package/package.json
CHANGED
|
@@ -1,39 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-architect",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "index.ts",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/
|
|
9
|
+
"url": "git+https://github.com/Expert-Vision-Software/opencode-architect.git"
|
|
10
10
|
},
|
|
11
|
+
"homepage": "https://github.com/Expert-Vision-Software/opencode-architect#readme",
|
|
11
12
|
"publisher": "Expert Vision Software",
|
|
12
13
|
"author": "Expert Vision Support <support@expertvision.software>",
|
|
13
14
|
"bugs": {
|
|
14
|
-
"url": "https://github.com/
|
|
15
|
+
"url": "https://github.com/Expert-Vision-Software/opencode-architect/issues",
|
|
15
16
|
"email": "support@expertvision.software"
|
|
16
17
|
},
|
|
17
18
|
"scripts": {
|
|
18
19
|
"check": "tsc --noEmit",
|
|
20
|
+
"test": "bun test",
|
|
19
21
|
"release": "npm version patch && npm publish && git push --follow-tags"
|
|
20
22
|
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
21
26
|
"files": [
|
|
22
27
|
"index.ts",
|
|
23
|
-
"
|
|
24
|
-
"commands",
|
|
25
|
-
"scripts",
|
|
28
|
+
"agent-loader.ts",
|
|
26
29
|
"assets"
|
|
27
30
|
],
|
|
28
31
|
"dependencies": {
|
|
29
|
-
"yaml": "^2.7.1"
|
|
32
|
+
"yaml": "^2.7.1",
|
|
33
|
+
"@opencode-ai/plugin": "*"
|
|
30
34
|
},
|
|
31
35
|
"devDependencies": {
|
|
32
|
-
"@opencode-ai/plugin": "latest",
|
|
33
36
|
"@opencode-ai/sdk": "latest",
|
|
34
|
-
"@types/bun": "latest"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"typescript": "^5"
|
|
37
|
+
"@types/bun": "latest",
|
|
38
|
+
"@types/node": "latest",
|
|
39
|
+
"typescript": "latest"
|
|
38
40
|
}
|
|
39
41
|
}
|
package/commands/sync-docs.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { Config } from "@opencode-ai/sdk";
|
|
2
|
-
|
|
3
|
-
export const command: NonNullable<Config["command"]>[string] = {
|
|
4
|
-
description: "Sync OpenCode docs into ~/.cache/opencode/opencode-architect/docs",
|
|
5
|
-
template:
|
|
6
|
-
"Use the sync-docs tool to fetch the latest OpenCode documentation into `~/.cache/opencode/opencode-architect/docs`.",
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export default command;
|
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
-
import os from "node:os";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
|
|
5
|
-
import type { Logger } from "./logger";
|
|
6
|
-
import { ConsoleLogger } from "./logger";
|
|
7
|
-
|
|
8
|
-
interface ExternalDoc {
|
|
9
|
-
url: string;
|
|
10
|
-
filename: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export class OpenCodeDocsFetcher {
|
|
14
|
-
private readonly sitemapUrl: string;
|
|
15
|
-
private readonly docsDir: string;
|
|
16
|
-
private readonly externalDocs: ExternalDoc[];
|
|
17
|
-
private readonly logger: Logger;
|
|
18
|
-
|
|
19
|
-
public constructor(logger: Logger | null = null) {
|
|
20
|
-
this.sitemapUrl = "https://opencode.ai/sitemap.xml";
|
|
21
|
-
this.docsDir = path.join(
|
|
22
|
-
os.homedir(),
|
|
23
|
-
".cache",
|
|
24
|
-
"opencode",
|
|
25
|
-
"opencode-architect",
|
|
26
|
-
"docs",
|
|
27
|
-
);
|
|
28
|
-
this.logger = logger ?? new ConsoleLogger();
|
|
29
|
-
this.externalDocs = [
|
|
30
|
-
{
|
|
31
|
-
url: "https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices.md",
|
|
32
|
-
filename: "claude-skill-best-practices.md",
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
url: "https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-4-best-practices.md",
|
|
36
|
-
filename: "claude-4-best-practices.md",
|
|
37
|
-
},
|
|
38
|
-
];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
public async run(): Promise<void> {
|
|
42
|
-
try {
|
|
43
|
-
await this.ensureDocsDir();
|
|
44
|
-
const sitemap = await this.fetchText(this.sitemapUrl);
|
|
45
|
-
const docUrls = this.extractDocUrls(sitemap);
|
|
46
|
-
const markdownUrls = this.buildMarkdownUrls(docUrls);
|
|
47
|
-
await this.downloadDocs(markdownUrls);
|
|
48
|
-
await this.downloadExternalDocs();
|
|
49
|
-
} catch (error) {
|
|
50
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
51
|
-
this.logger.error(`Failed to fetch OpenCode docs: ${message}`);
|
|
52
|
-
process.exitCode = 1;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
private async ensureDocsDir(): Promise<void> {
|
|
57
|
-
await mkdir(this.docsDir, { recursive: true });
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
private async fetchText(url: string): Promise<string> {
|
|
61
|
-
const response = await fetch(url, {
|
|
62
|
-
headers: {
|
|
63
|
-
"User-Agent": "opencode-docs-fetcher",
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
if (!response.ok) {
|
|
67
|
-
throw new Error(`Request failed (${response.status}) for ${url}`);
|
|
68
|
-
}
|
|
69
|
-
return await response.text();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
private extractDocUrls(sitemap: string): string[] {
|
|
73
|
-
const urls: string[] = [];
|
|
74
|
-
const regex = /<loc>([^<]+)<\/loc>/g;
|
|
75
|
-
let match: RegExpExecArray | null = regex.exec(sitemap);
|
|
76
|
-
while (match) {
|
|
77
|
-
const url = match[1];
|
|
78
|
-
if (url !== undefined) {
|
|
79
|
-
try {
|
|
80
|
-
const parsed = new URL(url);
|
|
81
|
-
if (parsed.pathname.startsWith("/docs/")) {
|
|
82
|
-
urls.push(url);
|
|
83
|
-
}
|
|
84
|
-
} catch {
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
match = regex.exec(sitemap);
|
|
89
|
-
}
|
|
90
|
-
return Array.from(new Set(urls));
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
private buildMarkdownUrls(urls: string[]): string[] {
|
|
94
|
-
const markdownUrls: string[] = [];
|
|
95
|
-
for (const url of urls) {
|
|
96
|
-
const parsed = new URL(url);
|
|
97
|
-
if (!parsed.pathname.startsWith("/docs/")) {
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
const normalizedPath = this.normalizeDocPath(parsed.pathname);
|
|
101
|
-
if (normalizedPath === "/docs") {
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
const markdownUrl = `${parsed.origin}${normalizedPath}.md`;
|
|
105
|
-
markdownUrls.push(markdownUrl);
|
|
106
|
-
}
|
|
107
|
-
return Array.from(new Set(markdownUrls));
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
private normalizeDocPath(pathname: string): string {
|
|
111
|
-
if (pathname.endsWith("/")) {
|
|
112
|
-
return pathname.slice(0, -1);
|
|
113
|
-
}
|
|
114
|
-
return pathname;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
private async downloadDocs(urls: string[]): Promise<void> {
|
|
118
|
-
let successCount = 0;
|
|
119
|
-
let failureCount = 0;
|
|
120
|
-
for (const url of urls) {
|
|
121
|
-
try {
|
|
122
|
-
const content = await this.fetchText(url);
|
|
123
|
-
const filename = this.buildFilename(url);
|
|
124
|
-
const filePath = path.join(this.docsDir, filename);
|
|
125
|
-
await writeFile(filePath, content);
|
|
126
|
-
successCount += 1;
|
|
127
|
-
} catch (error) {
|
|
128
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
129
|
-
this.logger.error(`Failed to fetch ${url}: ${message}`);
|
|
130
|
-
failureCount += 1;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
this.logger.info(
|
|
135
|
-
`OpenCode docs fetch complete. Success: ${successCount}, Failed: ${failureCount}.`,
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
private async downloadExternalDocs(): Promise<void> {
|
|
140
|
-
let successCount = 0;
|
|
141
|
-
let failureCount = 0;
|
|
142
|
-
for (const doc of this.externalDocs) {
|
|
143
|
-
try {
|
|
144
|
-
const content = await this.fetchText(doc.url);
|
|
145
|
-
const filePath = path.join(this.docsDir, doc.filename);
|
|
146
|
-
await writeFile(filePath, content);
|
|
147
|
-
successCount += 1;
|
|
148
|
-
} catch (error) {
|
|
149
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
150
|
-
this.logger.error(`Failed to fetch ${doc.url}: ${message}`);
|
|
151
|
-
failureCount += 1;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
this.logger.info(
|
|
156
|
-
`External docs fetch complete. Success: ${successCount}, Failed: ${failureCount}.`,
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
private buildFilename(url: string): string {
|
|
161
|
-
const parsed = new URL(url);
|
|
162
|
-
const pathname = parsed.pathname;
|
|
163
|
-
if (pathname === "/docs.md" || pathname === "/docs/.md") {
|
|
164
|
-
return "index.md";
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
let relative = pathname;
|
|
168
|
-
if (relative.startsWith("/docs/")) {
|
|
169
|
-
relative = relative.slice("/docs/".length);
|
|
170
|
-
} else if (relative.startsWith("/docs")) {
|
|
171
|
-
relative = relative.slice("/docs".length);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (relative.startsWith("/")) {
|
|
175
|
-
relative = relative.slice(1);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (relative.length === 0) {
|
|
179
|
-
return "index.md";
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const normalized = relative.replace(/\//g, "-");
|
|
183
|
-
if (normalized.endsWith(".md")) {
|
|
184
|
-
return normalized;
|
|
185
|
-
}
|
|
186
|
-
return `${normalized}.md`;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (import.meta.main) {
|
|
192
|
-
void new OpenCodeDocsFetcher().run();
|
|
193
|
-
}
|
package/scripts/logger.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export interface Logger {
|
|
2
|
-
info(message: string): void;
|
|
3
|
-
error(message: string): void;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export class ConsoleLogger implements Logger {
|
|
7
|
-
public info(message: string): void {
|
|
8
|
-
console.log(message);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
public error(message: string): void {
|
|
12
|
-
console.error(message);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export class SilentLogger implements Logger {
|
|
17
|
-
public info(_message: string): void {}
|
|
18
|
-
|
|
19
|
-
public error(_message: string): void {}
|
|
20
|
-
}
|
package/tools/sync-docs.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { tool } from "@opencode-ai/plugin";
|
|
2
|
-
|
|
3
|
-
import { OpenCodeDocsFetcher } from "../scripts/fetch-opencode-docs";
|
|
4
|
-
|
|
5
|
-
type ToolDefinition = ReturnType<typeof tool>;
|
|
6
|
-
|
|
7
|
-
function createSyncDocsTool(): ToolDefinition {
|
|
8
|
-
return tool({
|
|
9
|
-
description: "Sync OpenCode documentation by fetching the latest docs from opencode.ai",
|
|
10
|
-
args: {},
|
|
11
|
-
async execute(_args, _context) {
|
|
12
|
-
try {
|
|
13
|
-
const fetcher = new OpenCodeDocsFetcher();
|
|
14
|
-
await fetcher.run();
|
|
15
|
-
return "Successfully synced OpenCode documentation.";
|
|
16
|
-
} catch (error) {
|
|
17
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
18
|
-
return `Failed to sync docs: ${message}`;
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export { createSyncDocsTool };
|