12 KiB
wf_api Slice 3A: Refs And Constants Move Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Move the protocol-neutral workflow API refs and constants helpers from wf_mcp.workflow_surface into wf_api, while preserving old imports as compatibility shims.
Architecture: wf_api is now the canonical home for process-local workflow API helpers that are not MCP-specific. This slice moves only constants.py and refs.py because both are small and import only wf_artifacts / wf_platform. wf_mcp.workflow_surface.constants and wf_mcp.workflow_surface.refs remain thin re-export shims so existing imports keep working.
Tech Stack: Python 3.14+, Pydantic-backed refs from wf_artifacts and wf_platform, pytest, ruff, basedpyright.
Scope
In Scope
- Create
src/wf_api/constants.py. - Create
src/wf_api/refs.py. - Re-export the new helpers from
src/wf_api/__init__.py. - Replace
wf_mcp.workflow_surface.constantswith a compatibility shim. - Replace
wf_mcp.workflow_surface.refswith a compatibility shim. - Update
src/wf_mcp/workflow_surface/handlers.pyto import canonical helpers fromwf_api. - Add/adjust tests for canonical imports and shim compatibility.
- Keep
wf_apifree ofwf_mcpimports.
Out Of Scope
- Do not move
models.py. - Do not move
next_actions.py. - Do not move
wrapper_hints.py. - Do not move
run_lifecycle.py. - Do not move
runtime_dependencies.py. - Do not move
saved_subgraphs.py. - Do not rename
WorkflowSurfaceHandlers. - Do not change public payloads, tool names, command names, or parsing behavior.
File Structure
New Canonical Files
| File | Responsibility |
|---|---|
src/wf_api/constants.py |
Canonical workflow API literals used by draft/helper code. |
src/wf_api/refs.py |
Canonical parser for workflow-surface capability IDs. |
Compatibility Shims
| File | Responsibility |
|---|---|
src/wf_mcp/workflow_surface/constants.py |
Re-export constants from wf_api.constants; no local logic. |
src/wf_mcp/workflow_surface/refs.py |
Re-export refs from wf_api.refs; no local logic. |
Modified Consumers
| File | Change |
|---|---|
src/wf_api/__init__.py |
Re-export moved helpers. |
src/wf_mcp/workflow_surface/handlers.py |
Import constants and parser from wf_api. |
tests/wf_mcp/test_workflow_surface_refs.py |
Keep shim compatibility tests and add canonical import tests. |
tests/wf_api/test_import_direction.py |
Existing guard should continue to pass. |
Task 1: Add Canonical wf_api.constants
Files:
-
Create:
src/wf_api/constants.py -
Step 1: Create
src/wf_api/constants.py
Write this exact file:
"""Protocol-neutral workflow API literals used by draft/helper code."""
DEFAULT_CALL_STEP_ID = "call"
DEFAULT_ERROR_STEP_ID = "tool_error"
DEFAULT_OK_OUTCOME = "ok"
DEFAULT_ERROR_OUTCOME = "error"
RUNTIME_ERROR_CAPABILITY = "wf.std.runtime_error"
__all__ = [
"DEFAULT_CALL_STEP_ID",
"DEFAULT_ERROR_OUTCOME",
"DEFAULT_ERROR_STEP_ID",
"DEFAULT_OK_OUTCOME",
"RUNTIME_ERROR_CAPABILITY",
]
- Step 2: Run import smoke check
Run:
uv run python -c "from wf_api.constants import DEFAULT_CALL_STEP_ID, RUNTIME_ERROR_CAPABILITY; print(DEFAULT_CALL_STEP_ID, RUNTIME_ERROR_CAPABILITY)"
Expected output:
call wf.std.runtime_error
Task 2: Add Canonical wf_api.refs
Files:
-
Create:
src/wf_api/refs.py -
Step 1: Create
src/wf_api/refs.py
Write this exact file:
from __future__ import annotations
from typing import Any, TypeAlias
from wf_artifacts import WorkflowCapabilityRef
from wf_platform import CapabilityRef
WorkflowSurfaceCapabilityId: TypeAlias = CapabilityRef | WorkflowCapabilityRef
def parse_workflow_surface_capability_id(
value: str | dict[str, Any],
) -> WorkflowSurfaceCapabilityId:
"""Parse a workflow API capability id into its real domain ref.
API callers still pass strings at protocol boundaries. Internally,
workflow-facing capability ids are either live source capabilities or saved
wrapper artifacts, so this parser avoids inventing a third identifier model.
"""
if isinstance(value, dict):
if "artifact_id" in value and "version" in value:
return WorkflowCapabilityRef._validate(value)
return CapabilityRef._validate(value)
try:
return WorkflowCapabilityRef.parse(value)
except ValueError:
return CapabilityRef.parse(value)
- Step 2: Run import smoke check
Run:
uv run python -c "from wf_api.refs import parse_workflow_surface_capability_id; print(parse_workflow_surface_capability_id('workflow.echo_wrapper.v2'))"
Expected output:
workflow.echo_wrapper.v2
Task 3: Re-export Helpers From wf_api
Files:
-
Modify:
src/wf_api/__init__.py -
Step 1: Update imports and
__all__
Change src/wf_api/__init__.py to include these imports:
from .constants import (
DEFAULT_CALL_STEP_ID,
DEFAULT_ERROR_OUTCOME,
DEFAULT_ERROR_STEP_ID,
DEFAULT_OK_OUTCOME,
RUNTIME_ERROR_CAPABILITY,
)
from .refs import WorkflowSurfaceCapabilityId, parse_workflow_surface_capability_id
Ensure __all__ includes:
__all__ = [
"DEFAULT_CALL_STEP_ID",
"DEFAULT_ERROR_OUTCOME",
"DEFAULT_ERROR_STEP_ID",
"DEFAULT_OK_OUTCOME",
"RUNTIME_ERROR_CAPABILITY",
"TraceRange",
"WorkflowApi",
"WorkflowApiBackend",
"WorkflowSurfaceCapabilityId",
"parse_workflow_surface_capability_id",
]
- Step 2: Run import smoke check
Run:
uv run python -c "from wf_api import DEFAULT_OK_OUTCOME, parse_workflow_surface_capability_id; print(DEFAULT_OK_OUTCOME, parse_workflow_surface_capability_id('demo.personal.echo_tool'))"
Expected output:
ok demo.personal.echo_tool
Task 4: Convert Old Workflow-Surface Modules To Shims
Files:
-
Modify:
src/wf_mcp/workflow_surface/constants.py -
Modify:
src/wf_mcp/workflow_surface/refs.py -
Step 1: Replace
src/wf_mcp/workflow_surface/constants.py
Replace the file with this shim:
"""Compatibility shim for workflow API constants.
New code should import these literals from `wf_api.constants`. This module stays
so older MCP workflow-surface imports keep working during extraction.
"""
from wf_api.constants import (
DEFAULT_CALL_STEP_ID,
DEFAULT_ERROR_OUTCOME,
DEFAULT_ERROR_STEP_ID,
DEFAULT_OK_OUTCOME,
RUNTIME_ERROR_CAPABILITY,
)
__all__ = [
"DEFAULT_CALL_STEP_ID",
"DEFAULT_ERROR_OUTCOME",
"DEFAULT_ERROR_STEP_ID",
"DEFAULT_OK_OUTCOME",
"RUNTIME_ERROR_CAPABILITY",
]
- Step 2: Replace
src/wf_mcp/workflow_surface/refs.py
Replace the file with this shim:
"""Compatibility shim for workflow API capability refs.
New code should import from `wf_api.refs`. This module stays so older MCP
workflow-surface imports keep working during extraction.
"""
from wf_api.refs import (
WorkflowSurfaceCapabilityId,
parse_workflow_surface_capability_id,
)
__all__ = [
"WorkflowSurfaceCapabilityId",
"parse_workflow_surface_capability_id",
]
- Step 3: Run shim import smoke check
Run:
uv run python -c "from wf_mcp.workflow_surface.constants import DEFAULT_CALL_STEP_ID; from wf_mcp.workflow_surface.refs import parse_workflow_surface_capability_id; print(DEFAULT_CALL_STEP_ID, parse_workflow_surface_capability_id('workflow.echo_wrapper.v2'))"
Expected output:
call workflow.echo_wrapper.v2
Task 5: Update Canonical Imports In WorkflowSurfaceHandlers
Files:
-
Modify:
src/wf_mcp/workflow_surface/handlers.py -
Step 1: Change constants import
Replace:
from .constants import (
DEFAULT_CALL_STEP_ID,
DEFAULT_ERROR_OUTCOME,
DEFAULT_ERROR_STEP_ID,
DEFAULT_OK_OUTCOME,
RUNTIME_ERROR_CAPABILITY,
)
with:
from wf_api.constants import (
DEFAULT_CALL_STEP_ID,
DEFAULT_ERROR_OUTCOME,
DEFAULT_ERROR_STEP_ID,
DEFAULT_OK_OUTCOME,
RUNTIME_ERROR_CAPABILITY,
)
- Step 2: Change refs import
Replace:
from .refs import parse_workflow_surface_capability_id
with:
from wf_api.refs import parse_workflow_surface_capability_id
- Step 3: Run import smoke check
Run:
uv run python -c "from wf_mcp.workflow_surface.handlers import WorkflowSurfaceHandlers; print(WorkflowSurfaceHandlers.__name__)"
Expected output:
WorkflowSurfaceHandlers
Task 6: Update Ref Tests For Canonical And Shim Imports
Files:
-
Modify:
tests/wf_mcp/test_workflow_surface_refs.py -
Step 1: Update imports
Change the top imports to:
from wf_api.refs import parse_workflow_surface_capability_id
from wf_artifacts import WorkflowCapabilityRef
from wf_mcp.workflow_surface.refs import (
parse_workflow_surface_capability_id as parse_workflow_surface_capability_id_shim,
)
from wf_platform import CapabilityRef
- Step 2: Add shim compatibility test
Append this test to the file:
def test_workflow_surface_refs_shim_reexports_canonical_parser() -> None:
assert parse_workflow_surface_capability_id_shim is parse_workflow_surface_capability_id
- Step 3: Add constants shim compatibility test
Append this test to the file:
def test_workflow_surface_constants_shim_reexports_canonical_literals() -> None:
from wf_api.constants import DEFAULT_CALL_STEP_ID
from wf_mcp.workflow_surface.constants import (
DEFAULT_CALL_STEP_ID as DEFAULT_CALL_STEP_ID_SHIM,
)
assert DEFAULT_CALL_STEP_ID_SHIM == DEFAULT_CALL_STEP_ID
- Step 4: Run focused tests
Run:
uv run pytest tests/wf_mcp/test_workflow_surface_refs.py tests/wf_api/test_import_direction.py -q
Expected: all tests pass.
Task 7: Search For Remaining Canonical Import Opportunities
Files:
-
Inspect only unless the search finds new low-risk direct consumers.
-
Step 1: Search old imports
Run:
rg -n "from \\.constants|from \\.refs|from wf_mcp\\.workflow_surface\\.(constants|refs)" src tests
Expected remaining matches:
src/wf_mcp/workflow_surface/constants.py
src/wf_mcp/workflow_surface/refs.py
tests/wf_mcp/test_workflow_surface_refs.py
If any other production module imports the old paths, update it to import from
wf_api.constants or wf_api.refs.
- Step 2: Search for accidental
wf_api -> wf_mcpimports
Run:
rg -n "wf_mcp" src/wf_api tests/wf_api
Expected matches only in test text/docstrings for the import-direction guard,
not in src/wf_api/*.py.
Task 8: Verification
- Step 1: Run focused tests
uv run pytest tests/wf_api tests/wf_mcp/test_workflow_surface_refs.py tests/wf_mcp/workflow_surface -q
Expected: all pass.
- Step 2: Run CLI context smoke tests
uv run pytest tests/wf_cli/test_context.py -q
Expected: pass.
- Step 3: Run ruff on touched files
uv run ruff check src/wf_api src/wf_mcp/workflow_surface/constants.py src/wf_mcp/workflow_surface/refs.py src/wf_mcp/workflow_surface/handlers.py tests/wf_mcp/test_workflow_surface_refs.py tests/wf_api
Expected: all checks pass.
- Step 4: Run basedpyright on touched files
uv run basedpyright --level error src/wf_api src/wf_mcp/workflow_surface/constants.py src/wf_mcp/workflow_surface/refs.py src/wf_mcp/workflow_surface/handlers.py tests/wf_mcp/test_workflow_surface_refs.py tests/wf_api
Expected: 0 errors.
- Step 5: Optional full suite
Run this if time allows:
uv run pytest -q
Expected: full suite passes with the project’s existing skipped/xfailed counts.
Self-Review Checklist
wf_api.constantsimports nowf_mcp.wf_api.refsimports nowf_mcp.- Old
wf_mcp.workflow_surface.constantsimport path still works. - Old
wf_mcp.workflow_surface.refsimport path still works. WorkflowSurfaceHandlersimports the canonicalwf_apihelpers.- No public payload shape changed.
- No behavior changed.
- No other workflow-surface helper moved in this slice.