Skip to content

pvnjdv/acl-engine

Repository files navigation

ACL Engine

PyPI version Python 3.10+

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.

About

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

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages