Skip to main content

Plugin Development: Overview

Welcome — you're here to build a plugin, which is how a real domain comes to life on Circus. The core platform is domain-agnostic: it provides authentication, the configuration registries, the workflow execution engine, cost accounting, dashboards, and a plugin runtime. Your plugin provides the domain — the thing you actually work on and the behaviour around it.

A plugin is an app within the app

The best way to hold this: a plugin is an app within the app. Within the platform's boundaries you have enormous freedom — define your own entity, tables, pages, API, and the domain logic your workflows drive. The possibilities are effectively open-ended, bounded only by a few simple rules (the contract) that keep your plugin a good citizen. Concretely, a plugin is a self-contained directory under plugins/{entity_slug}/ holding a manifest, migrations, routes, the services that implement its extension points, and optional frontend components — nothing about it lives outside that folder.

The concepts you'll build with

You'll meet these in depth across this package; a quick orientation:

  • Entity & entity object — your domain's type (registered in the core entity table) and its records (in your own table).
  • Workspace & the join table — the core's operational unit, linked to your entity through your {entity_slug}_workspace join table (which carries your is_deleted / is_archived flags).
  • Workspace statuses — the states your entity moves through, scoped to your entity type.
  • The manifest — the single declaration of your plugin's identity, tables, statuses, routes, menu, and extension points.
  • The four extension pointsresultHandler, workspaceSnapshotProvider, dashboardStatsProvider, workspaceDisplayResolver — the functions the core calls at the right moments.
  • Migrations and core services (the @core alias) — how you create your tables and safely touch core state.

Know your customer: the operator

One habit to build from the start: you are building for the operator. The operator is, in a real sense, your customer — they configure the models, prompts, and workflows, and they live on the pages your plugin renders. Great plugins come from developers who understand that experience. Before you get deep into manifests and migrations, it's genuinely worth walking the operator's world — how they manage entities, organize their work, and read results (the Operator docs). Building with that experience in mind is what turns a working plugin into a good product.

The reference you'll copy

You're not starting from a blank page. The default plugin (plugins/default_plugin/) is a complete, working reference implementation of everything in this package — the intended way to start is to copy it and adapt. Throughout these docs, its code is the example; studying it is the fastest way to internalise the contract.