Skip to content

SDK reference

Generated from the docstrings in civex-plugin-sdk's public API (civex_plugin_sdk.__all__). See Writing a plugin for a guide to using it.

civex_plugin_sdk

SDK for authoring out-of-process (subprocess/container tier) civex workflow plugins.

Subclass Plugin, declare id/name/inputs/outputs/Config, implement invoke(), and call serve() (Tier 1) or serve_container() (Tier 2) from the plugin script's __main__ -- see docs/extending/writing-a-plugin.md for the full authoring guide.

IO_TYPES = ('any', 'string', 'number', 'boolean', 'bytes', 'table', 'files', 'records', 'mapping', 'list') module-attribute

Vocabulary for IOSpec.type.

Deliberately coarse: a step input/output is a live Python object (a DataFrame, raw bytes, a list of FileRef dicts), so this names the shape a workflow author needs to know when wiring one step into the next, not a validatable type. Nothing ever validates a runtime value against it -- host-side contract checking matches input and output names, never types.

any      no constraint / plugin-specific
string   text scalar
number   int or float
boolean  true/false
bytes    raw binary payload
table    tabular data (a pandas DataFrame in-process)
files    list of FileRef dicts ({sha256, filename, size})
records  list of record dicts
mapping  dict keyed by field/column name
list     list of anything not covered by files/records

Plugin

Bases: PluginBase, ABC

Out-of-process plugin contract: PluginBase's declarative surface plus the one method that actually does the work.

Subclass this, set the PluginBase class attributes (id, name, inputs, outputs, Config, ...), and implement invoke(). Pass the subclass to civex_plugin_sdk.serve() (Tier 1) or serve_container() (Tier 2) -- nothing else needs to instantiate it.

invoke(inputs, config, ctx) abstractmethod

Run this plugin for one workflow step.

Parameters:

Name Type Description Default
inputs dict[str, Any]

Step inputs, keyed by name, already converted from the wire form to invoke-time values (e.g. a declared table input arrives as a pandas DataFrame, not the wire envelope).

required
config Any

An instance of this plugin's Config model, already validated against the run frame's config dict.

required
ctx Ctx

The RPC-backed handle for reading/writing records, files, schemas, and collections beyond what inputs/config already supplied.

required

Returns:

Type Description
dict[str, Any]

Step outputs, keyed by name, matching this plugin's declared

dict[str, Any]

outputs (when declared). Converted to the wire form

dict[str, Any]

automatically -- return a DataFrame or raw bytes directly for a

dict[str, Any]

table/bytes output.

PluginBase

Declarative metadata shared by every plugin tier (BUILTIN, SUBPROCESS, CONTAINER).

Set the class attributes below on a subclass; invoke() itself is declared separately by each tier (see this package's Plugin for the out-of-process one).

Config

Bases: BaseModel

A plugin's run-time configuration.

Override with the fields this plugin actually accepts; the model is rendered to JSON Schema for describe and validated against the run frame's config dict before invoke() is called.

IOSpec

Bases: BaseModel

One declared input or output of a plugin.

type is a plain str rather than a Literal[IO_TYPES] on purpose: this model crosses the wire in a describe_result, and a Literal would make an older host fail discovery entirely on a plugin built against a newer SDK that added a vocabulary entry. An unrecognized type should degrade to being displayed as-is, not take the plugin down. In-repo declarations are held to the vocabulary by test, where a typo is worth failing on.

Ctx

The handle invoke() receives for everything beyond inputs/config: records, files, schemas, and collections.

Every method blocks on a single rpc_call/rpc_result round trip over writer/reader -- there is no batching or concurrency, so a plugin calling several Ctx methods pays one blocking round trip per call.

get_context_record()

Return the record that triggered this workflow step.

Ctx has no ambient .record/.dataset fields the way in-process WorkflowContext does -- this (and get_context_dataset()) is the only way an out-of-process plugin learns what triggered it.

get_context_dataset()

Return the dataset that owns get_context_record()'s record.

get_file(sha256)

Return the raw bytes stored under sha256 in the object store.

store_file(data, filename)

Write data to the object store and return its FileRef dict ({sha256, filename, size}).

update_record(record_id, data)

Merge data into the record identified by record_id and return the updated record.

create_record(dataset_name, schema_name, data, context_record_id=None)

Create a record in dataset_name against schema_name and return it.

context_record_id, when omitted, defaults host-side to get_context_record()'s id -- see WorkflowContext.create_record's docstring for why it isn't called parent_record_id.

get_record(record_id)

Return the record identified by record_id.

find_records(dataset_name, schema_name=None, parent_record_id=None, filters=None, search=None, limit=50, offset=0)

Return records in dataset_name matching the given filters.

Parameters:

Name Type Description Default
dataset_name str

Dataset to search within.

required
schema_name str | None

Restrict to records of this schema, if given.

None
parent_record_id str | None

Restrict to children of this record, if given.

None
filters list[str] | None

Host-parsed filter expressions (field/operator/value), ANDed together.

None
search str | None

Free-text search over the dataset's searchable fields.

None
limit int

Maximum number of records to return.

50
offset int

Number of matching records to skip, for pagination.

0

Returns:

Type Description
list[dict[str, Any]]

The matching records, most-recent-first.

delete_record(record_id)

Delete the record identified by record_id.

get_schema(name)

Return the schema named name, including its resolved fields.

list_schemas()

Return every schema in the project.

get_collection(name)

Return the collection named name.

list_collections()

Return every collection in the project.

commit()

Persist every write this Ctx made so far.

Mirrors AppContext.commit()'s in-process contract: nothing a plugin writes via update_record/create_record/store_file/the call_tool mutators is guaranteed durable until this is called (or the workflow step ends and the executor commits on the plugin's behalf).

PluginError

Bases: Exception

Base class for every error this SDK raises. Carries the {kind, message, retryable} envelope this module documents above.

Raise this directly (with a custom kind) from invoke() for a failure that doesn't fit one of the more specific subclasses below.

to_envelope()

Return the {kind, message, retryable} dict this error sends over the wire.

CapabilityDeniedError

Bases: PluginError

Raised host-side when a plugin issues an rpc_call for a method it didn't declare in its describe capabilities list.

ConfigValidationError

Bases: PluginError

Raised when incoming run config fails validation against the plugin's declared Config model.

RpcError

Bases: PluginError

Raised plugin-side when the host responds to an rpc_call with an error frame.

serve_container(plugin_cls)

Container-tier entrypoint: isolates the actual stdout fd, then performs exactly one describe or run (per sys.argv[1]) off real stdin.

Call this (and only this) from a container-tier plugin's main -- see docs/extending/container-plugins.md.

serve(plugin_cls)

Real entrypoint: isolates the actual stdout fd, then serves forever off real stdin.

Call this (and only this) from a plugin's main.