Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Kinetic DevOps

Status: ⚠️ ALPHA — Early development. API and features may change significantly.

Kinetic DevOps is a Python SDK and automation framework designed to bring modern DevOps practices to the Epicor Kinetic ecosystem. It provides a secure, extensible, and consistent foundation for environment management, CI/CD pipelines, and complex data migration workflows.

Features

  • 🔐 Secure credential management — OS keyring-backed encryption with optional Zero-Knowledge Vault mode and integrated maintenance tools (diagnose, find-orphans, full-wipe).
  • Multi-environment support — Seamlessly switch between Dev/Test/Production
  • 🛠️ Ready-to-use Service Clients — High-level clients for BAQ, BOReader, Reports, Tax, and more, built on a robust base client with wire logging and data redaction.
  • 🚀 Extensible Project Templates — A "batteries-included" project structure with auto-discovery for creating your own reusable functions, layers, and scheduled jobs.
  • 🤖 CI/CD Ready — Designed for automation with environment variable support, programmatic APIs, blocking sensitive-data gates, and pre-commit hooks for local validation.
  • 📜 Powerful CLI Tools — Includes helper scripts for environment initialization and common administrative tasks like configuration syncing. Unified test runner includes built-in health validation.
  • 🧩 Layer Lifecycle Operations — Native MetaFX support for core layer import/delete operations (ImportLayers / BulkDeleteLayers) with structured error reports.
  • ⚙️ EFx Function Library Management — Export/import/list libraries, plus per-function C# source extraction and push-back for local editing.
  • 📦 Modular architecture — Extend with custom project submodules

Quick Start

Windows PowerShell

.\scripts\env_init.ps1
uv run kinetic_devops auth store
uv run python -m tests.test_runner --validate

Linux/macOS

uv run python scripts/env_init.py
uv run python -m kinetic_devops.auth store
uv run python -m tests.test_runner --validate

Usage

from kinetic_devops.auth import KineticConfigManager
from kinetic_devops.baq import BAQClient

# Initialize authentication
config = KineticConfigManager()

# Create BAQ client (handles session, headers, requests)
baq_client = BAQClient(config)

# Execute a BAQ
results = baq_client.execute_baq(
    baq_id='CUST_List',
    args={'Company': 'ABC', 'MaxResults': 100}
)

# Process results
for customer in results['value']:
    print(f"{customer['CustomerID']}: {customer['CustomerName']}")

Local Development (.venv)

Use the repository-local virtual environment at .venv:

# From repo root
.\.venv\Scripts\activate
uv sync

Analysis Commands (Feature Slice)

The analysis router includes three workflows:

# Metadata-only functionality/regression review
uv run python -m kinetic_devops analysis no-commit-review

# Incremental snapshot + commit AI review
uv run python -m kinetic_devops analysis diff-review

# Legacy repository intake loop (analysis-only)
uv run python -m kinetic_devops analysis legacy-intake

Common environment variables:

  • KINETIC_ACTIVE_ROOT (default: D:\Kinetic_SDK)
  • KINETIC_AI_PROFILE: one AI profile for runners without a keyring, as JSON or the path to a JSON file (for example a mounted secret): {"v": 1, "base_url": "https://ai.example/v1", "api_style": "openai", "model": "my-model", "api_key": "..."} (only base_url is required). Normally profiles are stored in the keyring with uv run python -m kinetic_devops.auth ai-set, each as one entry in the same format (server, API style, model and key together). Profiles are named (ai-set --name fast, --name deep), share one key per server (setting it updates them all), and are chosen with analysis --ai-profile NAME (default: auth ai-default NAME); see auth ai-show / auth ai-clear. Order: --ai-base-url (its key and style come from a matching profile), then --ai-profile, then KINETIC_AI_PROFILE, then the default stored profile, then KINETIC_AI_BASE_URL. A malformed KINETIC_AI_PROFILE is an error, not silently ignored.
  • KINETIC_AI_BASE_URL (URL-only fallback, without key or style)
  • KINETIC_AI_TIMEOUT (default: 180)
  • KINETIC_ANALYSIS_MAX_COMMITS (default: 20)
  • KINETIC_ANALYSIS_LEGACY_OUT_DIR (default: D:\Kinetic_SDK\temp\legacy_intake_reviews)

