Open Source · v0.1.0

The language for
auditable AI agents

ACL is a declarative language for AI agent workflows. Every run produces a receipt — what was called, what was returned, and whether the rules passed.

Quickstart (5 min) Try Agentic Flow Lab Open Playground GitHub
$ go install github.com/ranausmanai/acl/cmd/acl@latest
expense_splitter.acl
AGENT SplitExpense
  IN  receipt_url
  OUT split
  TOOLS vision.describe, llm.generate

  # Read the receipt image
  STEP scan = TOOL vision.describe(url=receipt_url, prompt="List every item and price")

  # Calculate fair split
  STEP calc = TOOL llm.generate(prompt="Split these items fairly: {scan.description}")
    MUST calc.text CONTAINS "$"   # enforce output format

END

Demo flows (what ACL feels like)

These are the kinds of request → action → receipt flows you can show publicly. The point is not just chat. The point is safe actions with proof.

Split bill (Splitwise-style)

Consumer
User says
Dinner with Sarah - 20 USD each

Great demo because it is relatable and ambiguous. The assistant should ask who paid before writing anything.

1Parse intent: split expense, participants, amount-per-person, currency.
2Ask follow-up: who paid the full bill?
3Create split expense only after confirmation.
4Return summary + receipt of tool calls and checks.
ACL value: APIs can create the expense, but ACL makes sure the AI asks the missing question before doing the write.

Refund order + email customer

Ops / Support
Agent-assist request
Refund order #10482 and email the customer

This shows where ACL is strongest: risky write actions across systems with approval and a receipt.

1Fetch order + customer context.
2Validate refund eligibility (window, status, amount).
3Draft customer email and ask for approval.
4Execute refund, send email, log receipt.
ACL value: approval gates + MUST/CHECK + receipts make AI actions safe enough for production support workflows.

Calendar move + notify

Everyday
User says
Move tomorrow's 3pm with Sarah to next week and send a note

Simple language, multi-app action. Very visual in a screen recording.

1Resolve the event and proposed new time/date.
2Update calendar event.
3Send or draft the notification message.
4Return confirmation + receipt.
ACL value: one natural-language request can safely coordinate multiple APIs while keeping a clear action log.

Scheduled monitor + summary

Automation
ACL can run on a schedule
SCHEDULE PriceMonitor "*/3 * * * *"

Shows ACL is not only for chat. It can also run in the background and save receipts/history.

1Fetch data from API(s).
2Compare with previous snapshot (memory/file/db).
3Generate short summary for humans.
4Persist output + receipt for downstream systems.
ACL value: the same language handles chat-triggered actions and background automations with the same safety/receipt model.

Make Your App Agent-Ready

You do not need to rebuild your app as a chatbot. Expose machine-usable capabilities (API, MCP, Zapier, CLI), then use ACL to define how an agent may use them safely.

1. Expose Capabilities

Wrap existing app actions as tools (API wrappers, MCP adapters, Zapier webhooks, or CLI commands). ACL does not replace your app API.

2. Add Safety Rules

Use ACL to define allowed tools, checks, retries/fallbacks, and MUST gates so agent actions do not become ad hoc prompt glue.

3. Preview Before Writes

For risky actions (orders, refunds, money movement), preview first, ask for confirmation, then execute. The same contract can support both steps.

4. Keep Receipts

Every run emits a receipt so support, engineers, and users can inspect what happened. ACL is for safe AI actions, not opaque automation.

agent_ready_flow.acl
# App capability (via API / Zapier / MCP) exposed as a tool:
#   zapier.invoke(action="calendar.create_event", ...)

AGENT ScheduleEventPreview
  OUT answer
  TOOLS zapier.invoke, llm.generate

  STEP preview = TOOL zapier.invoke(
    action="calendar.create_event",
    mode="preview",
    approved=false,
    title="Lunch with Ali",
    starts_at="2026-02-23T13:00:00")
  MUST preview.status == "preview"

  STEP answer = TOOL llm.generate(
    prompt="Using {preview.preview}, confirm what will happen and ask for approval.")
  MUST has(answer, "text")
  RESULT answer

Language overview

ACL files define agents. Each agent has steps that call tools. Results flow between steps via string interpolation.

AGENT & STEP

