Skip to content

Architecture

Systematic is designed as a lightweight yet powerful extension for OpenCode. It leverages native plugin hooks to inject structured workflows and specialized agents into your development environment.

The plugin is divided into two main parts:

  1. TypeScript Source (src/): The core logic that handles plugin registration, asset discovery, config validation, and model availability resolution.
  2. Bundled Assets (skills/ and agents/): Structured engineering workflows and specialized agent definitions that are automatically discovered and registered by the plugin.

On OpenCode v1 (1.18.29 and later), Systematic registers these plugin hooks. OpenCode v2 works differently; see OpenCode v2 below.

The config hook is responsible for discovery and merging. It recursively walks the bundled asset directories (skills/ and agents/) and merges their definitions into your active OpenCode configuration. This ensures that agents like @architecture-strategist are available without manual setup.

The plugin registers a custom tool called systematic_skill. This tool is used by the AI to load the full content of bundled skills on demand. While OpenCode has a native skill tool, systematic_skill provides optimized access to the plugin’s bundled content.

systematic_skill takes an optional arguments string. If the skill text contains $ARGUMENTS, that gets replaced with the whole string. If it contains $1, $2, and so on, those get replaced with positional values (quoted text counts as one value, and the highest-numbered placeholder takes the rest of the string) — the same rules OpenCode uses for its own slash commands. If the skill has none of these placeholders, the argument text is appended after the skill body instead. Leaving arguments out entirely leaves any placeholders in the skill text untouched. This is text substitution only — it never executes anything.

OpenCode truncates plugin tool output at 2,000 lines or 50 KB by default. This hook restores the full skill text after that cut so large skills still arrive complete. If your own config sets tool_output.max_lines or tool_output.max_bytes, Systematic honors your limit and skips the restore.

OpenCode’s opt-in compaction.prune setting replaces older tool results with a placeholder, and it exempts only its own built-in skill tool. This hook clears that placeholder flag on completed systematic_skill results in the request being assembled, so the model receives the stored body again. What this covers:

  • With compaction.prune on, a loaded skill’s body survives pruning and the retained tail, but not full-session summarization.
  • The edit applies only to the request. Storage still marks the result as pruned.
  • Prune still counts the body toward its protect window, which it skips for the native skill tool.
  • The full-session summarizer sees a 2,000-character slice of the body.
  • A host that predates the hook never calls it, and keeps the placeholder.

This hook allows Systematic to inject a “bootstrap” instruction into the AI’s system prompt at the start of every conversation. This instruction (from the using-systematic skill) teaches the AI how to:

  • Discover available workflows.
  • Use the systematic_skill tool.
  • Follow the “invoke before response” discipline.
  • Create git worktrees at .worktrees/<branch> under the main repository root with the git-worktree skill, unless you or a project instruction name a different location or tool. This rule is left out when git-worktree is in disabled_skills.

The same npm package runs on OpenCode v2 (2.2.5 and later). v2 has no config hook and no string-keyed hooks. Instead, the plugin’s setup function loads your configuration once and registers four things through v2’s own APIs:

  • Agents. The bundled agents are created with the same names, descriptions, prompts and modes as on v1. Systematic’s permission rules are added after OpenCode’s default rules for the agent, so a tool the rules do not mention keeps the host default. A skill list that limits an agent to certain skills still refuses every other skill, including inside subagents.
  • Skills and the systematic_skill tool. Each enabled bundled skill is added to OpenCode, so the native skill tool lists and loads it. systematic_skill is still registered, because the native tool cannot pass arguments. OpenCode cuts tool output at 2,000 lines or 50 KB after the plugin returns it, so Systematic keeps the full text and puts it back in the request. Three bundled skills (ce:review, ce:plan and ce:compound-refresh) are over that limit.
  • Commands. Each command keeps its systematic: name and (Systematic) description. Systematic expands $ARGUMENTS and $1, $2, and so on itself and sends one prompt on your session, as it is. A plugin command on v2 cannot choose an agent or a model, so a bundled Systematic command that declares agent, model or subtask is refused with an error that says so; define such a command as an OpenCode command in Markdown or JSON instead. No bundled skill declares these fields. A discovered skill that declares them is never refused: Systematic leaves the fields off, writes one note, and runs the skill on your current session. A skill discovered in your project or home directory registers as a command under its bare name, unless that name belongs to a built-in OpenCode command.
  • Bootstrap. The using-systematic instructions are stored once per session as an instruction entry that OpenCode adds to the system prompt. Title requests do not carry it.

What differs from v1:

BehaviorOpenCode v1OpenCode v2
Config changesRe-read each time OpenCode loads its configRead once when the plugin loads; restart OpenCode to apply a change
Invalid systematic.jsonThe plugin fails to loadThe same: the plugin fails to load, OpenCode logs it and keeps running
! followed by a backtick block in a commandRun by OpenCode before the prompt is sentNever run; the text stays in the prompt as written
Skill names that are whole numbersMove ahead of the * deny ruleKeep their listed order
BootstrapAdded to the system prompt on each requestStored with the session; stays after the plugin is removed, and a changed bootstrap adds a <system-update> message to sessions that already have the old one
Compaction pruning placeholderCleared for systematic_skill resultsNot applicable; v2 has no such placeholder, so nothing is cleared
tool_output limits in your configHonored: Systematic skips the restoreSystematic always restores the full skill text
Color tokens such as infoPassed throughLeft off; v2 accepts only #RRGGBB
temperature and top_pAppliedStored; v2 does not send them yet

Invalid configuration is the one failure that stops the plugin. Any other failure inside a v2 callback is logged to the OpenCode server’s standard error with a systematic: prefix and does not stop the session.

For developers looking to contribute or understand the implementation, here are the key modules:

SymbolRoleLocation
default exportPlugin object with id, setup (OpenCode v2) and server (OpenCode v1)src/index.ts
createOpenCodeV1HooksRegisters the v1 hookssrc/lib/opencode-v1.ts
setupOpenCodeV2Loads config once and runs the v2 installers (agents, skills, commands, bootstrap)src/lib/opencode-v2.ts and src/lib/opencode-v2-*.ts
buildAssetPlanHost-neutral agents, commands, skills and permission rulessrc/lib/asset-plan.ts
createConfigHandlerImplements the config hook logicsrc/lib/config-handler.ts
createSkillToolImplements the systematic_skill toolsrc/lib/skill-tool.ts
getBootstrapContentHandles system prompt injectionsrc/lib/bootstrap.ts
findSkillsInDirDiscovers bundled skillssrc/lib/skills.ts