ADR-031: CLI Usability - Gateway Commands and Interactive Mode

Status

Proposed

Date

2025-12-07

Deciders

Research Summary

ERP CLI Comparison (Odoo, Frappe, SAP, Dynamics 365)

Feature Odoo Frappe SAP BTP D365 iDempiere
Command Pattern Verb-Noun Noun-Verb Verb-Noun-Noun Verb-Noun Noun-Verb
Scaffolding scaffold new-app ❌ ❌ dev init
Code Generation ❌ ❌ ❌ ❌ ✅ unique
Hot Reload --dev reload serve ❌ ❌ ❌
Shell/REPL shell console ❌ ❌ shell
IDE Setup ❌ ❌ ❌ ❌ ✅ unique
AI Features ❌ ❌ ❌ ❌ ✅ unique
Plugin System ❌ ❌ ❌ ❌ ✅ unique
JSON Output ❌ ❌ ❌ --output json --json
Dry Run ❌ ❌ ❌ --whatif --dry-run

Headless CMS & E-commerce CLI Comparison

Platform Type Key CLI Commands Schema Approach
Strapi Headless CMS generate, transfer, export Code-first
Contentful Headless CMS migration, Merge App CLI Migration scripts
Sanity Headless CMS schema validate, migration create TypeScript-first
Directus Headless CMS schema snapshot/apply Database-first
Shopify E-commerce app dev, theme dev, AI code gen Platform-managed
Magento E-commerce module:enable, setup:upgrade Module lifecycle
Medusa E-commerce seed, create-medusa-app Seed data focus
Saleor E-commerce Configurator CLI GraphQL-native

Key Sources

Source URL Insight
Odoo CLI https://www.odoo.com/documentation/19.0/developer/reference/cli.html Hot reload, scaffolding
Frappe Bench https://docs.frappe.io/framework/user/en/bench/bench-commands Comprehensive workflow
SAP BTP CLI https://help.sap.com/docs/btp/sap-business-technology-platform/commands-in-btp-cli Enterprise patterns
Strapi CLI https://docs.strapi.io/cms/cli Transfer tools, generators
Directus Migrations https://directus.io/docs/configuration/migrations Snapshot/apply pattern
Shopify CLI https://github.com/Shopify/cli AI code gen, MCP support
Magento CLI https://experienceleague.adobe.com/en/docs/commerce-operations/tools/cli-reference Module lifecycle
clig.dev https://clig.dev/ Modern CLI guidelines
12-Factor CLI https://medium.com/@jdxcode/12-factor-cli-apps-dd3c227a0e46 Best practices

iDempiere CLI Unique Strengths (No Other ERP Has)

  1. Code Generation: gen model, gen process, gen callout, gen event
  2. IDE Setup Automation: ide eclipse, ide intellij, ide vscode
  3. AI Integration: MCP server, RAG knowledge base, LangChain4j
  4. Plugin System: SPI-based extensibility
  5. Application Dictionary Query: dict registry with live database access

Context and Problem Statement

The iDempiere CLI has grown to 60+ commands across 11 groups. While powerful, this creates a discovery and usability problem for new users. Analysis shows:

Interface Time to create table Effort
Web UI 20-25 min ~50 clicks
CLI (current) 3-5 min 5 commands (must know them)
AI (MCP) 30-60 sec 1 prompt

The CLI is 4-5x faster than Web UI, but requires knowing which commands to use. New users face a steep learning curve.

Decision Drivers

Considered Options

  1. Gateway commands only: Add new, add, deploy as simplified entry points
  2. Interactive mode only: Launch wizard when no command given
  3. Both gateway commands + interactive mode: Comprehensive solution
  4. AI-first: Route everything through ai ask

Decision Outcome

Chosen option: "Both gateway commands + interactive mode", because it serves both users who know what they want (new plugin) and users who are exploring (just run idempiere-cli).

Implementation

1. Gateway Commands

Three task-oriented commands that wrap existing functionality:

idempiere-cli new - Create something new

# Interactive - shows menu
$ idempiere-cli new
? What do you want to create?
  > plugin     - New iDempiere plugin project
    table      - New table with window
    process    - New process class
    callout    - New callout class
    form       - New ZK form

# Direct - skips menu
$ idempiere-cli new plugin org.mycompany.hr
$ idempiere-cli new table XX_Employee
$ idempiere-cli new process MyProcess

Mapping:

new subcommand Underlying command
new plugin dev init
new table dict add table --wizard
new process gen process
new callout gen callout
new form gen form

idempiere-cli add - Add to existing

# Interactive
$ idempiere-cli add
? What do you want to add?
  > column     - Add column to existing table
    field      - Add field to existing window
    menu       - Add menu entry
    process    - Add process to plugin

