opencode-ultracode 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Abdulkadir Polat
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,243 @@
1
+ # opencode-ultracode
2
+
3
+ [![npm version](https://img.shields.io/npm/v/opencode-ultracode.svg)](https://www.npmjs.com/package/opencode-ultracode)
4
+ [![license](https://img.shields.io/github/license/polatdev/opencode-ultracode.svg)](https://github.com/polatdev/opencode-ultracode/blob/main/LICENSE)
5
+
6
+ Multi-agent workflow orchestration for [opencode](https://opencode.ai). The model
7
+ writes a small JavaScript script that fans a task out across phases of parallel
8
+ sub-agents, and you watch, pause, resume and stop the run from a live
9
+ `/workflows` view inside the TUI.
10
+
11
+ It's a plugin, not an MCP server, not a separate app. There is **no daemon and
12
+ no service** to run — the engine lives inside your opencode process, sub-agents
13
+ are ordinary opencode child sessions, and progress is written to a state file
14
+ the TUI polls.
15
+
16
+ ```
17
+ ╭ ⠋ audit-payments ──────────────────────────────────────────────────────────╮
18
+ │ phases │ agent model ctx tools time │
19
+ │ ● 1 Scan 12/12 │ ✓ find:webhooks sonnet-4 38k 6 tools 41s │
20
+ │ ● 2 Verify 18/24 │ ⠋ verify:idem-2 sonnet-4 21k 3 tools 12s │
21
+ │ ○ 3 Synthesize 0/1 │ ⠋ verify:idem-3 qwen3.8 17k 2 tools 9s │
22
+ │ │ ○ verify:retry-1 sonnet-4 │
23
+ ├────────────────────────────────────────────────────────────────────────────┤
24
+ │ ⠋ verify:idem-2 │ grep done · src/Services/Payment 3s ago │
25
+ ╰────────────────────────────────────────────────────────────────────────────╯
26
+ ↑↓ agent ←→ pane ⏎ open agent r result x stop p pause s save esc back
27
+ ```
28
+
29
+ ## Why
30
+
31
+ Some tasks do not fit one context: auditing every handler in a large codebase,
32
+ migrating dozens of files, reviewing a big diff from several angles, or
33
+ research that needs independent verification before you trust it. A single
34
+ agent either runs out of context or quietly narrows the job.
35
+
36
+ `opencode-ultracode` gives the model a `workflow` tool that decomposes such a
37
+ task into phases of parallel sub-agents with structured outputs, asks you to
38
+ approve the plan, runs it in the background, and delivers the result back into
39
+ your session when it is done. You get a live view of every agent, its model,
40
+ context size, tool calls and thinking, and you can stop or pause at any point.
41
+
42
+ ## Install
43
+
44
+ The package ships two entrypoints: the **server plugin** (the tool and the
45
+ engine) and the **TUI plugin** (the `/workflows` screens). Each goes in its
46
+ own config file.
47
+
48
+ Server plugin — add it to `opencode.json` (global `~/.config/opencode/opencode.json`
49
+ or per-project):
50
+
51
+ ```json
52
+ {
53
+ "$schema": "https://opencode.ai/config.json",
54
+ "plugin": [
55
+ "opencode-ultracode"
56
+ ]
57
+ }
58
+ ```
59
+
60
+ TUI plugin — add the same package to `tui.json` (global `~/.config/opencode/tui.json`
61
+ or per-project `.opencode/tui.json`):
62
+
63
+ ```json
64
+ {
65
+ "$schema": "https://opencode.ai/tui.json",
66
+ "plugin": [
67
+ "opencode-ultracode"
68
+ ]
69
+ }
70
+ ```
71
+
72
+ opencode installs npm plugins automatically at startup — there is nothing to
73
+ `npm install` yourself. Restart opencode and `/workflows` opens the run list.
74
+
75
+ ### From a checkout
76
+
77
+ To run the plugin from source instead, point both config files at the entry
78
+ files:
79
+
80
+ ```json
81
+ // opencode.json
82
+ { "plugin": ["/path/to/opencode-ultracode/src/server/index.ts"] }
83
+ ```
84
+
85
+ ```json
86
+ // tui.json
87
+ { "plugin": ["/path/to/opencode-ultracode/src/tui/index.tsx"] }
88
+ ```
89
+
90
+ ## How it works
91
+
92
+ Ask for it in plain words. Any of these make the model call the tool right away:
93
+
94
+ > run a workflow that audits every payment handler for missing idempotency checks
95
+ >
96
+ > ultracode: migrate all repositories from Doctrine to Eloquent
97
+
98
+ For a large task you did not phrase this way, the model recommends a workflow
99
+ (phases and rough agent count) and waits for your go-ahead.
100
+
101
+ 1. The model authors a script, or picks a saved one, and calls `workflow`.
102
+ 2. opencode shows a permission prompt with the plan: name, description, phases.
103
+ 3. The run starts in the background. Open `/workflows` to watch it.
104
+ 4. When the run finishes, its result arrives as a new turn in the session that
105
+ started it.
106
+
107
+ Sub-agents run in their own child sessions with the project's tools and
108
+ permissions. When one of them is blocked on a permission or a question, the
109
+ workflow views flag it and let you answer without leaving the screen.
110
+
111
+ If opencode exits while a run is in progress, the run is not lost. Every
112
+ completed agent is journaled, so resuming replays those results and only runs
113
+ the remaining agents again.
114
+
115
+ ### The `workflow` tool
116
+
117
+ | Argument | Meaning |
118
+ |---------------|---------------------------------------------------------------------|
119
+ | `script` | Inline workflow script |
120
+ | `scriptPath` | Path to a script file |
121
+ | `name` | Saved workflow from `.opencode/workflows/<name>.js` |
122
+ | `args` | Value exposed to the script as `args` |
123
+ | `resumeRunId` | Resume a stopped run, or one whose engine died, by its run id |
124
+
125
+ ### Writing a script
126
+
127
+ Scripts are plain JavaScript. They begin with a pure-literal `meta` block and
128
+ then use the primitives below. The bundled `workflow-authoring` skill teaches
129
+ the model the full format and the quality patterns; it is registered
130
+ automatically in every project the plugin is loaded in.
131
+
132
+ ```js
133
+ export const meta = {
134
+ name: 'review-changes',
135
+ description: 'Review changed files across dimensions, verify each finding',
136
+ phases: [{ title: 'Review' }, { title: 'Verify' }, { title: 'Synthesize' }],
137
+ }
138
+
139
+ const FINDING = { type: 'object', properties: { findings: { type: 'array' } }, required: ['findings'] }
140
+ const VERDICT = { type: 'object', properties: { isReal: { type: 'boolean' }, why: { type: 'string' } }, required: ['isReal'] }
141
+
142
+ const dims = [
143
+ { key: 'bugs', prompt: 'Review the current diff for correctness bugs…' },
144
+ { key: 'perf', prompt: 'Review the current diff for performance problems…' },
145
+ ]
146
+
147
+ // pipeline: each dimension moves on to Verify as soon as its own Review is done
148
+ const verified = await pipeline(
149
+ dims,
150
+ d => agent(d.prompt, { label: `review:${d.key}`, phase: 'Review', schema: FINDING }),
151
+ r => parallel((r?.findings ?? []).map(f => () =>
152
+ agent(`Try to REFUTE this finding: ${JSON.stringify(f)}`, { label: `verify:${f.file}`, phase: 'Verify', schema: VERDICT })
153
+ .then(v => ({ ...f, verdict: v }))
154
+ )),
155
+ )
156
+
157
+ phase('Synthesize')
158
+ const confirmed = verified.flat().filter(Boolean).filter(f => f.verdict?.isReal)
159
+ log(`${confirmed.length} confirmed findings`)
160
+ return await agent(`Write the final report for these findings: ${JSON.stringify(confirmed)}`, { label: 'report' })
161
+ ```
162
+
163
+ | Primitive | What it does |
164
+ |------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
165
+ | `agent(prompt, opts?)` | Spawns a sub-agent in its own session. Resolves to the schema-validated object or the final text, `null` on failure or stop. `opts`: `label`, `phase`, `schema`, `model`. |
166
+ | `parallel(thunks)` | Runs `Array<() => Promise>` concurrently and waits for all of them. A throwing thunk becomes `null`. |
167
+ | `pipeline(items, ...stages)` | Runs each item through every stage independently, with no barrier between stages. The default choice. |
168
+ | `phase(title)` | Starts a display phase. Use the same titles as `meta.phases`. |
169
+ | `log(message)` | Narrator line shown in the run view. |
170
+ | `args` | Whatever the tool call passed as `args`. |
171
+ | `budget` | `{ total, spent(), remaining() }`. `agent()` throws once `total` is reached. |
172
+
173
+ Scripts have no filesystem, network or Node APIs. `Date.now()`, `Math.random()`
174
+ and no-arg `new Date()` throw so a resumed run replays deterministically.
175
+ Concurrency is capped at roughly `min(16, cpus - 2)` agents at a time and
176
+ 1000 agents per run.
177
+
178
+ ## The `/workflows` TUI
179
+
180
+ | Screen | Keys |
181
+ |--------------|---------------------------------------------------------------------------------------------------------------------------------------------------|
182
+ | Run list | `↑↓` select · `⏎` open · `r` result · `x` stop · `p` pause / resume · `s` save script · `d` delete · `esc` back |
183
+ | Run view | `↑↓` phase or agent · `←→` switch pane · `⏎` open · `r` result · `x` stop · `p` pause / resume · `s` save · `!` answer a pending permission |
184
+ | Agent detail | `↑↓` scroll · `←→` previous / next agent · `e` show tool and thinking previews · `p` expand prompt · `⏎` answer a permission or question |
185
+ | Result view | `↑↓` scroll · `g` top |
186
+
187
+ The agent detail shows a **Live** feed while the agent runs (text, thinking
188
+ marked `∴`, tool calls marked `⚙`, newest first), the prompt, an **Activity**
189
+ list with one row per tool call and per thinking block with its duration, and
190
+ the final outcome.
191
+
192
+ ```
193
+ Activity · 3 tools · 2 thoughts e shows previews
194
+ ✓ grep /Users/me/PhpstormProjects/payzink-api 0s
195
+ ✓ think Retry logic lives in the webhook handler, so the idempotency… 16s
196
+ ✓ read src/Services/Payment/RetryService.php 1s
197
+ ⠋ think Comparing the two idempotency checks… 3s
198
+ ```
199
+
200
+ Thinking rows appear only when the provider streams reasoning. With thinking
201
+ disabled the list holds tool calls only.
202
+
203
+ ### Where things live
204
+
205
+ | Path | Contents |
206
+ |------------------------------------------------------|------------------------------------------------------------------------------------------------------------|
207
+ | `/tmp/opencode-workflows/<project>-<hash>/<runId>/` | Run artifacts: `state.json`, `journal.jsonl`, `script.js`, `control.json`. Scratch data, safe to delete. |
208
+ | `<project>/.opencode/workflows/<name>.js` | Saved workflows (`s` in the TUI). Project assets; commit them if you like. |
209
+
210
+ The TUI polls `state.json` and merges it fine-grained, so only changed cells
211
+ redraw. Pause, resume and stop are written to `control.json` and picked up by
212
+ the engine.
213
+
214
+ ## Requirements
215
+
216
+ - opencode `>= 1.3.4`
217
+ - Node.js >= 22 (only matters if you're developing the plugin itself; end
218
+ users just add it to `opencode.json` and `tui.json`)
219
+
220
+ ## Development
221
+
222
+ ```bash
223
+ npm install
224
+ npm run typecheck # tsc --noEmit
225
+ npm run test:runtime # engine self-test against a mock opencode client
226
+ ```
227
+
228
+ ```
229
+ src/
230
+ server/index.ts server plugin: workflow tool, triggers, system guidance, usage tracking
231
+ runtime/engine.ts run engine: agents, phases, journal, resume, state file
232
+ runtime/script.ts script parsing and the deterministic sandbox
233
+ runtime/schema.ts structured-output schema handling
234
+ tui/index.tsx TUI plugin: /workflows routes and keymaps
235
+ tui/store.ts state.json polling and fine-grained merge
236
+ tui/requests.ts pending permission / question tracking for sub-agents
237
+ shared/ types and formatting shared by both plugins
238
+ skills/workflow-authoring/SKILL.md
239
+ ```
240
+
241
+ ## License
242
+
243
+ MIT © [Abdulkadir Polat](https://github.com/polatdev)
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "opencode-ultracode",
3
+ "version": "0.1.0",
4
+ "description": "Workflow orchestration for opencode: model-authored scripts, parallel sub-agent fleet, live TUI progress view",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Abdulkadir Polat",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/polatdev/opencode-ultracode.git"
11
+ },
12
+ "homepage": "https://github.com/polatdev/opencode-ultracode#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/polatdev/opencode-ultracode/issues"
15
+ },
16
+ "keywords": [
17
+ "opencode",
18
+ "opencode-plugin",
19
+ "workflow",
20
+ "multi-agent",
21
+ "orchestration",
22
+ "tui"
23
+ ],
24
+ "exports": {
25
+ "./server": "./src/server/index.ts",
26
+ "./tui": "./src/tui/index.tsx"
27
+ },
28
+ "files": [
29
+ "src",
30
+ "skills",
31
+ "README.md",
32
+ "LICENSE"
33
+ ],
34
+ "engines": {
35
+ "opencode": ">=1.3.4"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "scripts": {
41
+ "typecheck": "tsc --noEmit",
42
+ "test:runtime": "node src/runtime/selftest.ts",
43
+ "prepublishOnly": "npm run typecheck && npm run test:runtime"
44
+ },
45
+ "dependencies": {
46
+ "@opencode-ai/plugin": "^1.15.13"
47
+ },
48
+ "peerDependencies": {
49
+ "@opentui/solid": "^0.5.11",
50
+ "solid-js": "^1.9.0"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^22.0.0",
54
+ "typescript": "^5.6.0",
55
+ "@opentui/keymap": "^0.5.11",
56
+ "@opentui/solid": "^0.5.11",
57
+ "solid-js": "^1.9.0",
58
+ "zod": "^4.1.8"
59
+ }
60
+ }
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: workflow-authoring
3
+ description: "Reference for authoring opencode workflow scripts: meta block, agent()/parallel()/pipeline()/phase()/log(), structured output schemas, quality patterns. Use ONLY when writing or editing a workflow script for the workflow tool."
4
+ ---
5
+
6
+ # Workflow authoring (opencode-workflow)
7
+
8
+ A workflow structures work across many agents — to be comprehensive (decompose and
9
+ cover in parallel), to be confident (independent perspectives and adversarial checks
10
+ before committing), or to take on scale one context can't hold (migrations, audits,
11
+ broad sweeps). The script is where you encode that structure: what fans out, what
12
+ verifies, what synthesizes.
13
+
14
+ Hybrid tip: scout inline first (list the files, scope the diff) to discover the
15
+ work-list, then call the `workflow` tool and pipeline over it.
16
+
17
+ ## Meta block (required, pure literal)
18
+
19
+ Every script starts with:
20
+
21
+ ```js
22
+ export const meta = {
23
+ name: 'find-flaky-tests',
24
+ description: 'Find flaky tests and propose fixes', // one line, shown in the approval dialog
25
+ whenToUse: 'when tests are flaky', // optional
26
+ phases: [ // optional; one entry per phase() call
27
+ { title: 'Scan', detail: 'grep test logs for retries' },
28
+ { title: 'Fix', detail: 'one agent per flaky test' },
29
+ ],
30
+ }
31
+ ```
32
+
33
+ - `meta` must be a PURE LITERAL — no variables, function calls, spreads, template strings.
34
+ - Use the SAME phase titles in `meta.phases` as in `phase()` calls.
35
+ - `name` is used for saving (`s` in /workflows) and for invoking saved workflows by name.
36
+
37
+ ## Script body primitives
38
+
39
+ - `agent(prompt, opts?)` → spawns a sub-agent in an isolated child session; resolves to
40
+ its structured result (with `schema`) or final text (without). Resolves to `null` if
41
+ the run is stopped or the agent fails — filter with `.filter(Boolean)`.
42
+ - `opts.label` — display name (shown in /workflows), e.g. `'tip:design'`
43
+ - `opts.phase` — assign to a progress group (use inside pipeline/parallel stages)
44
+ - `opts.schema` — JSON Schema; the agent is forced to return a matching JSON object
45
+ - `opts.model` — e.g. `'anthropic/claude-sonnet-4'`; omit to inherit the session model
46
+ - `parallel(thunks)` → run `Array<() => Promise>` concurrently; BARRIER (awaits all).
47
+ A throwing thunk yields `null` in the result array — the call never rejects.
48
+ - `pipeline(items, stage1, stage2, ...)` → run each item through all stages INDEPENDENTLY,
49
+ no barrier between stages. Stage callback receives `(prevResult, originalItem, index)`.
50
+ A throwing stage drops that item to `null` and skips its remaining stages.
51
+ - `phase(title)` → start a display phase; subsequent agents group under it.
52
+ - `log(message)` → narrator line in /workflows.
53
+ - `args` → value passed via the tool's `args` input (undefined if omitted).
54
+ - `budget` → `{ total, spent(), remaining() }`. `total` is null unless the user set a
55
+ token target; once `spent()` reaches `total`, further `agent()` calls throw.
56
+
57
+ **DEFAULT TO pipeline().** Use `parallel()` (a barrier) only when stage N genuinely needs
58
+ ALL of stage N-1's results at once (dedup across findings, early-exit on zero, comparing
59
+ "the other findings"). Otherwise a barrier wastes the fast finders' time.
60
+
61
+ ## Constraints in scripts
62
+
63
+ - Plain JavaScript (not TypeScript). No filesystem, no Node API, no network.
64
+ - `Date.now()`, `Math.random()`, and no-arg `new Date()` THROW (determinism for resume).
65
+ Pass timestamps in via `args`; vary prompts/labels by index instead of randomness.
66
+ - Concurrency is capped (~min(16, cpus-2) parallel agents); the total agent cap is 1000.
67
+ - Sub-agents run in their own sessions with the project's tools and permissions — for
68
+ long autonomous runs, pre-allow the tools agents need.
69
+
70
+ ## Quality patterns
71
+
72
+ - Adversarial verify: N independent skeptics per finding prompted to REFUTE; kill if
73
+ ≥majority refute.
74
+ - Perspective-diverse verify: distinct lenses (correctness, security, perf, repro)
75
+ instead of N identical refuters.
76
+ - Judge panel: N independent attempts from different angles, scored by parallel judges,
77
+ synthesize from the winner.
78
+ - Loop-until-dry: keep spawning finders until K consecutive rounds return nothing new.
79
+ - Multi-modal sweep: parallel agents each searching a different way (by-container,
80
+ by-content, by-entity).
81
+ - Completeness critic: final agent asks "what's missing?" — its findings become the
82
+ next round.
83
+ - No silent caps: `log()` anything you truncate top-N or drop.
84
+
85
+ ## Scale
86
+
87
+ "find any bugs" → a few finders, single-vote verify. "thoroughly audit this" → larger
88
+ finder pool, 3-vote adversarial pass, synthesis stage. Runs with >25 agents are flagged
89
+ as large — expect a permission prompt for the plan either way.