Skip to main content

A compact AI Command Language engine for safe LLM tool workflows

Project description

ACL Engine

ACL Engine is a lightweight Python execution engine for AI-generated action scripts.

It parses a compact ACL syntax, validates each command, applies safety checks, executes allowed actions in order, and returns structured JSON output.

The repository also includes syntax.md, SPEC.md, and runnable ACL samples in examples/.

Installation

pip install acl-engine

PyPI installs include the Python package and the acl CLI.

If you are working from a repository checkout or source distribution, you also get:

  • syntax.md for a focused language guide
  • SPEC.md for the formal execution contract
  • runnable ACL examples in examples/

For local development:

pip install -e ".[dev]"

What It Does

ACL Engine supports:

  • multi-line ACL scripts
  • metadata like @reason="debug"
  • variable assignment with -> name
  • structured object and list values
  • field and index selectors like result.stdout and items[0]
  • sequential multi-step workflows
  • safe built-in actions for files, system commands, network requests, memory, utility helpers, and data transformation
  • JSON-light API and file workflows so models do not have to handcraft raw JSON for common integrations
  • custom action registration from Python
  • structured JSON results for both Python and CLI usage
  • policy-driven execution modes for safer deployments

ACL intentionally does not support loops, conditionals, or nested control flow.

Example ACL

@reason="basic variable workflow"
util.echo(value="Hello from ACL Engine") -> greeting
memory.store(key="message", value=greeting)
memory.get(key="message") -> result

Structured values and selectors are supported:

util.echo(value={message="hello", items=["a", "b"]}) -> payload
util.echo(value=payload.message) -> msg
util.echo(value=payload.items[1]) -> second

Integration-oriented workflows are supported without dropping into Python:

net.request(method="GET", url="https://example.com/api/user") -> response
data.select(value=response.json, path="user.id") -> user_id
data.template(template="user-{id}", values={id=user_id}) -> label

Structured JSON files are also first-class, so ACL can move data between APIs and files without manual serialization steps:

data.pick(value=response.json, keys=["user", "meta"]) -> payload
file.write_json(path="cache/user.json", value=payload)
file.read_json(path="cache/user.json") -> stored

Python Usage

from acl_engine import execute_acl

result = execute_acl(
      '''
      util.echo(value="hello") -> msg
      util.echo(value=msg) -> copy
      '''
)

print(result)

You can also create a reusable engine instance:

from acl_engine import ACLEngine

engine = ACLEngine(workspace="./workspace", timeout=30)
result = engine.execute('file.read(path="main.py") -> code')

Running .acl Files

Run an .acl file from the CLI:

acl --workspace ./workspace run path/to/workflow.acl

If you want to invoke the CLI through Python directly:

python -m cli.main --workspace ./workspace run path/to/workflow.acl

Run an .acl file from Python code:

from pathlib import Path

from acl_engine import ACLEngine

engine = ACLEngine(workspace="./workspace", timeout=30)
acl_text = Path("path/to/workflow.acl").read_text(encoding="utf-8")
result = engine.execute(acl_text)

print(result)

For quick experiments without a file, you can still run inline ACL:

acl --workspace ./workspace exec 'util.echo(value="hello") -> msg'

Custom Actions

from acl_engine import ACLEngine

engine = ACLEngine()

def db_query(sql: str):
      return {"sql": sql, "rows": []}

engine.register_action(
   "db.query",
   db_query,
   {"sql": {"type": str, "min_length": 1}},
   capabilities={"data"},
   description="Run a SQL query",
   returns="object",
)

result = engine.execute('db.query(sql="SELECT 1") -> output')

CLI Usage

If you are using a repository checkout or source distribution, there are runnable ACL samples in examples/ for common tool-oriented workflows.

If you installed only the wheel from PyPI, use the inline CLI examples below or copy the ACL snippets from the repository documentation.

Run an ACL file:

acl --workspace ./workspace run examples/basic.acl
acl --workspace ./workspace run examples/file_roundtrip.acl
acl --workspace ./workspace run examples/json_pipeline.acl

Run with a stricter policy:

acl --workspace ./workspace --policy strict run examples/basic.acl

Run inline ACL:

acl --workspace ./workspace exec 'util.echo(value="hello") -> msg'

Validate ACL without executing it:

acl validate --inline 'util.echo(value="hello") -> msg'

Inspect the execution plan:

acl dry-run --inline 'util.echo(value={message="hello"}) -> payload'

List available actions and their schemas:

acl actions

Filter available actions for integration discovery:

acl actions --namespace data
acl actions --capability filesystem

Load custom actions from one or more plugin files:

acl --plugin ./plugins/example.py actions

Continue after an error instead of stopping on the first failed step:

acl --continue-on-error exec 'util.echo(value="ok") -> a
system.run(command="python", args=["-c", "print(1)"])
util.echo(value="still-runs") -> b'

