feat: simplify draft cli vocabulary
This commit is contained in:
@@ -67,7 +67,10 @@ clear operator feedback before adding more architecture.
|
||||
schema projection with step binding merge, replacing the narrower
|
||||
`bind-output-to-state` helper and reducing manual draft patch repairs in
|
||||
agent challenge runs.
|
||||
- Completed: `wf draft add-step-from-capability` inserts one explicit
|
||||
- Completed: draft CLI vocabulary now uses `wf draft create --capability` and
|
||||
`wf draft add-step --capability`, replacing the longer
|
||||
`*-from-capability` commands that agents repeatedly guessed around.
|
||||
- Completed: `wf draft add-step` inserts one explicit
|
||||
capability-backed step with route, input, and output-to-state schema/binding
|
||||
wiring in a single revision, reducing brittle JSON Patch authoring for
|
||||
multi-step workflows. Accepts `--route OUTCOME=TARGET` for multi-outcome steps.
|
||||
|
||||
@@ -0,0 +1,496 @@
|
||||
# Draft CLI Vocabulary 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:** Replace long draft CLI command names with `wf draft create --capability` and `wf draft add-step --capability`.
|
||||
|
||||
**Architecture:** This is a CLI vocabulary cleanup, not a programmatic API rename. Keep the existing Python/RPC/MCP methods and route the new Typer commands to those handlers. Remove the old long CLI commands and update live docs/skills so agents learn one command shape.
|
||||
|
||||
**Tech Stack:** Python 3.14, Typer CLI, pytest, ruff, basedpyright.
|
||||
|
||||
---
|
||||
|
||||
## File Map
|
||||
|
||||
- Modify `src/wf_cli/commands/drafts.py`: replace `create-from-capability` with `create`, replace `add-step-from-capability` with `add-step`.
|
||||
- Modify `tests/wf_cli/test_app.py`: update help tests and assert old long commands are absent.
|
||||
- Modify `tests/wf_cli/test_remote_target.py` and `tests/wf_cli/test_discovery_lifecycle.py`: update CLI invocations.
|
||||
- Modify live docs/skills that mention the old CLI commands:
|
||||
- `docs/wf_cli.md`
|
||||
- `docs/current_roadmap.md`
|
||||
- `docs/runbooks/rpc-cli-smoke.md`
|
||||
- `docs/runbooks/python-source.md`
|
||||
- `skills/wf-cli/SKILL.md`
|
||||
- `skills/wf-workflow/SKILL.md`
|
||||
- `skills/wf-workflow/references/workflow-lifecycle.md`
|
||||
- `skills/wf-workflow/references/draft-workspaces.md`
|
||||
- `skills/wf-workflow/references/direct-plan-import.md`
|
||||
- `skills/wf-workflow/references/system-model.md`
|
||||
- `docs/superpowers/specs/2026-06-27-draft-semantic-authoring-boundary.md`
|
||||
- Do not edit historical docs except by moving this plan after implementation.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Replace Create Command Shape
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/wf_cli/commands/drafts.py`
|
||||
- Test: `tests/wf_cli/test_app.py`, `tests/wf_cli/test_remote_target.py`, `tests/wf_cli/test_discovery_lifecycle.py`
|
||||
|
||||
- [ ] **Step 1: Update failing CLI help tests**
|
||||
|
||||
In `tests/wf_cli/test_app.py`, replace:
|
||||
|
||||
```python
|
||||
def test_wf_draft_create_from_capability_help_exists() -> None:
|
||||
result = runner.invoke(app, ["draft", "create-from-capability", "--help"])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "--title" in result.output
|
||||
```
|
||||
|
||||
with:
|
||||
|
||||
```python
|
||||
def test_wf_draft_create_help_accepts_capability_option() -> None:
|
||||
result = runner.invoke(app, ["draft", "create", "--help"])
|
||||
|
||||
assert result.exit_code == 0
|
||||
output = " ".join(result.output.split())
|
||||
assert "--capability" in output
|
||||
assert "--title" in output
|
||||
|
||||
|
||||
def test_wf_draft_help_does_not_list_old_create_from_capability() -> None:
|
||||
result = runner.invoke(app, ["draft", "--help"])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "create-from-capability" not in result.output
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Update CLI invocations in tests**
|
||||
|
||||
Replace command arrays like:
|
||||
|
||||
```python
|
||||
[
|
||||
"draft",
|
||||
"create-from-capability",
|
||||
"workspace_id",
|
||||
"wf.std.constant",
|
||||
]
|
||||
```
|
||||
|
||||
with:
|
||||
|
||||
```python
|
||||
[
|
||||
"draft",
|
||||
"create",
|
||||
"workspace_id",
|
||||
"--capability",
|
||||
"wf.std.constant",
|
||||
]
|
||||
```
|
||||
|
||||
Files to update:
|
||||
|
||||
- `tests/wf_cli/test_remote_target.py`
|
||||
- `tests/wf_cli/test_discovery_lifecycle.py`
|
||||
|
||||
Use `rg -n 'create-from-capability' tests/wf_cli` to find every live test hit.
|
||||
|
||||
- [ ] **Step 3: Run tests and confirm failure**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
uv run pytest tests/wf_cli/test_app.py tests/wf_cli/test_remote_target.py tests/wf_cli/test_discovery_lifecycle.py -q -k "draft or create"
|
||||
```
|
||||
|
||||
Expected: failures because `wf draft create` does not exist yet.
|
||||
|
||||
- [ ] **Step 4: Implement `wf draft create --capability`**
|
||||
|
||||
In `src/wf_cli/commands/drafts.py`, replace:
|
||||
|
||||
```python
|
||||
@app.command("create-from-capability")
|
||||
def create_from_capability(
|
||||
ctx: typer.Context,
|
||||
workspace_id: Annotated[str, typer.Argument(help="Draft workspace id.")],
|
||||
capability_name: Annotated[str, typer.Argument(help="Workflow capability name.")],
|
||||
name: Annotated[
|
||||
str | None, typer.Option("--name", help="Draft workflow name.")
|
||||
] = None,
|
||||
title: Annotated[
|
||||
str | None, typer.Option("--title", help="Workspace title.")
|
||||
] = None,
|
||||
) -> None:
|
||||
"""Bootstrap a draft workspace from inspect_capability wrapper hints."""
|
||||
```
|
||||
|
||||
with:
|
||||
|
||||
```python
|
||||
@app.command("create")
|
||||
def create_from_capability(
|
||||
ctx: typer.Context,
|
||||
workspace_id: Annotated[str, typer.Argument(help="Draft workspace id.")],
|
||||
capability_name: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
"--capability",
|
||||
help="Qualified capability name used to bootstrap the draft.",
|
||||
),
|
||||
],
|
||||
name: Annotated[
|
||||
str | None, typer.Option("--name", help="Draft workflow name.")
|
||||
] = None,
|
||||
title: Annotated[
|
||||
str | None, typer.Option("--title", help="Workspace title.")
|
||||
] = None,
|
||||
) -> None:
|
||||
"""Create a patchable draft workspace from one capability."""
|
||||
```
|
||||
|
||||
Keep the handler call unchanged:
|
||||
|
||||
```python
|
||||
context.handlers.create_draft_workspace_from_capability(...)
|
||||
```
|
||||
|
||||
Do not keep `@app.command("create-from-capability")`.
|
||||
|
||||
- [ ] **Step 5: Run create-focused tests**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
uv run pytest tests/wf_cli/test_app.py tests/wf_cli/test_remote_target.py tests/wf_cli/test_discovery_lifecycle.py -q -k "create"
|
||||
```
|
||||
|
||||
Expected: selected tests pass.
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```powershell
|
||||
git add src/wf_cli/commands/drafts.py tests/wf_cli/test_app.py tests/wf_cli/test_remote_target.py tests/wf_cli/test_discovery_lifecycle.py
|
||||
git commit -m "feat: simplify draft create cli"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Replace Add-Step Command Shape
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/wf_cli/commands/drafts.py`
|
||||
- Test: `tests/wf_cli/test_app.py`, `tests/wf_cli/test_remote_target.py`
|
||||
|
||||
- [ ] **Step 1: Update failing CLI help tests**
|
||||
|
||||
In `tests/wf_cli/test_app.py`, replace:
|
||||
|
||||
```python
|
||||
def test_wf_draft_add_step_from_capability_help_explains_explicit_wiring() -> None:
|
||||
result = runner.invoke(app, ["draft", "add-step-from-capability", "--help"])
|
||||
```
|
||||
|
||||
with:
|
||||
|
||||
```python
|
||||
def test_wf_draft_add_step_help_explains_explicit_wiring() -> None:
|
||||
result = runner.invoke(app, ["draft", "add-step", "--help"])
|
||||
|
||||
assert result.exit_code == 0
|
||||
output = " ".join(result.output.split())
|
||||
assert "--capability" in output
|
||||
assert "--from-step" in output
|
||||
assert "--bind-output" in output
|
||||
assert "does not guess" in output
|
||||
|
||||
|
||||
def test_wf_draft_help_does_not_list_old_add_step_from_capability() -> None:
|
||||
result = runner.invoke(app, ["draft", "--help"])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "add-step-from-capability" not in result.output
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Update CLI invocations in tests**
|
||||
|
||||
Replace:
|
||||
|
||||
```python
|
||||
[
|
||||
"draft",
|
||||
"add-step-from-capability",
|
||||
"workspace_id",
|
||||
"--revision",
|
||||
"1",
|
||||
"--step",
|
||||
"render",
|
||||
"--capability",
|
||||
"local.report.render_markdown_report",
|
||||
]
|
||||
```
|
||||
|
||||
with:
|
||||
|
||||
```python
|
||||
[
|
||||
"draft",
|
||||
"add-step",
|
||||
"workspace_id",
|
||||
"--revision",
|
||||
"1",
|
||||
"--step",
|
||||
"render",
|
||||
"--capability",
|
||||
"local.report.render_markdown_report",
|
||||
]
|
||||
```
|
||||
|
||||
Files to update:
|
||||
|
||||
- `tests/wf_cli/test_app.py`
|
||||
- `tests/wf_cli/test_remote_target.py`
|
||||
|
||||
Use `rg -n 'add-step-from-capability' tests/wf_cli` to find every live test hit.
|
||||
|
||||
- [ ] **Step 3: Run tests and confirm failure**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
uv run pytest tests/wf_cli/test_app.py tests/wf_cli/test_remote_target.py -q -k "add_step or add-step"
|
||||
```
|
||||
|
||||
Expected: failures because `wf draft add-step` does not exist yet.
|
||||
|
||||
- [ ] **Step 4: Implement `wf draft add-step --capability`**
|
||||
|
||||
In `src/wf_cli/commands/drafts.py`, replace:
|
||||
|
||||
```python
|
||||
@app.command("add-step-from-capability")
|
||||
def add_step_from_capability(
|
||||
```
|
||||
|
||||
with:
|
||||
|
||||
```python
|
||||
@app.command("add-step")
|
||||
def add_step_from_capability(
|
||||
```
|
||||
|
||||
Update the docstring first line to:
|
||||
|
||||
```python
|
||||
"""Add one capability-backed step with explicit route, input, and output wiring.
|
||||
```
|
||||
|
||||
Keep the handler call unchanged:
|
||||
|
||||
```python
|
||||
context.handlers.add_step_from_capability(...)
|
||||
```
|
||||
|
||||
Do not keep `@app.command("add-step-from-capability")`.
|
||||
|
||||
- [ ] **Step 5: Run add-step tests**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
uv run pytest tests/wf_cli/test_app.py tests/wf_cli/test_remote_target.py -q -k "add_step or add-step"
|
||||
```
|
||||
|
||||
Expected: selected tests pass.
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```powershell
|
||||
git add src/wf_cli/commands/drafts.py tests/wf_cli/test_app.py tests/wf_cli/test_remote_target.py
|
||||
git commit -m "feat: simplify draft add-step cli"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Update Live Docs And Skills
|
||||
|
||||
**Files:**
|
||||
- Modify: `docs/wf_cli.md`
|
||||
- Modify: `docs/current_roadmap.md`
|
||||
- Modify: `docs/runbooks/rpc-cli-smoke.md`
|
||||
- Modify: `docs/runbooks/python-source.md`
|
||||
- Modify: `docs/superpowers/specs/2026-06-27-draft-semantic-authoring-boundary.md`
|
||||
- Modify: `skills/wf-cli/SKILL.md`
|
||||
- Modify: `skills/wf-workflow/SKILL.md`
|
||||
- Modify: `skills/wf-workflow/references/workflow-lifecycle.md`
|
||||
- Modify: `skills/wf-workflow/references/draft-workspaces.md`
|
||||
- Modify: `skills/wf-workflow/references/direct-plan-import.md`
|
||||
- Modify: `skills/wf-workflow/references/system-model.md`
|
||||
- Move: `docs/superpowers/plans/2026-06-28-draft-cli-vocabulary.md` to `docs/historical/superpowers/plans/2026-06-28-draft-cli-vocabulary.md`
|
||||
|
||||
- [ ] **Step 1: Replace old command names in live docs/skills**
|
||||
|
||||
Use:
|
||||
|
||||
```powershell
|
||||
rg -n 'create-from-capability|add-step-from-capability|draft create --capability' docs skills -S -g '!docs/historical/**'
|
||||
```
|
||||
|
||||
Update live CLI examples:
|
||||
|
||||
```powershell
|
||||
wf draft create report_ws --capability local.report.extract_report --name report
|
||||
```
|
||||
|
||||
```powershell
|
||||
wf draft add-step report_ws --revision 3 --step render --capability local.report.render_markdown_report --route ok=__end__
|
||||
```
|
||||
|
||||
Remove text that says:
|
||||
|
||||
```text
|
||||
There is currently no `wf draft create --capability` alias.
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Update semantic authoring spec**
|
||||
|
||||
In `docs/superpowers/specs/2026-06-27-draft-semantic-authoring-boundary.md`,
|
||||
replace public CLI operation names:
|
||||
|
||||
```markdown
|
||||
- `create`
|
||||
- `add-step`
|
||||
- `bind`
|
||||
- `branch`
|
||||
- `handle`
|
||||
```
|
||||
|
||||
Keep Python method names when the document explicitly discusses internal API
|
||||
implementation details.
|
||||
|
||||
- [ ] **Step 3: Update roadmap**
|
||||
|
||||
Add a completed bullet under Priority 1:
|
||||
|
||||
```markdown
|
||||
- Completed: draft CLI vocabulary now uses `wf draft create --capability` and
|
||||
`wf draft add-step --capability`, replacing the longer
|
||||
`*-from-capability` commands that agents repeatedly guessed around.
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Move plan to historical**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
New-Item -ItemType Directory -Force -Path docs/historical/superpowers/plans | Out-Null
|
||||
Move-Item docs/superpowers/plans/2026-06-28-draft-cli-vocabulary.md docs/historical/superpowers/plans/2026-06-28-draft-cli-vocabulary.md
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Verify no stale live CLI names remain**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
rg -n 'create-from-capability|add-step-from-capability' docs skills tests src -S -g '!docs/historical/**'
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- No CLI command docs or tests use the old names.
|
||||
- Programmatic API/RPC/MCP names may still appear, for example
|
||||
`create_draft_workspace_from_capability`, `add_step_from_capability`, and
|
||||
`workflow.draft_workspaces.add_step_from_capability`.
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```powershell
|
||||
git add docs skills tests src docs/historical/superpowers/plans/2026-06-28-draft-cli-vocabulary.md
|
||||
git commit -m "docs: update draft cli vocabulary"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Final Verification
|
||||
|
||||
**Files:**
|
||||
- No planned source edits.
|
||||
|
||||
- [ ] **Step 1: Run focused CLI tests**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
uv run pytest tests/wf_cli/test_app.py tests/wf_cli/test_remote_target.py tests/wf_cli/test_discovery_lifecycle.py -q -k "draft or create or add_step or add-step"
|
||||
```
|
||||
|
||||
Expected: all selected tests pass.
|
||||
|
||||
- [ ] **Step 2: Run broader affected suites**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
uv run pytest tests/wf_cli tests/docs -q
|
||||
```
|
||||
|
||||
Expected: all tests pass. If docs tests are not present in the current checkout,
|
||||
record that and continue with the CLI tests.
|
||||
|
||||
- [ ] **Step 3: Run lint, format, and type checks**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
uv run ruff check
|
||||
uv run ruff format --check
|
||||
uv run basedpyright --level error
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- Ruff clean.
|
||||
- Format clean.
|
||||
- Basedpyright reports `0 errors`.
|
||||
- `git diff --check` has no whitespace errors. CRLF warnings are acceptable on
|
||||
Windows.
|
||||
|
||||
- [ ] **Step 4: Optional smoke command**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
uv run wf --config wf.config.json draft create --help
|
||||
uv run wf --config wf.config.json draft add-step --help
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `create` help shows `--capability`.
|
||||
- `add-step` help shows `--capability`, `--route`, `--input`, and
|
||||
`--bind-output`.
|
||||
|
||||
- [ ] **Step 5: Commit final cleanup if needed**
|
||||
|
||||
```powershell
|
||||
git status --short
|
||||
git add <only files changed by cleanup>
|
||||
git commit -m "fix: polish draft cli vocabulary"
|
||||
```
|
||||
|
||||
Skip this commit if the tree is already clean after Task 3.
|
||||
|
||||
---
|
||||
|
||||
## Self-Review Notes
|
||||
|
||||
- This plan intentionally changes only CLI command names and live docs/skills.
|
||||
- It does not rename Python/RPC/MCP programmatic method names.
|
||||
- It removes the old long CLI names rather than keeping aliases.
|
||||
- Future work can rename RPC/MCP tools if evidence shows model confusion there too.
|
||||
@@ -137,8 +137,8 @@ Expected output includes:
|
||||
Create a draft from the Python capability:
|
||||
|
||||
```powershell
|
||||
uv run wf --url http://127.0.0.1:8766/rpc draft create-from-capability `
|
||||
python_echo_ws local.ops.echo --name python_echo
|
||||
uv run wf --url http://127.0.0.1:8766/rpc draft create `
|
||||
python_echo_ws --capability local.ops.echo --name python_echo
|
||||
```
|
||||
|
||||
Save it as an artifact. Bind the configured Python source. Built-in platform
|
||||
|
||||
@@ -109,7 +109,7 @@ workflow output.
|
||||
Use unique ids so repeated runs do not collide:
|
||||
|
||||
```bash
|
||||
uv run wf --config wf.config.json draft create-from-capability smoke_ws wf.std.constant --name smoke_constant --title "Smoke Constant"
|
||||
uv run wf --config wf.config.json draft create smoke_ws --capability wf.std.constant --name smoke_constant --title "Smoke Constant"
|
||||
uv run wf --config wf.config.json draft validate smoke_ws
|
||||
uv run wf --config wf.config.json draft save smoke_ws --artifact smoke_artifact --version 1 --title "Smoke Artifact" --outcome ok
|
||||
uv run wf --config wf.config.json deploy save smoke_deploy --artifact smoke_artifact --version 1
|
||||
|
||||
@@ -107,8 +107,8 @@ The public draft surface is documented in descending order of preference.
|
||||
|
||||
### Semantic Authoring Operations
|
||||
|
||||
- `create-from-capability`
|
||||
- `add-step-from-capability`
|
||||
- `create`
|
||||
- `add-step`
|
||||
- `bind`
|
||||
- `branch`
|
||||
- `handle`
|
||||
@@ -149,7 +149,7 @@ authoring intent.
|
||||
|
||||
### Add Step From Capability
|
||||
|
||||
`add-step-from-capability` atomically adds:
|
||||
`add-step` atomically adds:
|
||||
|
||||
- one capability-backed `use` step;
|
||||
- explicit input bindings;
|
||||
@@ -160,7 +160,7 @@ authoring intent.
|
||||
The outgoing CLI option is repeatable:
|
||||
|
||||
```powershell
|
||||
wf draft add-step-from-capability WORKSPACE `
|
||||
wf draft add-step WORKSPACE `
|
||||
--revision 4 `
|
||||
--step second_echo `
|
||||
--capability everything.default.echo `
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
# Draft CLI Vocabulary Design
|
||||
|
||||
## Status
|
||||
|
||||
Planned. This design generalizes the two remaining capability-specific draft
|
||||
CLI verbs:
|
||||
|
||||
- `wf draft create-from-capability`
|
||||
- `wf draft add-step-from-capability`
|
||||
|
||||
They are replaced at the CLI layer by:
|
||||
|
||||
- `wf draft create --capability <qualified_name>`
|
||||
- `wf draft add-step --capability <qualified_name>`
|
||||
|
||||
The long commands should be removed from the CLI, docs, and skills rather than
|
||||
kept as aliases. The programmatic API/RPC/MCP method names are not renamed in
|
||||
this slice because they are older, tested surfaces with broader callers than
|
||||
the CLI benchmark loop.
|
||||
|
||||
## Problem
|
||||
|
||||
Agents keep trying CLI shapes that match common command vocabulary:
|
||||
|
||||
```powershell
|
||||
wf draft create --capability local.report.extract_report ...
|
||||
wf draft add-step --capability local.report.render_markdown_report ...
|
||||
```
|
||||
|
||||
The product currently exposes:
|
||||
|
||||
```powershell
|
||||
wf draft create-from-capability ...
|
||||
wf draft add-step-from-capability ...
|
||||
```
|
||||
|
||||
The long names are precise but hostile to discovery. Skills currently have to
|
||||
warn agents that `wf draft create --capability` does not exist, which is a sign
|
||||
that the CLI shape is wrong.
|
||||
|
||||
## New CLI Shape
|
||||
|
||||
Create a workspace:
|
||||
|
||||
```powershell
|
||||
wf draft create <workspace_id> `
|
||||
--capability <qualified_name> `
|
||||
--name <draft_name> `
|
||||
--title <workspace_title>
|
||||
```
|
||||
|
||||
Add a capability step:
|
||||
|
||||
```powershell
|
||||
wf draft add-step <workspace_id> `
|
||||
--revision <n> `
|
||||
--step <step_id> `
|
||||
--capability <qualified_name> `
|
||||
--from-step <prev_step> `
|
||||
--from-outcome ok `
|
||||
--route ok=__end__ `
|
||||
--input input.text=local.text `
|
||||
--bind-output result=state.result
|
||||
```
|
||||
|
||||
`--capability` is required for both commands in this slice. Future core step
|
||||
types can extend `add-step` with `--type condition`, `--type foreach`, or
|
||||
similar flags, but this slice only renames the current capability-backed
|
||||
operations.
|
||||
|
||||
## Removal Policy
|
||||
|
||||
Remove these CLI commands:
|
||||
|
||||
- `wf draft create-from-capability`
|
||||
- `wf draft add-step-from-capability`
|
||||
|
||||
Do not keep aliases. These names made sense as implementation descriptions, but
|
||||
they now actively fight agent behavior. Removing them keeps `wf draft --help`
|
||||
smaller and prevents skills from teaching two ways to do the same operation.
|
||||
|
||||
Keep these programmatic method names for now:
|
||||
|
||||
- `create_draft_workspace_from_capability`
|
||||
- `add_step_from_capability`
|
||||
- `workflow.draft_workspaces.create_from_capability`
|
||||
- `workflow.draft_workspaces.add_step_from_capability`
|
||||
- `wf.workflow.create_draft_workspace_from_capability`
|
||||
- `wf.workflow.add_step_from_capability`
|
||||
|
||||
Those surfaces are outside the immediate CLI vocabulary problem and have older
|
||||
test/docs coverage. A future transport vocabulary cleanup can rename them if
|
||||
there is evidence that MCP/RPC callers struggle with the same names.
|
||||
|
||||
## Documentation Policy
|
||||
|
||||
Live user-facing docs and skills should teach only:
|
||||
|
||||
```powershell
|
||||
wf draft create ... --capability ...
|
||||
wf draft add-step ... --capability ...
|
||||
```
|
||||
|
||||
Historical docs may keep old command names. Live docs that mention the old CLI
|
||||
names must either be updated or clearly mark them as historical context.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- `wf draft create --capability ...` creates the same workspace as the old
|
||||
command.
|
||||
- `wf draft add-step --capability ...` adds the same capability-backed step as
|
||||
the old command.
|
||||
- `wf draft --help` lists `create` and `add-step`, not the long
|
||||
`*-from-capability` CLI commands.
|
||||
- Skills no longer say “there is no `wf draft create --capability` alias.”
|
||||
- Existing RPC/MCP tests keep passing without programmatic surface renames.
|
||||
+3
-3
@@ -261,7 +261,7 @@ specific upstream source.
|
||||
Create a draft from a capability:
|
||||
|
||||
```bash
|
||||
wf draft create-from-capability concat_ws wf.std.concat --name concat_ws
|
||||
wf draft create concat_ws --capability wf.std.concat --name concat_ws
|
||||
```
|
||||
|
||||
List and inspect drafts:
|
||||
@@ -337,14 +337,14 @@ Use `set-route` separately for outcome routing.
|
||||
|
||||
### Add A Capability Step To A Draft
|
||||
|
||||
Use `wf draft add-step-from-capability` when adding a new capability-backed step
|
||||
Use `wf draft add-step` when adding a new capability-backed step
|
||||
to an existing draft. The command is explicit: it does not guess missing maps.
|
||||
When the capability declares multiple outcomes, provide exactly one
|
||||
`--route OUTCOME=TARGET` for each declared outcome. Missing or unknown outcomes
|
||||
are rejected before the draft is mutated.
|
||||
|
||||
```bash
|
||||
wf draft add-step-from-capability report_ws \
|
||||
wf draft add-step report_ws \
|
||||
--revision 3 \
|
||||
--step render \
|
||||
--capability local.report.render_markdown_report \
|
||||
|
||||
@@ -34,8 +34,7 @@ wf cap list --format ids
|
||||
wf cap inspect <capability>
|
||||
wf cap call <capability> --input '{"field":"value"}'
|
||||
|
||||
wf draft create-from-capability <workspace_id> <capability>
|
||||
# There is currently no `wf draft create --capability` alias.
|
||||
wf draft create <workspace_id> --capability <capability>
|
||||
wf draft inspect <workspace_id> --include-draft
|
||||
wf draft patch <workspace_id> --revision <n> --input-file patch.json
|
||||
wf draft set-name <workspace_id> --revision <n> --name <name>
|
||||
@@ -49,7 +48,7 @@ wf draft handle <workspace_id> --revision <n> --to fail --branch lookup:error --
|
||||
wf draft compile <workspace_id>
|
||||
wf draft bind <workspace_id> --revision <n> --step <step_id> --from local.<field> --to state.<field>
|
||||
wf draft bind <workspace_id> --revision <n> --step <step_id> --from input.<field> --to local.<field>
|
||||
wf draft add-step-from-capability <workspace_id> --revision <n> --step <step_id> --capability <qualified_name> --from-step <prev> --from-outcome ok --route ok=__end__ --route error=fail --input input.text=text --bind-output result=state.result
|
||||
wf draft add-step <workspace_id> --revision <n> --step <step_id> --capability <qualified_name> --from-step <prev> --from-outcome ok --route ok=__end__ --route error=fail --input input.text=text --bind-output result=state.result
|
||||
wf draft validate <workspace_id>
|
||||
wf draft save <workspace_id> --artifact <artifact_id> --version <n> --title <title>
|
||||
|
||||
@@ -88,7 +87,7 @@ projection. Use `input/state -> local` for step inputs and `local ->
|
||||
state/output` for step outputs. It requires a capability-backed step with
|
||||
`use`; use JSON Patch for non-capability/control draft steps.
|
||||
|
||||
To add a capability step, prefer `wf draft add-step-from-capability` over raw
|
||||
To add a capability step, prefer `wf draft add-step` over raw
|
||||
JSON Patch when the route, input bindings, and output-to-state bindings are
|
||||
known. It is explicit and does not guess missing maps.
|
||||
If a capability has multiple outcomes, pass one `--route OUTCOME=TARGET` for
|
||||
|
||||
@@ -18,7 +18,7 @@ low-level escape hatch or you already have a complete compiler/generated plan.
|
||||
2. Inspect one candidate with `wf cap inspect`.
|
||||
3. Call one candidate with `wf cap call` when payload shape or upstream source
|
||||
reachability is uncertain.
|
||||
4. Create a patchable draft workspace with `wf draft create-from-capability`.
|
||||
4. Create a patchable draft workspace with `wf draft create --capability`.
|
||||
5. Patch targeted fields with focused draft commands or JSON Patch.
|
||||
6. Validate with `wf draft validate`.
|
||||
7. Save an artifact with `wf draft save`, or import a complete raw plan with
|
||||
|
||||
@@ -127,8 +127,7 @@ The plan file is the low-level workflow model. It is not a draft workspace.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Do not use `wf draft create --capability`; current CLI command is
|
||||
`wf draft create-from-capability <workspace_id> <capability>`.
|
||||
- Use `wf draft create <workspace_id> --capability <capability>` for draft creation.
|
||||
- Do not pass draft JSON to `artifact create-from-plan`.
|
||||
- Do not omit deployment bindings for ordinary sources. Platform sources such
|
||||
as `wf.std` may be omitted or self-bound, but configured sources usually need
|
||||
|
||||
@@ -93,7 +93,7 @@ wf draft handle <workspace_id> --revision <n> --to fail --branch lookup:error --
|
||||
wf draft compile <workspace_id>
|
||||
wf draft bind <workspace_id> --revision <n> --step <step_id> --from local.<field> --to state.<field>
|
||||
wf draft bind <workspace_id> --revision <n> --step <step_id> --from input.<field> --to local.<field>
|
||||
wf draft add-step-from-capability <workspace_id> --revision <n> --step <step_id> --capability <qualified_name> --from-step <prev> --from-outcome ok --route ok=__end__ --route error=fail --input input.text=text --bind-output result=state.result
|
||||
wf draft add-step <workspace_id> --revision <n> --step <step_id> --capability <qualified_name> --from-step <prev> --from-outcome ok --route ok=__end__ --route error=fail --input input.text=text --bind-output result=state.result
|
||||
```
|
||||
|
||||
`set-input` direction: `input.text=text` means graph source `input.text` maps to
|
||||
@@ -134,7 +134,7 @@ wf draft validate <workspace_id>
|
||||
know a map, inspect the capability or run validation rather than guessing.
|
||||
|
||||
```bash
|
||||
wf draft add-step-from-capability <workspace_id> --revision <n> --step <step_id> --capability <qualified_name> --from-step <prev> --from-outcome ok --route ok=__end__ --route error=fail --input input.text=text --bind-output result=state.result
|
||||
wf draft add-step <workspace_id> --revision <n> --step <step_id> --capability <qualified_name> --from-step <prev> --from-outcome ok --route ok=__end__ --route error=fail --input input.text=text --bind-output result=state.result
|
||||
wf draft validate <workspace_id>
|
||||
```
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ Configured sources usually need explicit deployment bindings.
|
||||
Use the guided draft path when editing step-by-step:
|
||||
|
||||
```bash
|
||||
wf draft create-from-capability <workspace_id> <capability>
|
||||
wf draft create <workspace_id> --capability <capability>
|
||||
wf draft set-input ...
|
||||
wf draft set-output ...
|
||||
wf draft validate <workspace_id>
|
||||
|
||||
@@ -12,7 +12,7 @@ validated, runnable deployment.
|
||||
3. Inspect one capability.
|
||||
- CLI: `wf cap inspect <name>`
|
||||
4. Bootstrap a draft workspace.
|
||||
- CLI: `wf draft create-from-capability <workspace_id> <capability>`
|
||||
- CLI: `wf draft create <workspace_id> --capability <capability>`
|
||||
5. Inspect/patch/validate the workspace until valid.
|
||||
- Use focused CLI commands (`set-name`, `set-route`, `set-input`, `set-output`)
|
||||
for common edits.
|
||||
@@ -24,7 +24,7 @@ validated, runnable deployment.
|
||||
the binding in one revision-checked edit.
|
||||
- When adding a new capability-backed step, prefer:
|
||||
```bash
|
||||
wf draft add-step-from-capability ...
|
||||
wf draft add-step ...
|
||||
wf draft validate <workspace_id>
|
||||
```
|
||||
Use raw `wf draft patch` only when changing structure that no focused helper
|
||||
|
||||
@@ -92,11 +92,17 @@ def inspect_draft(
|
||||
)
|
||||
|
||||
|
||||
@app.command("create-from-capability")
|
||||
@app.command("create")
|
||||
def create_from_capability(
|
||||
ctx: typer.Context,
|
||||
workspace_id: Annotated[str, typer.Argument(help="Draft workspace id.")],
|
||||
capability_name: Annotated[str, typer.Argument(help="Workflow capability name.")],
|
||||
capability_name: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
"--capability",
|
||||
help="Qualified capability name used to bootstrap the draft.",
|
||||
),
|
||||
],
|
||||
name: Annotated[
|
||||
str | None, typer.Option("--name", help="Draft workflow name.")
|
||||
] = None,
|
||||
@@ -104,7 +110,7 @@ def create_from_capability(
|
||||
str | None, typer.Option("--title", help="Workspace title.")
|
||||
] = None,
|
||||
) -> None:
|
||||
"""Bootstrap a draft workspace from inspect_capability wrapper hints."""
|
||||
"""Create a patchable draft workspace from one capability."""
|
||||
context = load_cli_context(ctx)
|
||||
emit_json(
|
||||
run_cli_operation(
|
||||
@@ -337,7 +343,7 @@ def bind_draft(
|
||||
)
|
||||
|
||||
|
||||
@app.command("add-step-from-capability")
|
||||
@app.command("add-step")
|
||||
def add_step_from_capability(
|
||||
ctx: typer.Context,
|
||||
workspace_id: Annotated[str, typer.Argument(help="Draft workspace id.")],
|
||||
@@ -384,7 +390,7 @@ def add_step_from_capability(
|
||||
),
|
||||
] = None,
|
||||
) -> None:
|
||||
"""Add one capability step with explicit route, input, and output wiring.
|
||||
"""Add one capability-backed step with explicit route, input, and output wiring.
|
||||
|
||||
This command does not guess missing maps. Pass the route and bindings you
|
||||
want, then run `wf draft validate <workspace_id>`.
|
||||
|
||||
@@ -121,11 +121,20 @@ def test_wf_deploy_save_help_exists() -> None:
|
||||
assert "--binding" in result.output
|
||||
|
||||
|
||||
def test_wf_draft_create_from_capability_help_exists() -> None:
|
||||
result = runner.invoke(app, ["draft", "create-from-capability", "--help"])
|
||||
def test_wf_draft_create_help_accepts_capability_option() -> None:
|
||||
result = runner.invoke(app, ["draft", "create", "--help"])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "--title" in result.output
|
||||
output = " ".join(result.output.split())
|
||||
assert "--capability" in output
|
||||
assert "--title" in output
|
||||
|
||||
|
||||
def test_wf_draft_help_does_not_list_old_create_from_capability() -> None:
|
||||
result = runner.invoke(app, ["draft", "--help"])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "create-from-capability" not in result.output
|
||||
|
||||
|
||||
def test_wf_draft_map_help_explains_replace_merge_and_validate() -> None:
|
||||
@@ -154,22 +163,30 @@ def test_wf_draft_bind_help_explains_direction() -> None:
|
||||
assert "validate" in output
|
||||
|
||||
|
||||
def test_wf_draft_add_step_from_capability_help_explains_explicit_wiring() -> None:
|
||||
result = runner.invoke(app, ["draft", "add-step-from-capability", "--help"])
|
||||
def test_wf_draft_add_step_help_explains_explicit_wiring() -> None:
|
||||
result = runner.invoke(app, ["draft", "add-step", "--help"])
|
||||
|
||||
assert result.exit_code == 0
|
||||
output = " ".join(result.output.split())
|
||||
assert "--capability" in output
|
||||
assert "--from-step" in output
|
||||
assert "--bind-output" in output
|
||||
assert "does not guess" in output
|
||||
|
||||
|
||||
def test_wf_draft_help_does_not_list_old_add_step_from_capability() -> None:
|
||||
result = runner.invoke(app, ["draft", "--help"])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "add-step-from-capability" not in result.output
|
||||
|
||||
|
||||
def test_wf_draft_route_flags_reject_duplicate_outcomes() -> None:
|
||||
add_result = runner.invoke(
|
||||
app,
|
||||
[
|
||||
"draft",
|
||||
"add-step-from-capability",
|
||||
"add-step",
|
||||
"ws",
|
||||
"--revision",
|
||||
"1",
|
||||
|
||||
@@ -302,8 +302,9 @@ def test_wf_draft_create_patch_validate_save(tmp_path: Path) -> None:
|
||||
"--config",
|
||||
str(config_path),
|
||||
"draft",
|
||||
"create-from-capability",
|
||||
"create",
|
||||
"echo_workspace",
|
||||
"--capability",
|
||||
"demo.personal.echo_tool",
|
||||
"--name",
|
||||
"echo_workspace",
|
||||
|
||||
@@ -633,8 +633,9 @@ def test_wf_remote_draft_artifact_deploy_lifecycle(monkeypatch, tmp_path) -> Non
|
||||
[
|
||||
*base_args,
|
||||
"draft",
|
||||
"create-from-capability",
|
||||
"create",
|
||||
"remote_ws",
|
||||
"--capability",
|
||||
"wf.std.constant",
|
||||
"--name",
|
||||
"remote_constant",
|
||||
@@ -657,8 +658,9 @@ def test_wf_remote_draft_artifact_deploy_lifecycle(monkeypatch, tmp_path) -> Non
|
||||
[
|
||||
*base_args,
|
||||
"draft",
|
||||
"create-from-capability",
|
||||
"create",
|
||||
"repair_ws",
|
||||
"--capability",
|
||||
"wf.std.constant",
|
||||
"--name",
|
||||
"repair_constant",
|
||||
@@ -927,8 +929,9 @@ def test_wf_draft_delete_succeeds_with_confirm(monkeypatch, tmp_path) -> None:
|
||||
[
|
||||
*base_args,
|
||||
"draft",
|
||||
"create-from-capability",
|
||||
"create",
|
||||
"delete-me",
|
||||
"--capability",
|
||||
"wf.std.constant",
|
||||
"--name",
|
||||
"delete_me_ws",
|
||||
@@ -1000,8 +1003,9 @@ def test_wf_draft_focused_edit_commands_use_rpc_target(monkeypatch, tmp_path) ->
|
||||
[
|
||||
*base_args,
|
||||
"draft",
|
||||
"create-from-capability",
|
||||
"create",
|
||||
"focused_ws",
|
||||
"--capability",
|
||||
"wf.std.constant",
|
||||
"--name",
|
||||
"focused_initial",
|
||||
@@ -1152,8 +1156,9 @@ def test_wf_draft_bind_uses_rpc_target(monkeypatch, tmp_path) -> None:
|
||||
[
|
||||
*base_args,
|
||||
"draft",
|
||||
"create-from-capability",
|
||||
"create",
|
||||
"snapshot_ws",
|
||||
"--capability",
|
||||
"wf.std.constant",
|
||||
"--name",
|
||||
"snapshot",
|
||||
@@ -1199,8 +1204,9 @@ def test_wf_draft_add_step_from_capability_uses_rpc_target(
|
||||
[
|
||||
*base_args,
|
||||
"draft",
|
||||
"create-from-capability",
|
||||
"create",
|
||||
"add_step_ws",
|
||||
"--capability",
|
||||
"wf.std.constant",
|
||||
"--name",
|
||||
"add_step",
|
||||
@@ -1213,7 +1219,7 @@ def test_wf_draft_add_step_from_capability_uses_rpc_target(
|
||||
[
|
||||
*base_args,
|
||||
"draft",
|
||||
"add-step-from-capability",
|
||||
"add-step",
|
||||
"add_step_ws",
|
||||
"--revision",
|
||||
"1",
|
||||
@@ -1253,8 +1259,9 @@ def test_wf_draft_compile_prints_compiled_plan(monkeypatch, tmp_path) -> None:
|
||||
[
|
||||
*base_args,
|
||||
"draft",
|
||||
"create-from-capability",
|
||||
"create",
|
||||
"compile_ws",
|
||||
"--capability",
|
||||
"wf.std.constant",
|
||||
"--name",
|
||||
"compile_me",
|
||||
|
||||
Reference in New Issue
Block a user