Documentation
Plugins
How Syrus plugins extend UI, tools, prompts, graders, previews, and integrations.
Plugins
Plugins are installed extension bundles. Installing a plugin makes its code available after restart; enabling a plugin makes its surfaces visible and its behavior active. In general, the plugin enable switch is the feature flag for that plugin.
What Plugins Can Add
Plugins can contribute:
- sidebar and admin navigation entries,
- repository tabs,
- React components bundled into the app,
- MCP tools for chat and workflow agents,
- prompt context injectors,
- typed artifact renderers,
- preview providers,
- prepare detectors,
- grader augmentors,
- CI log parsers,
- dependency-audit commands,
- affected-test analyzers,
- source integrations such as GitHub or Linear,
- speech-to-text backends for chat dictation.
Plugins can also declare stable credential type names for a credential-management plugin to discover. These declarations are intentionally metadata-only: a name such as k8s_cluster.kubeconfig, plus optional safe label and description text. Credential storage, encryption, payload parsing, authorization, broker materialization, redaction, and credential-use callbacks remain outside this hook.
The core app should keep behavior that is required for Syrus to function. Plugins should be things that can reasonably be disabled, replaced, or distributed separately.
Bundled Plugin Directory
The public plugin directory at /plugins is generated from the bundled plugin manifests, so it is the most complete browsable list. This snapshot calls out the launch-relevant groups:
| Group | Bundled plugins |
|---|---|
| Agent providers | Claude Agent, Codex Agent, Antigravity Agent, Muse Agent |
| Work inputs and planning | Walkthrough Videos, Scheduled Tasks, GitHub Source, Linear Source, Design Docs, Operator Briefing |
| Repository intelligence | Agent Insights, Agent Memory, Git History, Search, Test Insights, Throughput, Metrics Dashboard, Spending Insights |
| Language and platform support | Android, Browser (Playwright), Django, Go, iOS, Java, JavaScript, Kotlin, Python, Rails, Ruby |
| Runtime and infrastructure | Git Mirror, GitHub Host, Kubernetes Cluster Viewer, Plugin Runtime, Tailscale, Terminal, Runtime Terminal, Worker Timeline, Build Cache |
Worker Timeline uses the shared composable filter bar and Smart Folders. Saved timeline expressions can combine supported fields with nested AND, OR, and NOT groups across workflow spans, pending workflows, and idle worker lanes.
The Kubernetes Cluster Viewer reports kubeconfig credential expiry in its admin cluster list. Operators rotate pasted tokens or client certificates by editing the existing connection and pasting a replacement kubeconfig, which keeps cluster identity and access settings intact. OIDC auth-provider kubeconfigs with refresh credentials renew automatically shortly before expiry; failures appear as a degraded credential state without exposing secret material. | Collaboration and UI | Agent Activity, Review Notes, Credential Store, Discord, Mockups, Team Directory, Theming Tools, Whiteboard | | Data and admin tools | Admin MySQL, MySQL DB Browser, Alertmanager Investigations, Syrus Dev, Whisper speech-to-text |
Whiteboard's high-level arrow tool creates connectors anchored to the visible edges of rectangles, stickies, ellipses, and diamonds. Optional arrow labels render as bound text and move with the connector, while raw scene updates remain available for advanced Excalidraw geometry.
Metrics Dashboard records the same bounded metrics exposed to Prometheus. Its feature-usage and admission-decision counters combine increments from every web and worker process into monotonic shared totals. If that cross-process snapshot is unavailable or stale, those charts omit new readings and show an operator warning instead of presenting the recorder process's local zero as complete.
MySQL DB Browser connections inherit access from their Credential Store scope: user, repository, team, or instance. New connections default to the creating user, while existing instance-scoped connections remain shared until an admin narrows them. Legacy embedded passwords are admin-only until migrated by re-entering the password in the connection editor.
Provider copy on the homepage and FAQ should use the adapter display names from plugins/*/lib/*.rb and AgentProviders::*#display_name, not hand-rolled model names. As of this release, the provider adapters are Claude Code, Codex, Antigravity, and Muse Code.
Installed vs Enabled
Installed means the plugin's code, migrations, translations, and frontend assets are present. Enabled means Syrus uses the plugin at runtime. This lets operators install a plugin during deployment but turn it on only for the repositories or users that need it.
Some plugins may be non-disableable because they provide core surfaces for a given distribution. Most should be disableable.
Some bundled plugins are marked experimental. They remain visible in Admin -> Plugins and are still part of the installed Syrus build, but a self-hosted instance must enable beta mode before enabling them. When an experimental plugin is disabled and beta mode is off, the Admin Plugins page shows an Experimental badge and an Enable beta mode action. The same server-side guard applies to API calls and dependency cascades, so a stable plugin cannot be enabled if that action would also turn on an experimental dependency. Beta mode does not enable any plugin by itself; it only allows admins to explicitly turn on beta or experimental capabilities.
A disabled plugin is not loaded. Its code stays resolvable, so enabling it takes effect immediately without a restart, but Syrus does not pay to load features nobody can reach. Migrations are the exception and always run at deploy time regardless of enabled state, so enabling a plugin finds its tables ready.
Disabling a plugin stops it doing work; it does not throw away the data it already wrote. That data is still cleaned up when its owner is -- deleting a repository still takes its plugin rows with it, whether the plugin is on or off.
Suggested Plugins
Syrus can tell you a plugin is worth turning on before you go looking for it. A plugin can declare what its own signal looks like, and Admin -> Plugins shows the ones this instance appears to want, with the evidence behind each: how many of your repositories are Python, which repositories have a resolvable Django settings module, whether you are running more than one worker host, or whether you are on MySQL. Plugins you have already enabled are never suggested, and a suggestion with no evidence behind it is not shown at all.
The repository side of this is observed while Syrus already has a clone in hand, during a normal run, so a repository Syrus has never worked on produces no suggestion.
Plugin Data
Plugins can own database tables. When they do, table names and model namespaces should make ownership obvious, such as linear_tickets for Linear::Ticket. Plugin migrations should avoid surprising global changes and should follow the same no-foreign-key policy as the rest of Syrus.
MCP Tools
Workflow and chat agents see tools through toolsets. A plugin should expose a toolset as the registration point, but individual tools should stay small and separately testable. Good tools have narrow inputs, clear side effects, and structured results.
Tool usage is logged so operators can see which tools are active, failing, or worth consolidating.
UI Contributions
Admin and repository pages are discovered from plugin declarations. Disabling a plugin hides those pages, but the compiled JavaScript can remain part of the app bundle. This keeps runtime enable/disable simple while still allowing plugin pages to use normal React components.
Dependencies
Plugins may depend on other plugins. If a dependency is disabled, Syrus should warn or cascade-disable dependent plugins rather than exposing a broken UI surface.
Authoring Guidelines
Keep plugin boundaries crisp:
- put plugin-specific tests with the plugin,
- namespace plugin models,
- prefix plugin-owned tables,
- use extension points instead of monkey-patching core behavior,
- make runtime disablement leave the rest of Syrus usable,
- keep the core test suite free of plugin specifics, so removing a plugin
entirely leaves a passing suite rather than a red one.
Syrus checks the last two by actually removing a plugin: bin/plugin-boundary-audit <plugin> copies the checkout, deletes that plugin plus everything that depends on it, and runs a command of your choosing — a boot check by default, or the full test suite — against what is left.