Skip to main content
Providers let you extend Pragmatiks to manage any tool, service, or infrastructure. A provider packages the logic to create, update, and delete resources of specific types.

Why Build a Provider?

Build a provider when you want to:
  • Manage internal tools - Bring your proprietary systems into the Pragma ecosystem
  • Support new services - Add resources for cloud services, databases, or APIs not yet covered
  • Standardize operations - Encode your team’s best practices into reusable resource types
  • Enable reactive pipelines - Let your resources participate in dependency-driven workflows
Once deployed, your provider’s resources work like any other Pragma resource: users apply configurations, the platform handles lifecycle events, and outputs propagate through dependency chains.

Provider Architecture

A provider consists of three main components:

Provider

A namespace that groups related resources. Think of it like a FastAPI router that collects related endpoints.
from pragma_sdk import Provider

gcp = Provider(name="gcp")

Resource

The core abstraction. Each resource type:
  • Has a Config schema defining what users configure
  • Has an Outputs schema defining what it exposes to other resources
  • Implements lifecycle methods to handle create, update, and delete events
from pragma_sdk import Resource, Config, Outputs

class DatabaseConfig(Config):
    name: str
    size_gb: int = 10

class DatabaseOutputs(Outputs):
    connection_url: str

@gcp.resource("database")
class Database(Resource[DatabaseConfig, DatabaseOutputs]):
    async def on_create(self) -> DatabaseOutputs:
        # Create the database, return outputs
        ...

    async def on_update(self, previous_config: DatabaseConfig) -> DatabaseOutputs:
        # Handle configuration changes
        ...

    async def on_delete(self) -> None:
        # Clean up the database
        ...

Config and Outputs

Both extend Pydantic BaseModel with extra="forbid" to catch typos and invalid fields:
  • Config: User-provided settings. Define required fields, defaults, and validation.
  • Outputs: Values your resource exposes. Other resources can reference these fields.

Lifecycle Methods

Every resource implements three async methods:
MethodCalled WhenReturns
on_createResource is first provisionedOutputs
on_updateConfiguration changesOutputs
on_deleteResource is removedNone
These methods must be idempotent. The platform may retry events if delivery fails, so calling a lifecycle method twice with the same input should produce the same result.
async def on_create(self) -> SecretOutputs:
    # Idempotent: handle "already exists" gracefully
    try:
        secret = client.create_secret(...)
    except AlreadyExists:
        secret = client.get_secret(...)  # Reuse existing

    return SecretOutputs(resource_name=secret.name)

Prerequisites

Before building a provider, you need:
  • Python 3.13+ - Providers use modern Python features
  • uv - Fast Python package manager (install via curl -LsSf https://astral.sh/uv/install.sh | sh)
  • pragma-sdk - The SDK provides Provider, Resource, Config, and Outputs classes
  • Pragmatiks CLI - For initializing projects and deploying (pragma providers init)

Project Structure

Initialize a provider project:
pragma providers init mycompany
cd mycompany-provider
This creates:
mycompany-provider/
├── pyproject.toml
├── src/mycompany_provider/
│   ├── __init__.py         # Provider instance and exports
│   └── resources/
│       ├── __init__.py     # Resource exports for discovery
│       └── example.py      # Your resource implementations
└── tests/
    └── test_example.py     # Tests using ProviderHarness

Testing Locally

The SDK includes ProviderHarness for testing lifecycle methods without deploying:
from pragma_sdk.provider import ProviderHarness
from mycompany_provider import Database, DatabaseConfig

async def test_database_creation():
    harness = ProviderHarness()

    result = await harness.invoke_create(
        Database,
        name="test-db",
        config=DatabaseConfig(name="analytics", size_gb=50)
    )

    assert result.success
    assert "postgres://" in result.outputs.connection_url
The harness simulates the runtime environment, letting you verify lifecycle logic before deployment.

Deploying

Once your provider is ready:
# Register resource types with the platform
pragma providers sync

# Build and deploy
pragma providers push --deploy
After deployment, users can create resources of your types:
provider: mycompany
resource: database
name: analytics
config:
  name: analytics
  size_gb: 100

What’s Next

Follow this learning path to build and deploy your first provider: