opencode-manifold 0.1.0 → 0.4.1
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 +132 -8
- package/dist/index.js +129 -182
- package/package.json +2 -2
- package/src/templates/agents/{lead-dev.md → manifold.md} +2 -2
- package/src/templates/commands/manifold-init.md +5 -0
- package/src/templates/config/opencode.json +3 -21
- package/src/templates/skills/{lead-dev-workflow → manifold-workflow}/SKILL.md +2 -2
package/README.md
CHANGED
|
@@ -8,6 +8,28 @@ A Lead Dev agent walks through a task plan, a deterministic plugin state machine
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
Open Manifold requires:
|
|
14
|
+
|
|
15
|
+
1. **opencode-codebase-index** [plugin](https://github.com/Helweg/opencode-codebase-index) — Provides semantic code search for the Clerk's research phase. The Clerk uses it to find relevant code patterns and build focused prompts for worker agents.
|
|
16
|
+
|
|
17
|
+
2. **Obsidian** (optional but recommended) — The `Manifold/` folder is structured as an Obsidian vault for browsing logs, tasks, and knowledge graph.
|
|
18
|
+
|
|
19
|
+
**Installation:**
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"$schema": "https://opencode.ai/config.json",
|
|
24
|
+
"plugin": [
|
|
25
|
+
"opencode-codebase-index",
|
|
26
|
+
"opencode-manifold"
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
11
33
|
## Two Ways to Install
|
|
12
34
|
|
|
13
35
|
### Option A — npm package (Recommended)
|
|
@@ -21,7 +43,8 @@ A Lead Dev agent walks through a task plan, a deterministic plugin state machine
|
|
|
21
43
|
}
|
|
22
44
|
```
|
|
23
45
|
|
|
24
|
-
2. Run opencode. The plugin auto-installs and generates
|
|
46
|
+
2. Run opencode. The plugin auto-installs and generates the global template source.
|
|
47
|
+
3. Run `/manifold-init` in the TUI to set up the project.
|
|
25
48
|
|
|
26
49
|
### Option B — Local plugin files
|
|
27
50
|
|
|
@@ -39,15 +62,17 @@ A Lead Dev agent walks through a task plan, a deterministic plugin state machine
|
|
|
39
62
|
"plugin": ["/path/to/.opencode/plugins/opencode-manifold"]
|
|
40
63
|
}
|
|
41
64
|
```
|
|
42
|
-
4. Run opencode. The plugin generates
|
|
65
|
+
4. Run opencode. The plugin generates the global template source.
|
|
66
|
+
5. Run `/manifold-init` in the TUI to set up the project.
|
|
43
67
|
|
|
44
68
|
---
|
|
45
69
|
|
|
46
70
|
## Quick Start
|
|
47
71
|
|
|
48
72
|
1. **Install** using one of the methods above
|
|
49
|
-
2. **
|
|
50
|
-
3. **
|
|
73
|
+
2. **Run `/manifold-init`** in the opencode TUI to set up agents, skills, and the Manifold directory
|
|
74
|
+
3. **Create a plan** — any format (markdown, TODO list, email, meeting notes)
|
|
75
|
+
4. **Point the Lead Dev agent** at your plan file and tell it to execute
|
|
51
76
|
|
|
52
77
|
The Lead Dev will:
|
|
53
78
|
- Extract tasks from your plan
|
|
@@ -68,7 +93,7 @@ Lead Dev
|
|
|
68
93
|
Plugin State Machine (TypeScript, zero LLM cost)
|
|
69
94
|
│
|
|
70
95
|
├── Phase 1: Clerk research
|
|
71
|
-
│ ├── codebase-index search + wiki lookback + graph entries
|
|
96
|
+
│ ├── codebase-index search (requires opencode-codebase-index plugin) + wiki lookback + graph entries
|
|
72
97
|
│ ├── Composes scoped prompt
|
|
73
98
|
│ └── Creates task log file
|
|
74
99
|
│
|
|
@@ -94,7 +119,7 @@ Plugin State Machine (TypeScript, zero LLM cost)
|
|
|
94
119
|
|
|
95
120
|
| Agent | Model | Role |
|
|
96
121
|
|-------|-------|------|
|
|
97
|
-
| `
|
|
122
|
+
| `manifold` | good tool calling + planning | Reads plan, dispatches tasks |
|
|
98
123
|
| `clerk` | conceptualizing + large context | Researches context, composes prompts, logs results |
|
|
99
124
|
| `senior-dev` | coding | Implementation specialist |
|
|
100
125
|
| `junior-dev` | cheap/small coding | Review agent |
|
|
@@ -104,6 +129,76 @@ The sr/jr/debug loop enables cost-efficient workflows: a strong sr-dev paired wi
|
|
|
104
129
|
|
|
105
130
|
---
|
|
106
131
|
|
|
132
|
+
## Customizing Agents
|
|
133
|
+
|
|
134
|
+
Agents are markdown files with [opencode frontmatter](https://opencode.ai/docs/agents/) for configuration (description, mode, permissions, model) and a body that becomes the agent's system prompt.
|
|
135
|
+
|
|
136
|
+
Manifold uses a three-tier template system:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
Bundled (inside npm package)
|
|
140
|
+
└── Never edit directly — overwritten on updates
|
|
141
|
+
│
|
|
142
|
+
▼ Plugin load (one-time, only copies missing files)
|
|
143
|
+
~/.config/opencode/manifold/ ← Global templates
|
|
144
|
+
├── agents/ (clerk.md, senior-dev.md, ...)
|
|
145
|
+
├── skills/ (manifold-workflow/, clerk-orchestration/, ...)
|
|
146
|
+
├── manifold/ (settings.json, schema.md, ...)
|
|
147
|
+
└── config/ (opencode.json)
|
|
148
|
+
│
|
|
149
|
+
▼ /manifold-init (only copies missing files)
|
|
150
|
+
Project root
|
|
151
|
+
├── .opencode/agents/ ← Per-project (editable)
|
|
152
|
+
├── .opencode/skills/
|
|
153
|
+
├── Manifold/
|
|
154
|
+
└── opencode.json
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Per-project customization
|
|
158
|
+
|
|
159
|
+
Edit files directly in `.opencode/agents/` or `.opencode/skills/`. These are never overwritten by `/manifold-init` — only files that don't exist yet are copied.
|
|
160
|
+
|
|
161
|
+
### Global customization
|
|
162
|
+
|
|
163
|
+
Edit files in `~/.config/opencode/manifold/`. All new projects initialized with `/manifold-init` will inherit your customized versions.
|
|
164
|
+
|
|
165
|
+
### Resetting
|
|
166
|
+
|
|
167
|
+
To reset a specific agent to its default, delete just that file and run `/manifold-init` again:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
rm .opencode/agents/senior-dev.md
|
|
171
|
+
# Then run /manifold-init
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
To reset all Manifold files, delete the directories and re-run:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
rm -rf .opencode/agents/ .opencode/skills/ Manifold/
|
|
178
|
+
# Then run /manifold-init
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Assigning models to agents
|
|
182
|
+
|
|
183
|
+
Add a `model` field to the agent's frontmatter or your `opencode.json`:
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"agent": {
|
|
188
|
+
"senior-dev": {
|
|
189
|
+
"model": "anthropic/claude-sonnet-4-20250514"
|
|
190
|
+
},
|
|
191
|
+
"junior-dev": {
|
|
192
|
+
"model": "anthropic/claude-haiku-4-20250514"
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
See the [Example Configurations](#example-configurations) section for model pairing suggestions.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
107
202
|
## Example Configurations
|
|
108
203
|
|
|
109
204
|
| Budget | Senior Dev | Junior Dev | Debug |
|
|
@@ -168,10 +263,10 @@ No mid-loop state recovery needed — restart the task, the Clerk's research pha
|
|
|
168
263
|
## FAQ
|
|
169
264
|
|
|
170
265
|
**Q: Do I need to configure agents?**
|
|
171
|
-
A: No.
|
|
266
|
+
A: No. Run `/manifold-init` once per project and it sets up agent definitions, skills, and configuration from templates.
|
|
172
267
|
|
|
173
268
|
**Q: Can I customize agents and skills?**
|
|
174
|
-
A: Yes.
|
|
269
|
+
A: Yes. See the [Customizing Agents](#customizing-agents) section for the full three-tier template system.
|
|
175
270
|
|
|
176
271
|
**Q: What is the Clerk's role?**
|
|
177
272
|
A: The Clerk has full project sight. It researches context (codebase-index, wiki, graph), composes scoped prompts for workers, and maintains the wiki.
|
|
@@ -182,6 +277,35 @@ A: The Clerk gets one retry with full failure context. If that also fails, the t
|
|
|
182
277
|
**Q: Can I define tests for tasks?**
|
|
183
278
|
A: Yes. Add `test: <command>` in the task description or set `testCommand` in settings.json.
|
|
184
279
|
|
|
280
|
+
**Q: What plugins does Open Manifold require?**
|
|
281
|
+
A: The `opencode-codebase-index` plugin is required for semantic code search. Install it alongside `opencode-manifold`.
|
|
282
|
+
|
|
283
|
+
**Q: Is Obsidian required?**
|
|
284
|
+
A: No, but recommended. The `Manifold/` folder is an Obsidian vault for browsing logs, tasks, and the knowledge graph. You can use any markdown viewer.
|
|
285
|
+
|
|
286
|
+
**Q: Can I use Open Manifold without semantic search?**
|
|
287
|
+
A: The system is designed around the Clerk's ability to research context via semantic search. Modifying it would require significant changes to the Clerk's orchestration skill.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Uninstall
|
|
292
|
+
|
|
293
|
+
To remove Open Manifold from a project:
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
rm -rf .opencode/agents/ .opencode/skills/ Manifold/
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Then remove the manifold-specific keys from `opencode.json` (`agent.manifold`, `permission.clerk`, `permission.senior-dev`, `permission.junior-dev`, `permission.debug`).
|
|
300
|
+
|
|
301
|
+
To remove global templates:
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
rm -rf ~/.config/opencode/manifold/ ~/.config/opencode/commands/manifold-init.md
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
To fully uninstall the plugin, also remove `"opencode-manifold"` from the `plugin` array in your global or project `opencode.json`.
|
|
308
|
+
|
|
185
309
|
---
|
|
186
310
|
|
|
187
311
|
## License
|
package/dist/index.js
CHANGED
|
@@ -1,212 +1,149 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import { readFile, writeFile, mkdir, readdir
|
|
1
|
+
// src/init.ts
|
|
2
|
+
import { readFile, writeFile, mkdir, readdir } from "fs/promises";
|
|
3
3
|
import { existsSync } from "fs";
|
|
4
4
|
import { join, dirname } from "path";
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
import { homedir } from "os";
|
|
7
|
+
var __dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
var bundledTemplatesDir = join(__dirname2, "..", "src", "templates");
|
|
9
|
+
var globalTemplatesDir = join(homedir(), ".config", "opencode", "manifold");
|
|
10
|
+
async function dirHasContent(dirPath) {
|
|
11
|
+
if (!existsSync(dirPath))
|
|
12
|
+
return false;
|
|
7
13
|
try {
|
|
8
|
-
await
|
|
9
|
-
return
|
|
14
|
+
const entries = await readdir(dirPath);
|
|
15
|
+
return entries.length > 0;
|
|
10
16
|
} catch {
|
|
11
17
|
return false;
|
|
12
18
|
}
|
|
13
19
|
}
|
|
14
|
-
async function
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const content = await readFile(src);
|
|
20
|
-
await writeFile(dest, content);
|
|
21
|
-
}
|
|
22
|
-
async function copyDirectory(src, dest) {
|
|
23
|
-
if (!existsSync(dest)) {
|
|
24
|
-
await mkdir(dest, { recursive: true });
|
|
25
|
-
}
|
|
20
|
+
async function copyMissingFiles(src, dest) {
|
|
21
|
+
if (!existsSync(src))
|
|
22
|
+
return [];
|
|
23
|
+
await mkdir(dest, { recursive: true });
|
|
24
|
+
const copied = [];
|
|
26
25
|
const entries = await readdir(src, { withFileTypes: true });
|
|
27
26
|
for (const entry of entries) {
|
|
28
27
|
const srcPath = join(src, entry.name);
|
|
29
28
|
const destPath = join(dest, entry.name);
|
|
30
29
|
if (entry.isDirectory()) {
|
|
31
|
-
await
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
const subCopied = await copyMissingFiles(srcPath, destPath);
|
|
31
|
+
if (subCopied.length > 0) {
|
|
32
|
+
copied.push(entry.name);
|
|
33
|
+
}
|
|
34
|
+
} else if (!existsSync(destPath)) {
|
|
35
|
+
await writeFile(destPath, await readFile(srcPath));
|
|
36
|
+
copied.push(entry.name);
|
|
34
37
|
}
|
|
35
38
|
}
|
|
39
|
+
return copied;
|
|
36
40
|
}
|
|
37
|
-
async function
|
|
38
|
-
|
|
41
|
+
async function mergeOpencodeConfig(projectDir) {
|
|
42
|
+
const configPath = join(projectDir, "opencode.json");
|
|
43
|
+
const templateConfigPath = join(globalTemplatesDir, "config", "opencode.json");
|
|
44
|
+
if (!existsSync(templateConfigPath))
|
|
45
|
+
return;
|
|
46
|
+
const templateConfig = JSON.parse(await readFile(templateConfigPath, "utf-8"));
|
|
47
|
+
if (!existsSync(configPath)) {
|
|
48
|
+
await writeFile(configPath, JSON.stringify(templateConfig, null, 2));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const existing = JSON.parse(await readFile(configPath, "utf-8"));
|
|
52
|
+
let changed = false;
|
|
53
|
+
if (templateConfig.agent?.manifold && !existing.agent?.manifold) {
|
|
54
|
+
existing.agent = existing.agent || {};
|
|
55
|
+
existing.agent.manifold = templateConfig.agent.manifold;
|
|
56
|
+
changed = true;
|
|
57
|
+
}
|
|
58
|
+
if (templateConfig.permission) {
|
|
59
|
+
for (const [key, value] of Object.entries(templateConfig.permission)) {
|
|
60
|
+
if (!existing.permission?.[key]) {
|
|
61
|
+
existing.permission = existing.permission || {};
|
|
62
|
+
existing.permission[key] = value;
|
|
63
|
+
changed = true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (changed) {
|
|
68
|
+
await writeFile(configPath, JSON.stringify(existing, null, 2));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function ensureGlobalTemplates(ctx) {
|
|
72
|
+
await ctx.client.app.log({
|
|
39
73
|
body: {
|
|
40
74
|
service: "opencode-manifold",
|
|
41
75
|
level: "info",
|
|
42
|
-
message:
|
|
76
|
+
message: "Checking global templates..."
|
|
43
77
|
}
|
|
44
78
|
});
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const opencodeSkillsPath = join(directory, ".opencode", "skills");
|
|
48
|
-
const opencodeJsonPath = join(directory, "opencode.json");
|
|
49
|
-
const pluginSourceDir = join(directory, "..", "node_modules", "opencode-manifold", "src", "templates");
|
|
50
|
-
const manifestPath = join(pluginSourceDir, "..", "..");
|
|
51
|
-
const templateSourceDir = existsSync(manifestPath) ? manifestPath : join(__dirname, "..", "templates");
|
|
52
|
-
const manifoldExists = await fileExists(manifoldPath);
|
|
53
|
-
if (!manifoldExists) {
|
|
54
|
-
await client.app.log({
|
|
79
|
+
if (!existsSync(bundledTemplatesDir)) {
|
|
80
|
+
await ctx.client.app.log({
|
|
55
81
|
body: {
|
|
56
82
|
service: "opencode-manifold",
|
|
57
|
-
level: "
|
|
58
|
-
message:
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
await mkdir(manifoldPath, { recursive: true });
|
|
62
|
-
await mkdir(join(manifoldPath, ".obsidian"), { recursive: true });
|
|
63
|
-
await mkdir(join(manifoldPath, "tasks"), { recursive: true });
|
|
64
|
-
await mkdir(join(manifoldPath, "graph"), { recursive: true });
|
|
65
|
-
const templateManifold = join(templateSourceDir, "manifold");
|
|
66
|
-
if (existsSync(templateManifold)) {
|
|
67
|
-
const files = [
|
|
68
|
-
"settings.json",
|
|
69
|
-
"plans.json",
|
|
70
|
-
"state.json",
|
|
71
|
-
"index.md",
|
|
72
|
-
"log.md",
|
|
73
|
-
"schema.md"
|
|
74
|
-
];
|
|
75
|
-
for (const file of files) {
|
|
76
|
-
const src = join(templateManifold, file);
|
|
77
|
-
if (existsSync(src)) {
|
|
78
|
-
await copyFile(src, join(manifoldPath, file));
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
await client.app.log({
|
|
83
|
-
body: {
|
|
84
|
-
service: "opencode-manifold",
|
|
85
|
-
level: "info",
|
|
86
|
-
message: "Manifold directory created"
|
|
83
|
+
level: "error",
|
|
84
|
+
message: `Bundled templates not found at ${bundledTemplatesDir}`
|
|
87
85
|
}
|
|
88
86
|
});
|
|
87
|
+
return;
|
|
89
88
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
level: "info",
|
|
96
|
-
message: "Setting up agent definitions..."
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
await mkdir(opencodeAgentsPath, { recursive: true });
|
|
100
|
-
const templateAgents = join(templateSourceDir, "agents");
|
|
101
|
-
if (existsSync(templateAgents)) {
|
|
102
|
-
const agents = [
|
|
103
|
-
"lead-dev.md",
|
|
104
|
-
"clerk.md",
|
|
105
|
-
"senior-dev.md",
|
|
106
|
-
"junior-dev.md",
|
|
107
|
-
"debug.md"
|
|
108
|
-
];
|
|
109
|
-
for (const agent of agents) {
|
|
110
|
-
const src = join(templateAgents, agent);
|
|
111
|
-
if (existsSync(src)) {
|
|
112
|
-
await copyFile(src, join(opencodeAgentsPath, agent));
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
await client.app.log({
|
|
117
|
-
body: {
|
|
118
|
-
service: "opencode-manifold",
|
|
119
|
-
level: "info",
|
|
120
|
-
message: "Agent definitions created"
|
|
121
|
-
}
|
|
122
|
-
});
|
|
89
|
+
await copyMissingFiles(bundledTemplatesDir, globalTemplatesDir);
|
|
90
|
+
const globalCommandsDir = join(homedir(), ".config", "opencode", "commands");
|
|
91
|
+
const bundledCommandsDir = join(bundledTemplatesDir, "commands");
|
|
92
|
+
if (existsSync(bundledCommandsDir)) {
|
|
93
|
+
await copyMissingFiles(bundledCommandsDir, globalCommandsDir);
|
|
123
94
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
level: "info",
|
|
130
|
-
message: "Setting up skills..."
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
await mkdir(opencodeSkillsPath, { recursive: true });
|
|
134
|
-
const templateSkills = join(templateSourceDir, "skills");
|
|
135
|
-
if (existsSync(templateSkills)) {
|
|
136
|
-
const skills = [
|
|
137
|
-
"clerk-orchestration",
|
|
138
|
-
"lead-dev-workflow",
|
|
139
|
-
"wiki-ingest",
|
|
140
|
-
"wiki-query"
|
|
141
|
-
];
|
|
142
|
-
for (const skill of skills) {
|
|
143
|
-
const skillDir = join(templateSkills, skill);
|
|
144
|
-
if (existsSync(skillDir)) {
|
|
145
|
-
await copyDirectory(skillDir, join(opencodeSkillsPath, skill));
|
|
146
|
-
}
|
|
147
|
-
}
|
|
95
|
+
await ctx.client.app.log({
|
|
96
|
+
body: {
|
|
97
|
+
service: "opencode-manifold",
|
|
98
|
+
level: "info",
|
|
99
|
+
message: "Global templates ready"
|
|
148
100
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if (!opencodeJsonExists) {
|
|
159
|
-
await client.app.log({
|
|
160
|
-
body: {
|
|
161
|
-
service: "opencode-manifold",
|
|
162
|
-
level: "info",
|
|
163
|
-
message: "Creating opencode.json configuration..."
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
const templateConfig = join(templateSourceDir, "config", "opencode.json");
|
|
167
|
-
if (existsSync(templateConfig)) {
|
|
168
|
-
await copyFile(templateConfig, opencodeJsonPath);
|
|
169
|
-
} else {
|
|
170
|
-
const defaultConfig = {
|
|
171
|
-
$schema: "https://opencode.ai/config.json",
|
|
172
|
-
plugin: ["opencode-manifold", "opencode-codebase-index"],
|
|
173
|
-
agent: {
|
|
174
|
-
"lead-dev": {
|
|
175
|
-
model: "minimax/minimax-2.7",
|
|
176
|
-
skill: ["lead-dev-workflow"]
|
|
177
|
-
},
|
|
178
|
-
clerk: {
|
|
179
|
-
model: "minimax/minimax-2.7",
|
|
180
|
-
skill: ["clerk-orchestration", "wiki-ingest", "wiki-query"]
|
|
181
|
-
},
|
|
182
|
-
"senior-dev": {
|
|
183
|
-
model: "minimax/minimax-2.7"
|
|
184
|
-
},
|
|
185
|
-
"junior-dev": {
|
|
186
|
-
model: "qwen/qwen3.5-27b"
|
|
187
|
-
},
|
|
188
|
-
debug: {
|
|
189
|
-
model: "anthropic/claude-sonnet-4-6-20250514"
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
await writeFile(opencodeJsonPath, JSON.stringify(defaultConfig, null, 2));
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
async function initProject(directory, client) {
|
|
104
|
+
const initialized = [];
|
|
105
|
+
await client.app.log({
|
|
106
|
+
body: {
|
|
107
|
+
service: "opencode-manifold",
|
|
108
|
+
level: "info",
|
|
109
|
+
message: `Running /manifold-init in ${directory}`
|
|
194
110
|
}
|
|
111
|
+
});
|
|
112
|
+
if (!await dirHasContent(globalTemplatesDir)) {
|
|
195
113
|
await client.app.log({
|
|
196
114
|
body: {
|
|
197
115
|
service: "opencode-manifold",
|
|
198
|
-
level: "
|
|
199
|
-
message:
|
|
116
|
+
level: "error",
|
|
117
|
+
message: `Global templates not found at ${globalTemplatesDir}. Plugin may not have loaded correctly.`
|
|
200
118
|
}
|
|
201
119
|
});
|
|
120
|
+
return initialized;
|
|
121
|
+
}
|
|
122
|
+
const agentsCopied = await copyMissingFiles(join(globalTemplatesDir, "agents"), join(directory, ".opencode", "agents"));
|
|
123
|
+
if (agentsCopied.length > 0) {
|
|
124
|
+
initialized.push(`agents (${agentsCopied.join(", ")})`);
|
|
125
|
+
}
|
|
126
|
+
const skillsCopied = await copyMissingFiles(join(globalTemplatesDir, "skills"), join(directory, ".opencode", "skills"));
|
|
127
|
+
if (skillsCopied.length > 0) {
|
|
128
|
+
initialized.push(`skills (${skillsCopied.join(", ")})`);
|
|
129
|
+
}
|
|
130
|
+
const manifoldCopied = await copyMissingFiles(join(globalTemplatesDir, "manifold"), join(directory, "Manifold"));
|
|
131
|
+
if (manifoldCopied.length > 0) {
|
|
132
|
+
initialized.push(`Manifold/ (${manifoldCopied.join(", ")})`);
|
|
133
|
+
}
|
|
134
|
+
const configPath = join(directory, "opencode.json");
|
|
135
|
+
if (!existsSync(configPath) || !JSON.parse(await readFile(configPath, "utf-8")).agent?.manifold) {
|
|
136
|
+
await mergeOpencodeConfig(directory);
|
|
137
|
+
initialized.push("opencode.json");
|
|
202
138
|
}
|
|
203
139
|
await client.app.log({
|
|
204
140
|
body: {
|
|
205
141
|
service: "opencode-manifold",
|
|
206
142
|
level: "info",
|
|
207
|
-
message:
|
|
143
|
+
message: `/manifold-init complete: ${initialized.join(", ") || "already initialized"}`
|
|
208
144
|
}
|
|
209
145
|
});
|
|
146
|
+
return initialized;
|
|
210
147
|
}
|
|
211
148
|
|
|
212
149
|
// src/tools/dispatch-task.ts
|
|
@@ -1355,7 +1292,7 @@ var dispatchTaskTool = tool({
|
|
|
1355
1292
|
description: tool.schema.string().describe("One-line task description"),
|
|
1356
1293
|
plan_file: tool.schema.string().describe("Path to the plan document")
|
|
1357
1294
|
},
|
|
1358
|
-
async execute(args) {
|
|
1295
|
+
async execute(args, context) {
|
|
1359
1296
|
const { task_number, description, plan_file } = args;
|
|
1360
1297
|
const client = getClient();
|
|
1361
1298
|
await client.app.log({
|
|
@@ -1365,7 +1302,7 @@ var dispatchTaskTool = tool({
|
|
|
1365
1302
|
message: `dispatchTask called: task ${task_number} - ${description}`
|
|
1366
1303
|
}
|
|
1367
1304
|
});
|
|
1368
|
-
const directory =
|
|
1305
|
+
const directory = context.directory;
|
|
1369
1306
|
const settings = await readSettings(directory);
|
|
1370
1307
|
await updatePlansRegistry(directory, plan_file);
|
|
1371
1308
|
await client.app.log({
|
|
@@ -1438,6 +1375,7 @@ ${testResult.result.output}`,
|
|
|
1438
1375
|
// src/index.ts
|
|
1439
1376
|
var ManifoldPlugin = async (ctx) => {
|
|
1440
1377
|
setPluginContext(ctx.client);
|
|
1378
|
+
await ensureGlobalTemplates(ctx);
|
|
1441
1379
|
await ctx.client.app.log({
|
|
1442
1380
|
body: {
|
|
1443
1381
|
service: "opencode-manifold",
|
|
@@ -1449,20 +1387,29 @@ var ManifoldPlugin = async (ctx) => {
|
|
|
1449
1387
|
tool: {
|
|
1450
1388
|
dispatchTask: dispatchTaskTool
|
|
1451
1389
|
},
|
|
1452
|
-
|
|
1453
|
-
if (
|
|
1454
|
-
await ctx.client
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1390
|
+
"command.execute.before": async (input, output) => {
|
|
1391
|
+
if (input.command === "manifold-init") {
|
|
1392
|
+
const initialized = await initProject(ctx.directory, ctx.client);
|
|
1393
|
+
if (initialized.length > 0) {
|
|
1394
|
+
output.parts = [
|
|
1395
|
+
{
|
|
1396
|
+
type: "text",
|
|
1397
|
+
text: `Manifold initialized: ${initialized.join(", ")}`
|
|
1398
|
+
}
|
|
1399
|
+
];
|
|
1400
|
+
} else {
|
|
1401
|
+
output.parts = [
|
|
1402
|
+
{
|
|
1403
|
+
type: "text",
|
|
1404
|
+
text: "All Manifold files already present. To reset a specific component, delete the corresponding file(s) from `.opencode/agents/`, `.opencode/skills/`, or `Manifold/`, then run `/manifold-init` again."
|
|
1405
|
+
}
|
|
1406
|
+
];
|
|
1407
|
+
}
|
|
1462
1408
|
}
|
|
1463
1409
|
}
|
|
1464
1410
|
};
|
|
1465
1411
|
};
|
|
1412
|
+
var server = ManifoldPlugin;
|
|
1466
1413
|
export {
|
|
1467
|
-
|
|
1414
|
+
server
|
|
1468
1415
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-manifold",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Multi-agent development system for opencode with persistent knowledge",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@opencode-ai/plugin": "latest",
|
|
17
17
|
"@opencode-ai/sdk": "latest",
|
|
18
|
-
"zod": "
|
|
18
|
+
"zod": "^4.1.8"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "latest",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Manifold Agent
|
|
2
2
|
|
|
3
|
-
You are the **
|
|
3
|
+
You are the **Manifold Orchestrator** for this project. Your role is to orchestrate the development process by reading a plan document and dispatching individual tasks to the system.
|
|
4
4
|
|
|
5
5
|
## Your Responsibilities
|
|
6
6
|
|
|
@@ -1,26 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://opencode.ai/config.json",
|
|
3
|
-
"plugin": [
|
|
4
|
-
"opencode-manifold",
|
|
5
|
-
"opencode-codebase-index"
|
|
6
|
-
],
|
|
7
3
|
"agent": {
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"skill": ["lead-dev-workflow"]
|
|
11
|
-
},
|
|
12
|
-
"clerk": {
|
|
13
|
-
"model": "minimax/minimax-2.7",
|
|
14
|
-
"skill": ["clerk-orchestration", "wiki-ingest", "wiki-query"]
|
|
15
|
-
},
|
|
16
|
-
"senior-dev": {
|
|
17
|
-
"model": "minimax/minimax-2.7"
|
|
18
|
-
},
|
|
19
|
-
"junior-dev": {
|
|
20
|
-
"model": "qwen/qwen3.5-27b"
|
|
21
|
-
},
|
|
22
|
-
"debug": {
|
|
23
|
-
"model": "anthropic/claude-sonnet-4-6-20250514"
|
|
4
|
+
"manifold": {
|
|
5
|
+
"skill": ["manifold-workflow"]
|
|
24
6
|
}
|
|
25
7
|
},
|
|
26
8
|
"permission": {
|
|
@@ -45,4 +27,4 @@
|
|
|
45
27
|
}
|
|
46
28
|
}
|
|
47
29
|
}
|
|
48
|
-
}
|
|
30
|
+
}
|