ADR-006: CLI as Machine-to-Machine (M2M) API
Status
Proposed
Context
The idempiere-cli can serve as a programmatic interface similar to a REST API. This enables:
- CI/CD pipeline integration
- Scripting and automation
- Integration with other tools (IDEs, build systems)
- Programmatic access to iDempiere Application Dictionary operations
This ADR documents the CLI's M2M communication contract.
CLI as API Architecture
┌─────────────────────────────────────────────────────────────────┐
│ M2M Communication Flow │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌─────────────────┐ ┌──────────────┐ │
│ │ Caller │ │ idempiere-cli │ │ iDempiere │ │
│ │ (Script/CI) │────▶│ (CLI/API) │────▶│ REST API │ │
│ └──────────────┘ └─────────────────┘ └──────────────┘ │
│ │ │ │ │
│ │ │ │ │
│ Arguments Exit Code JSON/XML │
│ + Options + stdout Response │
│ + stdin + stderr │
│ │
└─────────────────────────────────────────────────────────────────┘
API Contract
1. Exit Codes
| Code | Meaning | Use Case |
|---|---|---|
0 |
Success | Operation completed successfully |
1 |
Error | Operation failed (check stderr for details) |
Example:
idempiere-cli add column XX_Field --table C_Order --type string
if [ $? -eq 0 ]; then
echo "Column created successfully"
else
echo "Column creation failed"
fi
2. Output Streams
| Stream | Content | Format |
|---|---|---|
stdout |
Success output, data | Human-readable (default) or JSON (--json) |
stderr |
Error messages, warnings | Human-readable |
Example:
# Capture output
OUTPUT=$(idempiere-cli export table XX_MyTable -f sql 2>/dev/null)
# Capture errors
idempiere-cli add column XX_Bad --table NonExistent 2>&1
3. Input Methods
| Method | Use Case | Example |
|---|---|---|
| CLI Arguments | Simple values | --table C_Order --type string |
| Options | Flags and configuration | --dry-run --verbose |
| Environment Variables | Secrets, configuration | IDEMPIERE_API_TOKEN |
| Config File | Persistent settings | ~/.idempiere-cli/config.yaml |
Command Reference for M2M
Configuration Commands
# Configure API connection (store credentials)
idempiere-cli config \
--url https://idempiere.example.com \
--token "$IDEMPIERE_TOKEN"
# Test connection (exit 0 = connected)
idempiere-cli config --test
Application Dictionary Commands
# Add column (returns exit 0 on success)
idempiere-cli add column XX_MyField \
--table C_BPartner \
--type string \
--length 100 \
--mandatory
# Add table with columns
idempiere-cli add table XX_MyTable \
--description "Custom table" \
--columns standard,document
# Dry run (preview without changes)
idempiere-cli add column XX_Test \
--table C_Order \
--type yesno \
--dry-run
Sync Commands
# Sync table to database
idempiere-cli sync table XX_MyTable
# Sync specific column
idempiere-cli sync column XX_MyTable.XX_MyColumn
Export Commands
# Export to 2Pack XML (stdout)
idempiere-cli export table XX_MyTable -f pack
# Export to SQL files
idempiere-cli export table XX_MyTable -f sql -o ./migration/
# Export to specific file
idempiere-cli export table XX_MyTable -o META-INF/2Pack.zip
Plugin Scaffolding
# Create plugin (non-interactive)
idempiere-cli init org.mycompany.myplugin \
--name "My Plugin" \
--version 1.0.0 \
--with-callout \
--with-process \
-i 12 \
-o ./plugins/
M2M Integration Patterns
Pattern 1: CI/CD Pipeline Integration
# GitHub Actions example
jobs:
create-table:
runs-on: ubuntu-latest
steps:
- name: Configure CLI
run: |
idempiere-cli config \
--url ${{ secrets.IDEMPIERE_URL }} \
--token ${{ secrets.IDEMPIERE_TOKEN }}
- name: Create Table
run: |
idempiere-cli add table XX_AuditLog \
--description "Audit logging table" \
--columns standard
- name: Sync to Database
run: |
idempiere-cli sync table XX_AuditLog
- name: Export 2Pack
run: |
idempiere-cli export table XX_AuditLog \
-o META-INF/2Pack.zip
Pattern 2: Scripting Multiple Operations
#!/bin/bash
# create-invoice-customization.sh
set -e # Exit on any error
TABLE="XX_InvoiceExt"
# Step 1: Create table
echo "Creating table $TABLE..."
idempiere-cli add table $TABLE \
--description "Invoice Extension" \
--columns standard
# Step 2: Add custom columns
echo "Adding columns..."
idempiere-cli add column XX_ApprovalDate \
--table $TABLE \
--type date
idempiere-cli add column XX_ApprovedBy_ID \
--table $TABLE \
--type table \
--reference-table AD_User
idempiere-cli add column XX_Notes \
--table $TABLE \
--type memo
# Step 3: Sync
echo "Syncing to database..."
idempiere-cli sync table $TABLE
# Step 4: Export
echo "Exporting 2Pack..."
idempiere-cli export table $TABLE -o "$TABLE-2pack.zip"
echo "Done! Created $TABLE with custom columns."
Pattern 3: IDE Integration
// VS Code tasks.json
{
"version": "2.0.0",
"tasks": [
{
"label": "iDempiere: Add Column",
"type": "shell",
"command": "idempiere-cli",
"args": [
"add", "column", "${input:columnName}",
"--table", "${input:tableName}",
"--type", "${input:columnType}"
],
"problemMatcher": []
},
{
"label": "iDempiere: Sync Table",
"type": "shell",
"command": "idempiere-cli",
"args": ["sync", "table", "${input:tableName}"],
"problemMatcher": []
}
],
"inputs": [
{
"id": "tableName",
"type": "promptString",
"description": "Table name"
},
{
"id": "columnName",
"type": "promptString",
"description": "Column name"
},
{
"id": "columnType",
"type": "pickString",
"description": "Column type",
"options": ["string", "integer", "date", "yesno", "amount", "table"]
}
]
}
Pattern 4: Build Tool Integration (Maven)
<!-- pom.xml -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>export-2pack</id>
<phase>package</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>idempiere-cli</executable>
<arguments>
<argument>export</argument>
<argument>table</argument>
<argument>${project.artifactId}</argument>
<argument>-o</argument>
<argument>${project.build.directory}/META-INF/2Pack.zip</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
Environment Variables
| Variable | Purpose | Example |
|---|---|---|
IDEMPIERE_API_URL |
iDempiere REST API URL | https://idempiere.example.com |
IDEMPIERE_API_TOKEN |
Authentication token | eyJhbGc... |
ANTHROPIC_API_KEY |
Claude AI API key (for ai command) |
sk-ant-... |
IDEMPIERE_CLI_CONFIG |
Config file path | ~/.idempiere-cli/config.yaml |
Comparison: CLI vs REST API
| Aspect | CLI (M2M) | iDempiere REST API |
|---|---|---|
| Authentication | Token in config file or env var | Bearer token in header |
| Input Format | CLI arguments | JSON body |
| Output Format | Text (human) or structured (file) | JSON |
| Batching | Shell scripts | Single request |
| Error Handling | Exit codes + stderr | HTTP status codes |
| Offline Operations | Plugin scaffolding, DDL preview | Not supported |
| Best For | Automation, CI/CD, scripting | Direct API integration |
When to Use CLI
- CI/CD pipelines
- Shell scripts
- Local development workflow
- Offline operations (init, export)
- Quick one-off commands
When to Use REST API Directly
- Custom application integration
- Real-time data synchronization
- Complex queries
- High-volume operations
Future Enhancements (Roadmap)
Phase 1: JSON Output Mode (Proposed)
# Machine-readable output
idempiere-cli add column XX_Field --table C_Order --type string --json
# Output:
{
"success": true,
"operation": "add_column",
"table": "C_Order",
"column": "XX_Field",
"columnId": 1000123
}
Phase 2: Batch Operations (Proposed)
# Execute multiple operations from file
idempiere-cli batch ./operations.yaml
# operations.yaml
operations:
- type: add_column
table: C_Order
column: XX_Field1
dataType: string
- type: add_column
table: C_Order
column: XX_Field2
dataType: integer
Phase 3: Watch Mode (Proposed)
# Watch for changes and auto-sync
idempiere-cli watch ./ad-definitions/
Decision
- Document CLI as M2M API with clear contracts
- Maintain consistent exit codes (0=success, 1=error)
- Plan JSON output mode for structured responses
- Enable CI/CD and scripting use cases
Consequences
Positive
- Clear contract for automation
- Enables CI/CD integration
- Scriptable workflows
- IDE integration possibilities
Negative
- Additional documentation to maintain
- JSON output requires implementation work
- May need TTY detection for interactive prompts
Neutral
- CLI remains primary interface
- REST API still available for direct integration