13 KiB
wf Status And Product Smoke 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: Add a read-only wf status command that tells users what target they are connected to and summarizes server/source/admin state, then add a small product smoke test path for the remote server workflow.
Architecture: Do not add a new backend status endpoint in this slice. The CLI should compose status from existing surfaces already available on CliContext: workflow capability list, source inventory, admin connection/status/events/auth summaries, and source registry summaries when available. Local/static servers and remote RPC servers should both work; unavailable optional admin surfaces should report available: false instead of failing the whole command.
Tech Stack: Python 3.14, Typer CLI, existing WorkflowApiSurface / admin surface protocols, JSON output via wf_cli.io.emit_json, pytest, basedpyright, ruff.
File Structure
- Create:
src/wf_cli/commands/status.py- Owns
wf status. - Builds one compact JSON payload from existing CLI context surfaces.
- Contains small private helpers for safe optional calls.
- Owns
- Modify:
src/wf_cli/app.py- Register
statusas a top-level command.
- Register
- Modify:
tests/wf_cli/test_remote_target.py- Add remote status test using the existing ASGI-backed RPC client patch seam.
- Create:
tests/wf_cli/test_status.py- Add local/static and partial-unavailable behavior tests.
- Modify:
docs/wf_cli.md- Document
wf status.
- Document
- Modify:
docs/current_roadmap.md- Mark this slice complete after implementation.
Do not modify wf_server, wf_api, or wf_transport_rpc_http unless tests prove an existing surface is missing.
Payload Contract
wf status must emit JSON:
{
"target": {
"mode": "local|remote",
"config_path": "wf.config.json",
"url": "http://127.0.0.1:8765/rpc|null"
},
"workflow": {
"capability_count": 88,
"sample_capabilities": ["wf.std.constant"]
},
"sources": {
"available": true,
"source_count": 7,
"sample_sources": ["wf.std"]
},
"admin": {
"available": true,
"connection_count": 4,
"status_count": 4,
"event_count": 12,
"auth_count": 1
},
"registry": {
"available": true,
"entry_count": 0
}
}
Rules:
- Counts may be
0. - Optional sections must keep
available: falsewhen unavailable. - Do not include auth payload values.
- Do not include full capability/source/connection lists; this command is a quick orientation summary.
- Do not mutate config, stores, registry, auth, or catalog.
Task 1: Add Local Status Command Tests
Files:
-
Create:
tests/wf_cli/test_status.py -
Create later:
src/wf_cli/commands/status.py -
Modify later:
src/wf_cli/app.py -
Step 1: Write failing local status test
Create tests/wf_cli/test_status.py:
from __future__ import annotations
import json
from typer.testing import CliRunner
from wf_cli.app import app
def test_wf_status_local_static_target(tmp_path) -> None:
config_path = tmp_path / "wf.json"
config_path.write_text(
json.dumps(
{
"version": 1,
"client": {"target": {"kind": "local"}},
"server": {
"store": {
"kind": "filesystem",
"root": str(tmp_path / "store"),
}
},
}
),
encoding="utf-8",
)
result = CliRunner().invoke(
app,
[
"--config",
str(config_path),
"--local",
"status",
],
)
assert result.exit_code == 0, result.output
payload = json.loads(result.output)
assert payload["target"]["mode"] == "local"
assert payload["target"]["config_path"] == str(config_path)
assert payload["target"]["url"] is None
assert payload["workflow"]["capability_count"] >= 1
assert "wf.std.constant" in payload["workflow"]["sample_capabilities"]
assert payload["sources"]["available"] is True
assert payload["sources"]["source_count"] >= 1
assert payload["admin"]["available"] is True
assert payload["registry"]["available"] is False
- Step 2: Run the failing test
Run:
uv run pytest tests/wf_cli/test_status.py::test_wf_status_local_static_target -q
Expected: FAIL because wf status is not registered.
Task 2: Implement wf status
Files:
-
Create:
src/wf_cli/commands/status.py -
Modify:
src/wf_cli/app.py -
Step 1: Create status command module
Create src/wf_cli/commands/status.py:
from __future__ import annotations
from typing import Any
import typer
from wf_cli.context import CliTyperState, load_cli_context_from_typer
from wf_cli.io import emit_json
from wf_cli.remote_errors import run_cli_operation
def status_command(ctx: typer.Context) -> None:
"""Print a compact read-only summary of the selected workflow target."""
state = CliTyperState.from_context(ctx)
context = load_cli_context_from_typer(ctx)
payload: dict[str, Any] = {
"target": {
"mode": "remote" if state.rpc_url is not None else "local",
"config_path": str(context.config_path),
"url": state.rpc_url,
},
"workflow": _workflow_status(context),
"sources": _sources_status(context),
"admin": _admin_status(context),
"registry": _registry_status(context),
}
emit_json(payload)
def _workflow_status(context) -> dict[str, Any]:
capabilities = run_cli_operation(
context,
context.handlers.list_capabilities(limit=20),
)
items = capabilities.get("capabilities", [])
names = [
item.get("name")
for item in items
if isinstance(item, dict) and isinstance(item.get("name"), str)
]
return {
"capability_count": len(items),
"sample_capabilities": names[:5],
}
def _sources_status(context) -> dict[str, Any]:
try:
payload = run_cli_operation(context, context.source_admin.list_sources(limit=20))
except Exception as exc:
return _unavailable(exc)
sources = payload.get("sources", [])
source_ids = [
item.get("id")
for item in sources
if isinstance(item, dict) and isinstance(item.get("id"), str)
]
return {
"available": True,
"source_count": len(sources),
"sample_sources": source_ids[:5],
}
def _admin_status(context) -> dict[str, Any]:
try:
connections = run_cli_operation(context, context.admin.list_connections())
statuses = run_cli_operation(context, context.admin.get_connection_statuses())
events = run_cli_operation(context, context.admin.list_events())
auth = run_cli_operation(context, context.admin.list_auth_records())
except Exception as exc:
return _unavailable(exc)
return {
"available": True,
"connection_count": len(connections.get("connections", [])),
"status_count": len(statuses.get("statuses", [])),
"event_count": len(events.get("events", [])),
"auth_count": len(auth.get("auth_records", [])),
}
def _registry_status(context) -> dict[str, Any]:
admin = context.source_registry_admin
if admin is None:
return {"available": False, "reason": "source registry admin is not configured"}
try:
payload = run_cli_operation(context, admin.list_registry_entries(limit=20))
except Exception as exc:
return _unavailable(exc)
return {
"available": True,
"entry_count": len(payload.get("entries", [])),
}
def _unavailable(exc: Exception) -> dict[str, Any]:
return {
"available": False,
"reason": str(exc),
}
- Step 2: Register top-level command
Modify src/wf_cli/app.py:
from .commands import (
admin,
artifacts,
caps,
deployments,
docs,
drafts,
explain,
runs,
schema,
sources,
status,
)
Add registration near the other top-level commands:
app.command("status")(status.status_command)
- Step 3: Run local status test
Run:
uv run pytest tests/wf_cli/test_status.py::test_wf_status_local_static_target -q
Expected: PASS.
- Step 4: Typecheck the new command
If basedpyright reports unknown types in helper functions, add local annotations by importing CliContext:
from wf_cli.context import CliContext, CliTyperState, load_cli_context_from_typer
Then annotate helpers:
def _workflow_status(context: CliContext) -> dict[str, Any]:
Run:
uv run basedpyright --level error src\wf_cli\commands\status.py tests\wf_cli\test_status.py
Expected: 0 errors.
Task 3: Add Remote Status Test
Files:
-
Modify:
tests/wf_cli/test_remote_target.py -
Step 1: Add remote test using existing RPC patch helper
Append this test near the existing remote target CLI tests:
def test_wf_status_uses_rpc_url_override(monkeypatch, tmp_path) -> None:
server = build_local_static_workflow_server(tmp_path / "store")
_patch_rpc_client_to_server(monkeypatch, server)
config_path = tmp_path / "wf.json"
config_path.write_text('{"version": 1}', encoding="utf-8")
result = CliRunner().invoke(
app,
[
"--config",
str(config_path),
"--url",
"http://test/rpc",
"status",
],
)
assert result.exit_code == 0, result.output
payload = json.loads(result.output)
assert payload["target"]["mode"] == "remote"
assert payload["target"]["url"] == "http://test/rpc"
assert payload["workflow"]["capability_count"] >= 1
assert payload["sources"]["available"] is True
assert payload["admin"]["available"] is True
assert payload["registry"]["available"] is False
- Step 2: Run remote test
Run:
uv run pytest tests/wf_cli/test_remote_target.py::test_wf_status_uses_rpc_url_override -q
Expected: PASS.
Task 4: Add Product Smoke Script Documentation
Files:
-
Modify:
docs/wf_cli.md -
Modify:
docs/current_roadmap.md -
Step 1: Document
wf status
In docs/wf_cli.md, under the remote server section or before capability
discovery, add:
Check the selected target:
```bash
wf status
wf --url http://127.0.0.1:8765/rpc status
```
`status` is read-only. It reports the selected target, capability/source
availability, admin counts, auth record count, and desired registry count when
the target exposes those admin surfaces. It does not return auth payload values.
```
- Step 2: Mark roadmap item complete
In docs/current_roadmap.md, under Priority 1: Product Smoke And Status UX,
change:
- Add `wf status` as a compact target/server status command.
to:
- Completed: `wf status` is a compact read-only target/server status command.
Leave the manual product smoke item open.
- Step 3: Run docs lint
Run:
uv run ruff check docs\wf_cli.md docs\current_roadmap.md
Expected: no lint errors. Ruff may report "No Python files found"; that is acceptable for markdown-only paths.
Task 5: Final Verification
Files: all touched files.
- Step 1: Run focused tests
Run:
uv run pytest tests/wf_cli/test_status.py tests/wf_cli/test_remote_target.py -q
Expected: all tests pass.
- Step 2: Run broader CLI/RPC smoke tests
Run:
uv run pytest tests/wf_transport_rpc_http tests/wf_cli/test_remote_target.py tests/wf_cli/test_status.py -q
Expected: all tests pass.
- Step 3: Run lint
Run:
uv run ruff check src\wf_cli tests\wf_cli tests\wf_transport_rpc_http
Expected: All checks passed!
- Step 4: Run typecheck
Run:
uv run basedpyright --level error src\wf_cli tests\wf_cli\test_status.py tests\wf_cli\test_remote_target.py
Expected: 0 errors, 0 warnings, 0 notes.
- Step 5: Manual product smoke
If a server is running:
uv run wf --url http://127.0.0.1:8765/rpc status
uv run wf --url http://127.0.0.1:8765/rpc cap call wf.std.constant --input '{"value":"status smoke"}'
Expected:
-
statusreturns JSON withtarget.mode == "remote". -
cap callreturnsoutcome == "ok". -
Step 6: Commit
git add src\wf_cli\commands\status.py src\wf_cli\app.py tests\wf_cli\test_status.py tests\wf_cli\test_remote_target.py docs\wf_cli.md docs\current_roadmap.md
git commit -m "feat: add workflow status command"
Self-Review Checklist
- Spec coverage: this plan implements the roadmap's first Priority 1 item (
wf status) and leaves manual product smoke as a visible follow-up. - Placeholder scan: no TODO/TBD placeholders remain.
- Scope check: no new backend endpoint, no store mutation, no new server state.
- Type consistency:
CliContext,CliTyperState, and existing admin/source methods match current code. - Security: auth status returns counts only; no payload values.