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.mdfor a focused language guideSPEC.mdfor 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.stdoutanditems[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
standardonly allowslsinsystem.rundevallowspython,node, andlsfor local iterationrm,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 usestrict— disables network access and file deletion, and reduces allowed system commandsdev— 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b71491c3a14f738a9becab5dc5871665b0aebefb6a7e7f8c87898bff7d947f32
|
|
| MD5 |
01ed2ababac98b5746c5cdf5f091be1f
|
|
| BLAKE2b-256 |
77e811c6648563f007ec054e9dbe6f3a89d9e98d38b6b30df78f3f1c4cdac6b7
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c976e0e5a24d53f0bd314a4f8498e7e36a23888f3906eccfd1224d65393d579f
|
|
| MD5 |
2c5718bd4526601056238208d42f3372
|
|
| BLAKE2b-256 |
adaa8a67ea88c40bb241b714212d2cb1e9dde335535737eeec12f2b92c919fc6
|