Declare inputs, outputs, and a sequence of tool calls. Each step names its result for later reference.

MUST & CHECK

Evidence gating. MUST halts on failure. CHECK records the result but continues. Both are in the receipt.

IF / FOREACH

Real control flow. Branch on conditions, iterate over lists. Not just a linear pipeline.

{step.field}

String interpolation. Reference any previous step's output inside arguments. Nested fields work too.

price_alert.acl
AGENT PriceAlert
  IN  ticker
  OUT action

  STEP price = TOOL http.get(url="https://api.example.com/price/{ticker}")
    MUST price.status == 200

  IF price.json.usd > 100000
    STEP notify = TOOL email.draft(to="team@co.com", subject="{ticker} above $100k")
  ELSE
    STEP log = TOOL llm.generate(prompt="Summarize {ticker} at ${price.json.usd}")
  END

END
foreach.acl
AGENT BatchTranslator
  IN  languages
  OUT translations

  STEP langs = TOOL json.parse(text=languages)

  FOREACH lang IN langs.data
    STEP t = TOOL llm.generate(
      prompt="Translate 'hello' to {lang}")
  END

END
react_agent.acl
AGENT Researcher
  IN  question
  OUT answer

  STEP r = TOOL react.run(
    goal=question,
    tools="search.web,browser.fetch",
    max_steps="5")
    MUST r.answer != ""

END

Language reference

Keywords

KeywordPurpose
AGENT ... ENDDefine an agent with steps
IN / OUTDeclare input and output variables
TOOLSRestrict which tools the agent may use
STEP name = TOOL fn(args)Call a tool, store result as name
MUST exprHard assertion — agent fails if false
CHECK exprSoft check — recorded, execution continues
IF / ELSE / ENDConditional execution
FOREACH var IN expr ... ENDIterate over a list
TEMPLATE name(params)Reusable agent fragment
ALLOW / LIMITGlobal policy: tool allowlist, time/call/retry limits
SCHEDULECron-based automatic execution
REMOTEDelegate to an agent on another server

Expressions

Used in MUST, CHECK, and IF:

==, !=Equality
>, <, >=, <=Numeric comparison
CONTAINSString/substring match

Field access: step.field, step.nested.field, step.array[0]

Interpolation

STEP a = TOOL llm.generate(prompt="What is AI?")
STEP b = TOOL llm.generate(prompt="Translate to French: {a.text}")

Serving as API

$ acl serve agents.acl --port 8080

$ curl -X POST localhost:8080/run/SplitExpense \
    -d '{"vars": {"receipt_url": "https://..."}}'

Response is the full receipt. Set ACL_SERVE_API_KEY for auth.


Built-in tools

No plugins needed. Ships with the binary.

ToolReturns
llm.generatetext, model, tokens, provider
vision.describedescription, model, provider
audio.transcribetext, language, duration_s
search.webhits[{title,url,snippet}], count
browser.fetchurl, title, text, word_count
http.get / http.requeststatus, text, json, url
react.runanswer, steps_taken, log
json.parse / json.stringifydata / text
csv.parse / csv.writerows, columns / text
sql.queryrows, count
file.read / file.writetext, path / path, written
memory.set / memory.getkey, stored_at / key, value
memory.messagessession, messages, count
vector.upsert / vector.searchid, dimensions / results, count
code.runstdout, stderr, exit_code
pdf.render / email.draftpath / message_id

Getting started

Install

go install github.com/ranausmanai/acl/cmd/acl@latest

Run

acl run myagent.acl
acl run myagent.acl --var name="World"

Serve

acl serve agents.acl --port 8080

LLM providers

Set one environment variable. ACL auto-detects:

ANTHROPIC_API_KEYClaude (claude-sonnet-4-6)
OPENAI_API_KEYGPT-4o
GROQ_API_KEYLlama 3.3 70B
MISTRAL_API_KEYMistral Large
OLLAMA_HOSTLocal Ollama

Configuration

ACL_DB_URLDatabase for sql.query
ACL_CODE_RUN_ENABLED=1Enable code.run
ACL_SERVE_API_KEYBearer token for serve
ACL_FILE_DIRSandbox for file tools
BRAVE_API_KEYBrave Search
SERPER_API_KEYGoogle Search