Files
lda-wf/docs/superpowers/specs/2026-06-11-python-source-provider.md
T

4.1 KiB

Python Source Provider

Date: 2026-06-11

Status: first static config slice implemented

Related:

Purpose

wf_sources_python should prove that workflow sources are not MCP-shaped. It is not a replacement for wf_authoring; it is the provider package that loads project-local Python capabilities and projects them into WorkflowApi as ordinary CapabilitySource and executable NodeSpec objects.

Boundary

wf_authoring
  owns authoring primitives:
    @node
    NodeSpec
    build_registry / build_async_registry
    reducers
    WorkflowBuilder

wf_sources_python
  owns source-provider glue:
    config entry interpretation
    module/object loading
    validation of exported specs
    source qualification
    CapabilitySource projection

wf_server
  owns composition:
    read wf_config
    select provider by source kind
    merge provider sources with built-ins

So wf_sources_python acts more like wf_sources_mcp than wf_authoring. wf_authoring creates specs; wf_sources_python imports and exposes specs from user code.

First Slice

Start with static config only:

{
  "kind": "python",
  "id": "local.ops",
  "path": ".",
  "module": "my_project.workflow_ops",
  "registry": "registry"
}

The loaded object may be:

  • a mapping of local name to NodeSpec
  • a sequence of NodeSpec
  • a callable returning either of the above

The provider qualifies local specs under the configured source id. A local spec named echo becomes local.ops.echo. A spec already named authoring.echo should become local.ops.echo, matching built-in source qualification behavior.

Non-Goals For First Slice

  • No source registry mutation/apply support.
  • No hot reload on every call.
  • No subprocess sandbox.
  • No package installation or dependency management.
  • No move of wf.std or wf.recipes.
  • No reducer loading until a concrete use case needs it.
  • No OpenAPI/HTTP source behavior.

Error Policy

Configuration and import errors should fail server construction clearly:

  • module cannot be imported
  • registry object is missing
  • registry object is not a supported shape
  • exported value is not a NodeSpec
  • duplicate local spec names inside one Python source

Runtime errors from Python node execution are ordinary workflow node failures, not source-load failures.

Why Not Move wf.recipes

wf.recipes is first-party built-in workflow content. It belongs with local sources because it is always available and versioned with the platform.

wf_sources_python is for user/project-defined source entries configured by a server operator. It should be optional and explicit.

Later Slices

After static config works:

  1. Add source registry/apply support for Python source entries.
  2. Consider explicit development reload.
  3. Consider reducer exports if a real project source needs custom reducers.
  4. Consider isolation policy for untrusted Python. The first version is trusted in-process code only.

Implementation Status

Implemented:

  • wf_config accepts server.sources[] entries with kind: "python".
  • wf_sources_python loads trusted in-process NodeSpec registries from path plus module:registry.
  • wf_sources_python.PythonSourceProvider implements the static WorkflowSourceProvider.load_sources() seam used by wf_server.config.
  • wf config validate imports configured trusted Python sources and reports missing modules, missing registries, invalid registry shapes, and duplicate specs before server startup.
  • Capability listing/calling works over JSON-RPC.
  • JSON-RPC integration coverage now proves a Python source capability can be converted into a draft artifact, deployed with required source bindings, and run as a workflow.

Still deferred:

  • mutable source registry/apply support
  • hot reload
  • reducer exports
  • sandboxing/untrusted code