{{ message }}
Tags: codemcp/workflows
Tags
fix(cli): bundle js-yaml into CLI dist to prevent ERR_MODULE_NOT_FOUN… …D on npx ## Intent When the CLI wizard is run via `npx @codemcp/workflows-cli`, the root package that npx installs does not include js-yaml as a transitive dependency visible at runtime. The wizard reads .vibe/config.yaml using js-yaml at startup, which causes an ERR_MODULE_NOT_FOUND crash. ## Key decisions - Added 'js-yaml' to the noExternal list in tsup.config.ts so it is inlined into the bundle at build time, making the CLI self-contained regardless of what the npx install resolution picks up - js-yaml is already declared in the package's dependencies (so it is present during the build); this change only affects the output bundling, not the dependency graph
feat: model capability routing for workflow phases
Workflow phases can declare a 'required_capability' to guide the LLM in
choosing an appropriate subagent and/or model for that phase. The user
wires up the capability→model/agent mapping in .vibe/config.yaml
(manually or via the new 'setup capabilities' CLI wizard). The feature
is fully opt-in: absent required_capability and absent capability_models
yields no behavioral change.
When a phase declares required_capability, the InstructionGenerator
embeds a hint into the phase instructions, e.g.:
Capability hint: This phase requires thinking capability (deep
reasoning, complex planning). When launching subagents, use agent:
thinking (model: anthropic/claude-opus-4-7).
'thinking' and 'research' ship with a built-in description; 'coding' is
deliberately self-evident; any other term is echoed verbatim.
Configuration
.vibe/config.yaml accepts an optional capability_models map of
{ model?, agent? } per capability. Both fields are optional; either,
neither, or both may be set. ConfigManager validates the structure and
accepts the existing config shape unchanged.
CLI wizard
npx @codemcp/workflows setup capabilities <target> \
[--model-thinking X --model-coding Y --model-research Z] [--force]
For each --model-<capability> provided, writes a per-target agent file
(e.g. .opencode/agents/<capability>.md for OpenCode, mode: subagent
with the chosen model) and merges the matching capability_models entry
into .vibe/config.yaml. Per-target agent files are produced from
templates shipped under resources/templates/opencode-agents/. Existing
per-target files are skipped by default; --force overwrites.
Only 'opencode' is currently implemented. Other registered targets
(kiro, claude, gemini, vscode, github-copilot) are stubs that throw
'not yet supported' and exit non-zero, but they are listed in
'setup capabilities --help' with a ⏳ status so users can see the wizard
is extensible. The architecture mirrors the per-target registry used
by ConfigGenerator and SkillGenerator — adding a new target is a single
class.
Workflow annotations
7 built-in workflows (qrspi, epcc, greenfield, waterfall, bugfix, tdd,
pr-review) annotate 23 phases with required_capability. Out of the
box, annotated phases still emit label-only hints; capability_models
config is only required for the LLM to know which model/agent to use.
Documentation
New user-facing page at packages/docs/user/capability-routing.md,
linked from the VitePress sidebar under 'User Guide'. Covers what you
get, declaring required_capability in a workflow YAML, configuring
capability_models in .vibe/config.yaml, the 'setup capabilities' CLI
command (flags, targets, examples), and which built-in workflows ship
with annotations.
Tests
936 tests across 4 packages (core 467, server 286, opencode 64, cli
119). The capability routing surface has dedicated unit tests for
formatCapabilityHint, the ProjectConfig validation rules, the
InstructionGenerator integration, the built-in workflow annotations
spot-check, and the per-target capability generator (registry,
concrete opencode impl, stubs, config merge).
fix(opencode-plugin): use SDK types directly and harden ask() against… … return-type changes The plugin manually duplicated all types from @opencode-ai/plugin instead of importing them, causing types.ts to silently go stale whenever the SDK changed. This caused the Fiber.runLoop crash when SDK 1.15.x reverted ToolContext.ask from Effect.Effect<void> back to Promise<void>. Changes: - Add @opencode-ai/plugin as peerDependency (dev + peer) so SDK types are available at compile time and mismatches are caught by the type checker - Replace types.ts manual copies with re-exports from @opencode-ai/plugin; only BusEvent subtypes (session.compacted / session.idle) remain local because the SDK does not export them individually yet - Add runAsk() helper in plugin.ts that detects at runtime whether ctx.ask() returned an Effect (identified by the stable '~effect/Effect' TypeId property key) or a plain Promise, and dispatches accordingly — a deliberate monkey-patch that insulates the plugin against future SDK flip-flops on this return type - Update wrap() to call runAsk() instead of Effect.runPromise() directly - Update test mock: ask now returns Promise.resolve() to match SDK 1.15.x; comment explains that runAsk() handles both forms
fix: embed workflow descriptions in tool description instead of .desc… …ribe() OpenCode does not propagate Zod parameter .describe() text to the LLM. Confirmed by canary test - descriptions are invisible regardless of zod instance or registry. The tool description IS propagated, so embed the workflow enum choices and their descriptions there directly. Also removes the tool.definition hook and globalRegistry bridging code which were solving the wrong problem.
PreviousNext