Restrict execution to specific capability groups:

acl --allow-capability utility --allow-capability memory exec 'util.echo(value="hello") -> msg'

Allow only specific network domains:

acl --allow-domain example.com exec 'net.request(method="GET", url="https://example.com") -> response'

Use the dev policy only for trusted local workflows that need interpreter-backed process execution:

acl --workspace ./workspace run examples/system_ls.acl
acl --workspace ./workspace --policy dev run examples/dev_python_probe.acl

CLI output is JSON:

{
   "acl_version": "1.0",
   "output_version": "1.2",
   "trace_id": "...",
   "status": "success",
   "data": {
      "msg": "hello"
   },
   "logs": [
      {
         "step": 1,
         "line": 1,
         "action": "util.echo",
         "raw_params": {
            "value": "hello"
         },
         "resolved_params": {
            "value": "hello"
         },
         "status": "success",
         "duration_ms": 0,
         "meta": {},
         "result": "hello"
      }
   ],
   "summary": {
      "policy": "standard",
      "steps_total": 1,
      "steps_completed": 1,
      "steps_failed": 0,
      "duration_ms": 0
   },
   "error": null
}

Safety Rules

ACL Engine applies a small, strict safety model:

  • file operations are restricted to the configured workspace root
  • path traversal outside the workspace is blocked
  • standard only allows ls in system.run
  • dev allows python, node, and ls for local iteration
  • rm, sudo, &&, and ; are blocked
  • subprocess execution uses shell=False
  • subprocess calls respect the configured timeout

standard is the recommended profile for AI-facing or hosted usage.

dev and custom plugins should be treated as trusted local-development features, not as a security sandbox for untrusted scripts.

Execution policy profiles are available:

  • standard — safer default profile for deployed or AI-facing use
  • strict — disables network access and file deletion, and reduces allowed system commands
  • dev — relaxed local profile that enables interpreter-driven tooling

Safety checks run after variable resolution so indirection cannot bypass restrictions.

Built-in Actions

  • file.read(path)
  • file.read_json(path)
  • file.write(path, content)
  • file.write_json(path, value, indent=2, sort_keys=false)
  • file.append(path, content)
  • file.list(path)
  • file.delete(path)
  • file.exists(path)
  • file.stat(path)
  • file.mkdir(path)
  • file.copy(source, destination, overwrite=false)
  • file.move(source, destination, overwrite=false)
  • file.glob(path=".", pattern="*")
  • system.run(command, args=[], cwd=None)
  • net.request(method, url, headers=None, query=None, body=None, json_body=None)
  • memory.store(key, value)
  • memory.get(key)
  • memory.delete(key)
  • memory.list()
  • memory.clear()
  • data.from_json(value)
  • data.to_json(value, indent=2, sort_keys=false)
  • data.merge(left, right, deep=false)
  • data.template(template, values)
  • data.select(value, path)
  • data.pick(value, keys)
  • data.omit(value, keys)
  • util.echo(value)
  • util.sleep(seconds)
  • util.now()
  • util.uuid()
  • util.hash(value, algorithm="sha256")
  • util.base64_encode(value)
  • util.base64_decode(value)

Project Layout

acl_engine/
   __init__.py
   engine.py
   parser.py
   validator.py
   executor.py
   context.py
   resolver.py
   actions/
      data.py
      file.py
      system.py
      net.py
      memory.py
      util.py
      registry.py
cli/
   main.py
examples/
   basic.acl
tests/

Running Tests

pytest

Status

The project is intentionally small and focused. The current goal is a reliable Python package and CLI, not a general-purpose workflow language.

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

acl_engine-0.1.0.tar.gz (47.0 kB view details)

Uploaded Source

Built Distribution

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

acl_engine-0.1.0-py3-none-any.whl (30.6 kB view details)

Uploaded Python 3

File details

Details for the file acl_engine-0.1.0.tar.gz.

File metadata

  • Download URL: acl_engine-0.1.0.tar.gz
  • Upload date:
  • Size: 47.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for acl_engine-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b71491c3a14f738a9becab5dc5871665b0aebefb6a7e7f8c87898bff7d947f32
MD5 01ed2ababac98b5746c5cdf5f091be1f
BLAKE2b-256 77e811c6648563f007ec054e9dbe6f3a89d9e98d38b6b30df78f3f1c4cdac6b7

See more details on using hashes here.

File details

Details for the file acl_engine-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: acl_engine-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 30.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for acl_engine-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c976e0e5a24d53f0bd314a4f8498e7e36a23888f3906eccfd1224d65393d579f
MD5 2c5718bd4526601056238208d42f3372
BLAKE2b-256 adaa8a67ea88c40bb241b714212d2cb1e9dde335535737eeec12f2b92c919fc6

See more details on using hashes here.

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