CLI_CONVERGENCE_PLAN

CLI Convergence Plan: gxwf-* Namespace Unification

Date: 2026-03-28 Branch (Galaxy): wf_tool_state Branch (gxformat2): abstraction_applications Status: IN PROGRESS

Motivation

The galaxy-tool-util workflow CLIs (galaxy-workflow-*) exist in a separate naming namespace from the gxformat2 CLIs (gxwf-*). The gxformat2 commands are structural (no tool defs), the galaxy-tool-util commands are schema-aware (need tool defs). They should feel like one cohesive toolkit — the gxwf-* namespace already exists and is the right home. The stateful variants extend the structural ones by adding tool-definition awareness.

This plan:

  1. Renames the galaxy-tool-util CLIs into the gxwf-* namespace
  2. Converges gxwf-to-format2 and gxwf-to-format2-stateful in structure/options
  3. Implements gxwf-to-native-stateful (format2→native with schema-aware encoding)
  4. Implements gxwf-lint-stateful (structural lint + tool state validation)

Since nothing has been released, we optimize for clean abstractions over backward compat.


Step 0: Rename Galaxy CLI Entry Points — COMPLETE

Commit: 8b0f33d91f

Renamed all galaxy-workflow-* commands to gxwf-*:

Old NameNew Name
galaxy-workflow-validategxwf-state-validate
galaxy-workflow-clean-stale-stategxwf-state-clean
galaxy-workflow-roundtrip-validategxwf-roundtrip-validate
galaxy-workflow-export-format2gxwf-to-format2-stateful
galaxy-tool-cachegalaxy-tool-cache (kept — not workflow-specific)

Files changed: setup.cfg, 4 script files (docstrings + prog=), wf_tooling.md (~40 references).


Step 1: Converge gxwf-to-format2 CLI Options — COMPLETE

Commits: 4379a59617 (convergence), e630b900a7 (remove —diff)

What Was Done

gxformat2 side (export.py — uncommitted, on abstraction_applications branch):

galaxy-tool-util side:

Converged Interface

Both gxwf-to-format2 and gxwf-to-format2-stateful now share:

Remaining differences are all inherently tool-definition-dependent:

Stateful-only flagsPurpose
--populate-cacheAuto-fetch tool defs
--tool-sourceWhere to fetch tool defs
--strictFail if any step can’t be schema-convert
--allow/--denyStale key policy
Directory inputBatch conversion

Step 2: Implement gxwf-to-native-stateful — COMPLETE

Commit: 7c9b9dc2c0

What Was Built

  1. to_native_stateful.py — core module:

    • convert_to_native_stateful(path, get_tool_info, strict)ToNativeResult
    • Loads file via ordered_load_path, rejects native input (would bypass encoder)
    • Calls to_native() with state_encode_to_native callback wrapping make_encode_tool_state()
    • StepEncodeStatus / ToNativeResult — per-step tracking (parallel to export’s StepExportStatus / ExportResult)
    • ToNativeOptions extends ToolCacheOptions, run_to_native() entry point
    • EncodeError for strict-mode failures
  2. scripts/workflow_to_native_stateful.py — thin CLI entry point via cli_main()

  3. setup.cfg — registered gxwf-to-native-stateful console script

  4. TestsTestToNativeStatefulCLIParser in test_tool_cache.py (5 tests: basic, -o, —strict, —populate-cache, -v)

CLI Interface

gxwf-to-native-stateful INPUT [-o FILE] [--strict] [--populate-cache] [--tool-source shed|galaxy|auto] [-v]

Design Decisions

Deferred


Step 3: Implement gxwf-lint-stateful — COMPLETE

Commit: 0ef61c0b28

Design Decision

Used Option A — separate gxwf-lint-stateful command in galaxy-tool-util. Clean dependency direction: galaxy-tool-util imports and delegates to gxformat2’s lint functions, then adds stateful checks.

What Was Built

  1. lint_stateful.py — core module:

    • run_structural_lint(workflow_dict, ...)LintContext — mirrors gxformat2’s main() but returns context instead of printing/exiting, enabling composition
    • run_lint_stateful(options) → exit code — two-phase pipeline: structural lint then stateful validation
    • format_lint_header() / format_combined_text() — unified output formatting
    • _lint_context_exit_code() / _combined_exit_code() — merged exit code logic
    • LintStatefulOptions — combines gxwf-lint args + gxwf-state-validate args
  2. scripts/workflow_lint_stateful.py — thin CLI entry point

  3. setup.cfg — registered gxwf-lint-stateful console script

  4. TestsTestLintStatefulCLIParser in test_tool_cache.py (9 tests)

CLI Interface

gxwf-lint-stateful INPUT [--strict] [--summary] [--connections]
    [--skip-best-practices] [--training-topic TOPIC]
    [--allow CAT] [--deny CAT]
    [--populate-cache] [--tool-source shed|galaxy|auto]
    [--report-json [FILE]] [--report-markdown [FILE]] [-v]

Design Notes

Deferred


Step 4: Converge gxwf-to-native CLI Options (gxformat2 side) — COMPLETE

Commit: 212bc6e (gxformat2 abstraction_applications branch)

Combined with the Step 1 export.py changes in a single commit:

  1. converter.py (gxwf-to-native):

    • Stdout by default (was: required output path or auto-generated INPUT.gxwf.yml)
    • Added -o FILE option
    • Fixed bug: workflow_directory was os.path.abspath(format2_path) (the file), now os.path.dirname(...) (the parent dir)
  2. export.py (gxwf-to-format2):

    • Stdout by default (was: required output path or auto-generated INPUT.gxwf.yml)
    • Added -o FILE option, --json, --compact
    • Fixed typo in help: .gxfw.yml.gxwf.yml

Converged Interface (both commands)

Flaggxwf-to-nativegxwf-to-format2
Positional INPUTyesyes
Positional OUTPUTyes (optional)yes (optional)
-o FILEyesyes
stdout defaultyesyes
--compactyes
--jsonyes (native is always JSON)

Deferred


Step 5: Update Documentation and Tests


Final CLI Landscape

┌─────────────────────────────────────────────────────────────────────┐
│                          planemo                                    │
│  workflow_lint  run  test  autoupdate  workflow_test_init           │
├─────────────────────────────────────────────────────────────────────┤
│                   galaxy-tool-util (stateful)                       │
│  Schema-aware · uses ParsedTool from ToolShed 2.0                  │
│                                                                     │
│  gxwf-state-validate        gxwf-state-clean                       │
│  gxwf-roundtrip-validate    gxwf-lint-stateful                     │
│  gxwf-to-format2-stateful   gxwf-to-native-stateful               │
│  galaxy-tool-cache                                                  │
├─────────────────────────────────────────────────────────────────────┤
│                    gxformat2 (structural)                            │
│  No tool definitions · format conversion · structural lint          │
│                                                                     │
│  gxwf-lint  gxwf-to-native  gxwf-to-format2                       │
│  gxwf-viz   gxwf-abstract-export                                   │
│                                                                     │
│  Callback slots:                                                    │
│    state_encode_to_format2 · state_encode_to_native                 │
└─────────────────────────────────────────────────────────────────────┘

Implementation Order

PhaseStepsPackageEffort
A0 (rename)galaxy-tool-utilSmall DONE
B1 (converge format2 export options)bothSmall DONE
C2 (gxwf-to-native-stateful)galaxy-tool-utilMedium DONE
D3 (gxwf-lint-stateful)bothMedium DONE
E4 (converge gxwf-to-native options)gxformat2Small DONE
F5 (docs + tests)bothMedium

C and D can proceed in parallel. E is independent.


Unresolved Questions