Skip to main content

Acumatica ERP Config-as-Code: tenant provisioning, baseline config, and reference data

Project description

Acumatica CLI

acu — configure Acumatica ERP purely from source code: no UI clicks, no Configuration Wizard.

Every operation is idempotent:

  • acu apply upserts records by key — running it twice is safe
  • acu diff detects drift between your YAML and the live tenant
  • acu tenant create bootstraps the new tenant at birth, so it is ready for acu apply in one step

Development environment. All development and live verification is done against Acumatica ERP 26.101.0225 running on Windows Server 2025, using the contract-based REST API endpoint Default/25.200.001. Other versions will likely work, but only this combination is tested.

Why?

Acumatica configuration normally lives in the web UI: wizards, screens, and manual data entry that nobody can review, version, or reproduce. acu moves that configuration into YAML files in a git repo, so a tenant can be rebuilt from scratch, audited in a pull request, and checked for drift like any other infrastructure.

Quick start

From the data repo:

acu config show     # sanity-check the resolved target
acu tenant create --id 3 --login DEV    # create the tenant + bootstrap it
acu --tenant DEV apply                  # seed bootstrap/, baseline/, setup/
acu --tenant DEV diff                   # prove zero drift (exit 2 on drift)

CLI Map

acu [--tenant NAME] [--url URL] [--ssh USER@HOST] [--username U] [--password P]
│
├── tenant                            tenant CRUD (ac.exe over SSH — control plane)
│   ├── list                          CompanyID, sign-in name, internal CD, type
│   ├── create --id N --login NAME    create a tenant + bootstrap it, ready to apply
│   │          [--type SalesDemo] [--parent N] [--hidden] [--no-init]
│   └── delete                        delete a tenant and its data, recycle app pool
│
├── apply [--dry-run] FILES...        seed baseline YAML via REST (idempotent PUT upserts)
├── diff FILES...                     drift check: YAML vs live tenant (exit 2 on drift)
├── schema [--out DIR]                dump the endpoint's OpenAPI schema (swagger.json)
│
└── config                            configuration ops
    ├── init [--host HOST] [DIR]      scaffold a data repo (.env plus example YAML)
    ├── show                          print the resolved target as a complete .env
    └── check                         read-only preflight: discovery, secrets, REST, SSH

The target instance comes from .env (found by walking up from the current directory), every key an ACU_* variable; global options (--tenant, --url, --ssh, --api-version, --username, --password) override per key. Run acu <command> --help for details on any command.

Installation

acu requires Python 3.12 or newer. Pick one of the options below — each code block is a complete, standalone command.

From PyPI (recommended)

With uv, installed as an isolated tool:

uv tool install acumatica-cli

With pipx:

pipx install acumatica-cli

With plain pip:

pip install acumatica-cli

From the GitHub repository

Install the latest development version straight from the main branch:

uv tool install git+https://github.com/kborovik/acumatica-cli.git

Or with pip:

pip install git+https://github.com/kborovik/acumatica-cli.git

Verify the installation:

acu --help

Configuration

Configuration lives in one file plus your SSH setup:

  1. .env — the whole configuration: where to apply and who signs in, every key an ACU_* variable. Three values are required — ACU_BASE_URL (the REST root: scheme, host, and site path), ACU_SSH (the control-plane user@host), and ACU_PASSWORD. Everything else has a code default matching a stock Acumatica install:

    ACU_BASE_URL=http://acu-dev1.vm.internal/AcumaticaERP
    ACU_SSH=Administrator@acu-dev1.vm.internal
    ACU_TENANT=Company    # sign-in name of the tenant API sessions use
    ACU_USER=admin        # optional, defaults to admin
    ACU_PASSWORD=...      # required
    

    Nothing is derived: split-horizon DNS, port forwards, and jump hosts are all handled by writing the address you actually want into the two address keys. The file is found by walking up from the current directory, so any subdirectory of the data repo works; without a .env, global flags plus the process environment supply the full config. The data repo stores the file encrypted as .env.gpg; make decrypt produces the plaintext .env once per clone.

    acu config show prints the fully resolved configuration as a complete, valid .env — every knob visible, the password excluded. To turn the resolved state into your working config, redirect and edit:

    acu config show > .env
    
  2. SSHhow the control plane reaches the Windows guest. Configured on the guest and in your ~/.ssh, not in .env — see the next section.