# Direct
$ idempiere-cli add column XX_Employee.Email
$ idempiere-cli add menu "My Menu" --window XX_Employee

Mapping:

add subcommand Underlying command
add column dict add column
add field dict add field
add menu dict add menu
add process dict add process

idempiere-cli deploy - Ship your work

# Interactive
$ idempiere-cli deploy
? What do you want to deploy?
  > packout    - Export changes as 2Pack
    packin     - Import 2Pack to server
    sync       - Sync table to database

# Direct
$ idempiere-cli deploy packout -o MyPlugin.zip
$ idempiere-cli deploy packin MyPlugin.zip

Mapping:

deploy subcommand Underlying command
deploy packout pack out
deploy packin pack in
deploy sync dict sync

2. Interactive Mode

When user runs idempiere-cli with no arguments OR with --interactive:

$ idempiere-cli

▗▄▄▄▖▗▄▄▄ ▗▄▄▄▖▗▖  ▗▖▗▄▄▖▗▄▄▄▖▗▄▄▄▖▗▄▄▖ ▗▄▄▄▖     ▗▄▄▖▗▖   ▗▄▄▄▖
  ...

iDempiere Development, AI & DevOps CLI  v1.56.0

? What would you like to do?
  > Create something new          (new)
    Add to existing               (add)
    Deploy / export               (deploy)
    Check environment             (doctor)
    Ask AI                        (ai)
    Show all commands             (help)
    Exit

3. Command Structure

idempiere-cli
├── new                    # Gateway: create new things
│   ├── plugin             # → dev init
│   ├── table              # → dict add table --wizard
│   ├── process            # → gen process
│   ├── callout            # → gen callout
│   └── form               # → gen form
├── add                    # Gateway: add to existing
│   ├── column             # → dict add column
│   ├── field              # → dict add field
│   ├── menu               # → dict add menu
│   └── process            # → dict add process
├── deploy                 # Gateway: deployment
│   ├── packout            # → pack out
│   ├── packin             # → pack in
│   └── sync               # → dict sync
├── doctor                 # Keep at top level (common)
├── ai                     # Keep at top level (common)
│   └── ask                # Natural language
├── dev/dict/gen/pack/...  # Expert commands (unchanged)
└── shell                  # Interactive REPL

4. Implementation Details

NewCommand.java

@Command(name = "new",
    description = "Create new iDempiere artifacts",
    subcommands = {
        NewPluginCommand.class,
        NewTableCommand.class,
        NewProcessCommand.class,
        NewCalloutCommand.class,
        NewFormCommand.class
    })
public class NewCommand implements Callable<Integer> {

    @Inject JLinePrompt prompt;

    @Override
    public Integer call() {
        // No subcommand given - show interactive menu
        List<String> options = List.of(
            "plugin   - New iDempiere plugin project",
            "table    - New table with window",
            "process  - New process class",
            "callout  - New callout class",
            "form     - New ZK form"
        );

        int selected = prompt.promptSelect("What do you want to create?", options, 0);

        // Delegate to appropriate subcommand
        return switch (selected) {
            case 0 -> new NewPluginCommand().call();
            case 1 -> new NewTableCommand().call();
            // ...
            default -> ExitCodes.SUCCESS;
        };
    }
}

Interactive Mode in IdempiereCli.java

@Override
public Integer call() {
    // No subcommand - launch interactive mode
    if (System.console() != null && isInteractive()) {
        return runInteractiveMode();
    }

    // Non-interactive - show help
    printBanner();
    printGroupedHelp();
    return 0;
}

private int runInteractiveMode() {
    printBanner();

    List<String> options = List.of(
        "Create something new     (new)",
        "Add to existing          (add)",
        "Deploy / export          (deploy)",
        "Check environment        (doctor)",
        "Ask AI                   (ai)",
        "Show all commands        (help)",
        "Exit"
    );

    int selected = jlinePrompt.promptSelect("What would you like to do?", options, 0);

    return switch (selected) {
        case 0 -> runNew();
        case 1 -> runAdd();
        case 2 -> runDeploy();
        case 3 -> runDoctor();
        case 4 -> runAi();
        case 5 -> { printGroupedHelp(); yield 0; }
        default -> 0;
    };
}

Pros and Cons

Pros

Cons

Migration Path

  1. v1.57.0: Add gateway commands (new, add, deploy)
  2. v1.58.0: Add interactive mode when no args
  3. Future: Consider deprecating some nested commands if gateway proves popular

References

Path: /docs/developers/architecture/idempiere-hub/031-cli-usability-gateway-commands