Extending formae
formae is designed to be highly extensible. It uses a flexible yet simple plugin model to allow engineers to add support for technologies that aren't yet supported.
Policy
The following policy defines the architectural and licensing expectations for plugins.
Plugins are independent works developed and distributed separately from formae components.
Plugins execute as separate processes or remote services and communicate with formae components exclusively through documented public interfaces. Plugins are not loaded, linked, or executed in-process.
Plugin developers may license their plugins under any license of their choosing, including open-source or proprietary licenses. Such licenses apply only to the plugin itself and do not affect the licensing of formae components or other plugins.
Plugins must not impose license terms, usage restrictions, or distribution obligations on formae components, their source code, or their users beyond those explicitly agreed in writing.
No formae component is a derivative work of any plugin, and no plugin is a derivative work of any formae component.
Plugin SDK
The formae Plugin SDK lets you extend formae to manage any infrastructure that exposes any sort of an API. Plugins implement CRUD operations (Create, Read, Update, Delete) and discovery for resource types that formae doesn't support out of the box.
When to Build a Plugin
Build a plugin when you need formae to manage resources in a system it doesn't already support:
- An infrastructure platform (SFTP servers, databases, message queues)
- A SaaS platform with an API (monitoring tools, CI/CD systems, DNS providers)
- Internal systems with custom APIs
- Any system where resources have a lifecycle (create, modify, delete)
How Plugins Work
Plugins run as separate processes that communicate with the formae agent. When the agent starts, it discovers installed plugins and spawns them. Each plugin announces its capabilities (supported resource types, rate limits) and the agent routes operations to the appropriate plugin.
┌─────────────────────────┐ ┌─────────────────────────┐
│ formae agent │ │ Your Plugin │
│ │ │ │
│ • Discovers plugins │ ───► │ • Announces types │
│ • Routes requests │ │ • Handles CRUD │
│ • Enforces rate limits │ ◄─── │ • Returns results │
└─────────────────────────┘ └─────────────────────────┘
This architecture provides:
- Isolation - Plugin crashes don't affect the agent
- Independent updates - Update plugins without updating formae
- Simplicity - Your plugin just implements a Go interface
What You'll Build
After scaffolding a formae plugin project, you'll implement two things:
- Resource schemas (
schema/pkl/*.pkl) - Define your resource types in PKL - ResourcePlugin interface (
plugin.go) - Implement CRUD operations and discovery
type ResourcePlugin interface {
// Configuration
RateLimit() RateLimitConfig
LabelConfig() LabelConfig
DiscoveryFilters() []MatchFilter
// CRUD + Discovery
Create(context.Context, *CreateRequest) (*CreateResult, error)
Read(context.Context, *ReadRequest) (*ReadResult, error)
Update(context.Context, *UpdateRequest) (*UpdateResult, error)
Delete(context.Context, *DeleteRequest) (*DeleteResult, error)
Status(context.Context, *StatusRequest) (*StatusResult, error)
List(context.Context, *ListRequest) (*ListResult, error)
}
Prerequisites
Before building a plugin, you should be familiar with:
- Go programming - Structs, interfaces, error handling, JSON marshaling
- Your target system's API - How to authenticate and perform CRUD operations
- PKL basics - For defining resource schemas (see PKL cheatsheet)
Getting Started
The Tutorial walks you through building a complete SFTP File plugin from scratch. You'll learn:
- How to scaffold a plugin project
- How to define resource schemas in PKL
- How to implement CRUD operations with proper error handling
- How to write tests using TDD
- How to run conformance tests in CI
For quick reference, see:
- ResourcePlugin Interface - Full API specification
- Manifest Format - Plugin manifest fields
- Schema Reference - PKL annotations for resources