Verify the result before touching anything live:

acu config check          # read-only preflight: discovery, secrets, REST, SSH
acu config show           # the fully resolved configuration as .env, no secrets
acu apply --dry-run baseline/

Two planes

acu talks to an instance over two independent channels:

  • Control plane (SSH): tenant create/delete/list via ac.exe -cm:CompanyConfig and sqlcmd on the Windows guest — see docs/ac-exe.md. Used by acu tenant.
  • Data plane (REST): baseline configuration and reference data through the contract-based API (/entity/Default/25.200.001/), where PUT is a keyed upsert — see docs/rest-api.md. Used by acu apply, acu diff, and acu schema.

If you only apply and diff baseline YAML, you never need SSH. SSH setup is required only for acu tenant.

SSH setup (control plane)

acu tenant runs commands on the Windows guest through plain ssh. Two things about this setup are not obvious, and both are hard requirements:

1. The default SSH shell on the Windows guest must be PowerShell. acu sends PowerShell syntax over the wire (& 'C:\...\ac.exe' ..., Import-Module WebAdministration, exit $LASTEXITCODE). Windows OpenSSH ships with cmd.exe as the default shell, where every one of those commands fails. Switch it once, in an elevated PowerShell on the guest:

New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell `
  -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" `
  -PropertyType String -Force

2. Authentication must be key-based and non-interactive. acu connects with BatchMode=yes, so it will never answer a password prompt — without a working key the connection just fails. And because the default ssh_user is Administrator (an administrators-group member), Windows OpenSSH reads the key from the machine-wide file C:\ProgramData\ssh\administrators_authorized_keysnot from ~\.ssh\authorized_keys like on Linux. On the guest:

# install + start the server (once)
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Set-Service sshd -StartupType Automatic
Start-Service sshd

# authorize your public key for administrators
Add-Content -Path C:\ProgramData\ssh\administrators_authorized_keys Value "ssh-ed25519 AAAA... you@laptop"

# the file must be readable by SYSTEM/Administrators only, or sshd ignores it
icacls C:\ProgramData\ssh\administrators_authorized_keys /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F" 

Then verify from your workstation — this one test proves both requirements at once (key auth works, and the shell is PowerShell):

ssh -o BatchMode=yes Administrator@acu-dev1.vm.internal '$PSVersionTable.PSVersion'

A version table means you are ready; a password prompt or '$PSVersionTable.PSVersion' is not recognized... means requirement 2 or 1 (respectively) is not met yet. Host aliases, jump hosts, and ports go in your ~/.ssh/config as usual, or set ACU_SSH=user@alias in .env.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

acumatica_cli-0.3.0.tar.gz (40.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

acumatica_cli-0.3.0-py3-none-any.whl (51.0 kB view details)

Uploaded Python 3

File details

Details for the file acumatica_cli-0.3.0.tar.gz.

File metadata

  • Download URL: acumatica_cli-0.3.0.tar.gz
  • Upload date:
  • Size: 40.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for acumatica_cli-0.3.0.tar.gz
Algorithm Hash digest
SHA256 53314916516693f6f6268c8ec4bdf81cbfcd9e55c4e72700d0174663ca60e1b2
MD5 6f37d75b8277a8bb69c9ec2307482da2
BLAKE2b-256 eacf6efdd2e72a2695d38ba324cbcff5072a2335df1aaf0e6b096422de317423

See more details on using hashes here.

Provenance

The following attestation bundles were made for acumatica_cli-0.3.0.tar.gz:

Publisher: release.yml on kborovik/acumatica-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file acumatica_cli-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: acumatica_cli-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 51.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for acumatica_cli-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fe04aefd8dd97e8a6a386a4060a2dc1afdb80bd742d6a2b9b3f97b93cb328703
MD5 666cc66b072819b8012ecbc24ecd0bc2
BLAKE2b-256 9e91fd0871cac2665be0a0fdb7c031f83df815bfd7e4b97133e87756c5ecf323

See more details on using hashes here.

Provenance

The following attestation bundles were made for acumatica_cli-0.3.0-py3-none-any.whl:

Publisher: release.yml on kborovik/acumatica-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page