Example:

Copy-Item scripts\ai_env.local.ps1.example scripts\ai_env.local.ps1
uv run python -m kinetic_devops analysis diff-review

MetaFX Layer DevOps Flow

# Dry-run: parse dump files and resolve layer operations without sending requests
python -m kinetic_devops meta --env <ENV> --user <USER> layers "C:/path/dump (5).json" "C:/path/dump (6).json" --dry-run

# Execute: run import/delete operations and capture status + correlation IDs in a report
python -m kinetic_devops meta --env <ENV> --user <USER> layers "C:/path/dump (5).json" "C:/path/dump (6).json" --report temp/layer_ops_report.json

Default behavior for layers is deployment mode (--ops import):

  • Executes delete operations first (when present)
  • Then executes import operations

This flow is designed to support layer deployment and rollback as part of the DevOps cycle.

ExportAllTheThings Full Export Flow

Export everything currently exposed by your ExportAllTheThings library:

# Export all discovered Export* functions and write a manifest
python -m kinetic_devops export --env <ENV> --user <USER> --library ExportAllTheThings --out-dir exports/ExportAllTheThings

# List discovered export functions only
python -m kinetic_devops export --env <ENV> --user <USER> --list

# Run one export function
python -m kinetic_devops export --env <ENV> --user <USER> --function ExportAllCustomBAQs

# Run full export across all configured companies (dedup enabled by default)
python -m kinetic_devops export --env <ENV> --user <USER> --all-companies --out-dir exports/ExportAllTheThings

The export command:

  • Discovers export-capable functions from the EFx library (FunctionID starts with Export)
  • Executes one or all exports
  • Saves each artifact file
  • Writes an export manifest JSON with per-function success/failure details

Mode behavior:

  • --mode auto (default): uses ExportAllTheThings when present, otherwise native endpoints
  • --mode eatt: requires EFx export library behavior
  • --mode native: no ExportAllTheThings dependency
  • --all-companies: runs exports once per configured company (or use --companies CO1 CO2)
  • de-duplication is enabled in --all-companies mode and records duplicate pointers in the manifest (--no-dedup disables this)

Native examples (no ExportAllTheThings required):

# Run built-in native export plan for BAQs, directives, UD codes, MetaFX app list, etc.
python -m kinetic_devops export --mode native --env <ENV> --user <USER> --out-dir exports/native

# Pull one endpoint at a time
python -m kinetic_devops export --mode native --env <ENV> --user <USER> --native-endpoint "/api/v2/odata/{company}/Ice.BO.BAQDesignerSvc/GetList" --native-method POST --native-body '{"whereClause":"SystemFlag=false","pageSize":0,"absolutePage":0}' --native-name baq_list_single

# Run native export plan across all configured companies
python -m kinetic_devops export --mode native --env <ENV> --user <USER> --all-companies --out-dir exports/native

Solution Workbench Backup And Recreate

Solution migration is a different workflow from package build/install.

  • BuildSolution and InstallSolution operate on a built package artifact
  • GetByID, GetNewExportPackage, and Update operate on the solution definition dataset
  • Recreating the solution in the target environment lets you build it there later

Typical operational sequence:

  • create in Kinetic UI (author/edit your solution)
  • backup in DevOps
  • build in DevOps (when you need a package artifact)
  • install in DevOps (when promoting by package)
  • recreate in DevOps (when migrating editable solution definition state)

You can use package promotion (build + install) and definition migration (recreate) independently or together.

Examples:

# Back up a solution definition and its tracked-item snapshots
python -m kinetic_devops solutions --env <SOURCE_ENV> --user <USER> backup MySolution --out-dir exports/solutions

