Ops (`ops`)

In the charm SDK, the Ops (ops) library is a Python framework (available on PyPI) for developing and testing Juju charms with standard Python constructs, allowing for clean, maintainable, and reusable code and making charm development simple.

Ops provides an object-oriented, high-level wrapper to respond to Juju hooks and interact with hook tools, among other things.

While charm development has gone through multiple stages, Ops is the current state of the art.

See more: About charming history

The remainder of this doc gives a high-level overview, highlighting the main abstractions.

For more, read the Ops library API reference, and see the source code on GitHub.


The Ops library provides a top-level main method. This method should be the main entrypoint for your charm, like so:

import ops

# ... charm code

if __name__ == "__main__":

The method takes a charm class (see the next section) as an argument, and is used to initialise the charm code when the charm is invoked and ensure that events are dispatched to the charm in response to controller-emitted events.


Charm classes must extend the ops.CharmBase base class, and charm authors must ensure that their charm’s __init__ methods invoke super().__init__ so that the relevant framework events are defined for the new charm.

A charm’s __init__ method should be used to ensure that the charm observes all events relevant to its operation, and configures default values for any Stored State.

See more: ops.CharmBase


The framework, bound into each charm class instantiation as self.framework, is the main interface from the charm to the ops library’s infrastructure. It’s an object-oriented abstraction and representation of the framework itself, providing mechanisms for observing events, accessing charm metadata and configuration, manipulating charm state, etc.

See more: ops.Framework


The most important construct within the framework object is event handling. The framework uses the observer pattern^.

Each time an event is fired by the Juju controller, the charm’s __init__ method is called (meaning that a new charm object is created each time it responds to an event). So, in the __init__ method of the charm class, we use ops constructs to add observers, which are functions that take an event and an event handler as arguments.

See more: ops.Framework.observe


Ops provides a convenient way for charm authors to access a charm’s metadata, which can be achieved either by self.framework.meta or self.meta. It’s an instantiation of the CharmMeta class that provides properties for all supported metadata fields, as per the specification.

See more: ops.CharmMeta


Charms do not run as persistent processes, so the Juju controller and the Ops library facilitate access to a per-unit state store, which can be useful for tracking configuration options and other information relevant to the current deployment of the application.

See more: ops.StoredState


Pebble is a lightweight, API-driven process supervisor.

Juju controller injects Pebble into each workload container and overrides the container’s entrypoint so that Pebble starts when the container is ready. When the container is ready, typically, charms will make calls to Pebble to manage the workload, like configuring and starting the workload, performing various operations, etc.

All Juju workload management works in this way: The Juju controller sends events to the charm and the charm responds to these events by managing the workload application via Pebble.

In the ops library, Pebble (ops.pebble.Client) is a client for Pebble.

See more: ops.pebble.Client


In the Ops library, ops.Model is a wrapper/representation for the Juju model as seen from the current unit. It is the main interface to access, from a charm, information about the Juju model that the charm belongs to. For example, information about the units, relations, configurations, storage of the model, etc.

See more: ops.Model

Contributors: @benhoyt, @bittner, @dimaqq, @hpidcock , @ironcore864, @jnsgruk , @jose, @pengale, @ppasotti , @sed-i , @tmihoc, @tony-meyer, @toto

Last updated a month ago. Help improve this document in the forum.