# Recreate that solution definition in a target environment
python -m kinetic_devops solutions --env <TARGET_ENV> --user <USER> recreate exports/solutions/solution_backup_MySolution_20260331T000000Z.json

# Recreate under a new Solution ID, replacing an existing target solution if needed
python -m kinetic_devops solutions --env <TARGET_ENV> --user <USER> recreate exports/solutions/solution_backup_MySolution_20260331T000000Z.json --target-solution-id MySolution_Copy --overwrite

# Build a CAB package from a solution on the server
python -m kinetic_devops solutions --env <ENV> --user <USER> build MySolution

# Install a CAB package
python -m kinetic_devops solutions --env <ENV> --user <USER> install temp/MySolution.cab

# Install with automatic tenant-layer conflict cleanup and one retry
uv run kinetic-devops solutions --env <ENV> --user <USER> install temp/MySolution.cab --overwrite-duplicate-file --overwrite-duplicate-data --override-directives --auto-clear-layer-conflicts

Current recreate behavior is intentionally focused on the Solution Workbench definition:

  • solution header and package rows
  • solution detail membership rows
  • backup capture of per-table dynamic/tracked snapshots for later analysis

recreate does not implicitly call build or install; those are explicit steps.

EFx Function Library Management

Export/import/list EFx Function Libraries (Ice.Lib.EfxLibraryDesignerSvc), and pull/push individual functions' C# source for local editing:

# List visible libraries
python -m kinetic_devops.efx_library --env <ENV> --user <USER> list

# Export a single library, or every visible library (one file per library)
python -m kinetic_devops.efx_library --env <ENV> --user <USER> export <LibraryID> --out backup.efxlib
python -m kinetic_devops.efx_library --env <ENV> --user <USER> export-all --out-dir backups/

# Import a previously exported library
python -m kinetic_devops.efx_library --env <ENV> --user <USER> import backup.efxlib --new-library-id CopyOfLib

# Pull a library's functions as editable .cs files, edit one, push it back
python -m kinetic_devops.efx_library --env <ENV> --user <USER> pull-source <LibraryID> --out-dir projects/libraries
python -m kinetic_devops.efx_library --env <ENV> --user <USER> push-source <LibraryID> <FunctionID> --out-dir projects/libraries

# Actually execute a saved function -- only in the environment named by --allow-env (default: Epicor's Pilot tier), interactive confirmation required, never unattended
python -m kinetic_devops.efx_library --env <env> --user <USER> test-pilot <LibraryID> <FunctionID> --allow-env <env>

pull-source extracts each function's embedded C# (CustomCodeAction.Code fragments inside the function's directive graph) into one .cs file per code node, plus a _body.xml sidecar and a _meta.json. push-source re-injects edited .cs files back into a freshly-fetched copy of the function (not the local sidecar, to avoid clobbering concurrent changes) via ApplyChangesWithDiagnostics, and raises if the server reports any diagnostics.

tools/efx_syntax_check is a Roslyn-based syntax-only validator for extracted .cs fragments (no semantic/type checking -- Epicor's runtime types aren't available outside the server).

Note: pulled function source (actual customer business logic) is intentionally kept out of this repo -- projects/ is gitignored. Store pulled libraries in a separate, dedicated location.

See examples/complete_flow.py for a complete auth → BAQ → results example.

Documentation

Versioning

Until 1.0.0, versions are PEP 440 0.BREAKING.FEATURES.FIXES plus a stage and sequence number (a8 = the 8th alpha release); checked by tests/test_versioning.py:

The release contains (its CHANGELOG.md section) Next version Example
a breaking change (Breaking) BREAKING + 1, FEATURES and FIXES 0 0.2.1.3a12 -> 0.3.0.0a13
new or changed behaviour, nothing breaking (Added / Changed) FEATURES + 1, FIXES 0 0.2.0.0a8 -> 0.2.1.0a9
fixes only (Fixed / Security / Dependencies) FIXES + 1 0.2.1.0a9 -> 0.2.1.1a10
  • The sequence number goes up by exactly 1 with every release, whatever else changes, so it is the release's place in the line: a8 follows a7. The stage moves forward only, alpha (a) -> beta (b) -> release candidate (rc), and the number restarts at 1 when it does (b1).
  • Breaking changes we know of always bump BREAKING, so pin to two numbers after the 0: kinetic-devops~=0.2.0a8 gets new features and fixes without them (it means >=0.2.0.0a8, <0.3). Pinning all four numbers (kinetic-devops~=0.2.0.0a8) gets fixes only. Alpha still means any release may change behaviour.
  • Every release before 1.0.0 is a pre-release: install with a version pin or --pre.
  • From 1.0.0 on, versions are Semantic Versioning MAJOR.MINOR.PATCH.
  • 0.1.0a1-a7 were published before this rule; their alpha numbers carry on (a8).

Known Limitations

  • Alpha stage — Breaking changes may occur between versions
  • Redaction edge cases — Heuristic-based sensitive data masking has known gaps
  • Windows-first — Tested primarily on Windows; Linux/macOS support improving

Project Structure

kinetic-devops/           # Core library (published)
├── src/kinetic_devops/   # Main package (src layout)
├── scripts/              # Helper scripts
├── tests/                # Test suite
└── projects/             # (Optional) User project submodules

Users extend this core by adding private Git submodules for their custom implementations.

Requirements

  • Python 3.11+ (every CPython version that still gets security fixes; see Supported Python versions)
  • keyring — Secure credential storage
  • requests — HTTP client

Supported Python versions

Kinetic-DevOps supports exactly the CPython versions that still receive security fixes upstream (see https://devguide.python.org/versions/). When a version reaches end of life, the next release drops it: requires-python, the classifiers and the CI matrix move up together, and the changelog says so. Older releases stay on PyPI for anyone who can't upgrade yet. Currently: 3.11, 3.12, 3.13 and 3.14.

Installation

Using uv (recommended):

uv pip install kinetic-devops

Or with pip:

pip install kinetic-devops

From source with uv:

git clone https://github.com/<owner>/kinetic-devops.git
cd kinetic-devops
uv run kinetic-devops

License

See LICENSE file.

Metadata

Release files for kinetic-devops 0.2.0.0a8

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for kinetic-devops 0.2.0.0a8
File Size Uploaded Provenance Actions
kinetic_devops-0.2.0.0a8.tar.gz 243.9 kB With provenance Details for kinetic_devops-0.2.0.0a8.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for kinetic-devops 0.2.0.0a8
File Interpreter ABI Platform Actions
kinetic_devops-0.2.0.0a8-py3-none-any.whl Python 3 none any Details for kinetic_devops-0.2.0.0a8-py3-none-any.whl

Total release size: 449.4 kB

Release files / kinetic_devops-0.2.0.0a8.tar.gz

Download URL kinetic_devops-0.2.0.0a8.tar.gz
Size 243.9 kB
Tags Source
SHA-256 checksum
How to use checksums
688efbac2151ef63f54783806b2d6038478953cd50b2bce0f37a945d1a0a37d2
BLAKE2b-256 checksum
How to use checksums
57a3bf164a029d9bbfe282de3da55d6f09072e5045d053873c7f33a2fe3017c1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

Release files / kinetic_devops-0.2.0.0a8-py3-none-any.whl

Download URL kinetic_devops-0.2.0.0a8-py3-none-any.whl
Size 205.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c550448a94a61bd66874dae2fb10bf4641b2f5c16ec1594171991a7642549b64
BLAKE2b-256 checksum
How to use checksums
21bd7ebb649cd83d913b3b6e43bf51fa4384047a74e1735f371f3ab54fbfdf11
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

Security for kinetic-devops 0.2.0.0a8

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for kinetic_devops-0.2.0.0a8.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page