This release is a pre-release and may not be stable for production use.
Your own agent world — built on the Python ecosystem.
Aelix is a small core. The plugins and extensions are the ecosystem, and an extension is just a Python function — so the stack you already work in becomes the agent's toolbox. Self-hosted, auditable, and running on the model budgets you already pay for.
The agent extends itself: it authors a duckdb_query tool into my_ext.py, /reload hot-loads it without restarting, and the very next prompt runs it in-process. Idle waits are cut and the recording plays at 2×.
What Aelix is
An agent runtime and extension platform in pure Python. It ships today as a terminal coding agent — its first workload, not its boundary. Read every line it runs, keep it entirely inside your own perimeter, and extend it with plain Python functions that import your existing stack — DuckDB, an internal SDK, a warehouse client — directly, in-process.
It sends nothing about you anywhere; there is no telemetry. It does make a few requests for
itself, and they are the whole list: a once-a-day release check (interactive sessions only —
headless runs never check, and /settings → Check for updates turns it off from the
next launch), the first-use ripgrep/fd download, and the extension-catalog fetch.
--offline turns those off.
Install
Aelix installs from GitHub Releases through a checksum-verified installer. It
bootstraps uv if needed, verifies every Aelix wheel
against the release's SHA256SUMS manifest, and installs the global aelix
command pinned to the version that manifest named.
# macOS, Linux
curl -fsSL https://raw.githubusercontent.com/handochan/aelix-ai/main/install.sh | sh
# Windows — EXPERIMENTAL, and needs v0.1.0-beta.2 or newer (PowerShell 5.1+)
powershell -ExecutionPolicy Bypass -c "irm https://raw.githubusercontent.com/handochan/aelix-ai/main/install.ps1 | iex"
v0.1.0-beta.2 is the release every Windows fix landed in, and the installer
takes the newest release — so on an older one that line installs a build where
none of this works. Scope and evidence: Platform support.
Both read the same environment variables: AELIX_VERSION pins a release tag
(vX.Y.Z-beta.N), AELIX_EXTRAS picks extras (default tui; empty installs the
headless CLI, POSIX only), GITHUB_TOKEN lifts the anonymous GitHub API rate
limit. Each has to reach the shell on the far side of the pipe, which is what
makes the obvious spelling wrong on both platforms — VAR=x curl … | sh sets it
for curl alone, and from a PowerShell prompt powershell -c "$env:VAR=…" is
expanded by the outer shell before the child sees it (measured on pwsh 7.6). The
getting-started guide gives the form
that works on each. Re-run the same line to upgrade; on a PATH miss both
installers now run uv tool update-shell for you instead of printing it.
uv tool uninstall aelix removes it.
PyPI carries a placeholder until
0.1.0b2. Today all four names hold a metadata-only0.0.0a0reservation, sopip install aelixexits 0 and installs nothing runnable — noaelixcommand, andimport aelixraisesModuleNotFoundError— whileuv tool install aelix@latestdeletes an existing install. From0.1.0b2on that trap is closed: every candidate on the index is a pre-release, and pip and uv both take the newest one in that case, souv tool install 'aelix[tui]'andpipx install aelixresolve the real thing (ADR-0240). The installer above stays the recommended path — it is the only one that checks the release'sSHA256SUMS— and an install it made upgrades by re-running it, not byuv tool upgrade.
Platform support
macOS, Linux and Windows. Windows became usable in v0.1.0-beta.2 and has the
thinnest evidence of the three: CI runs the full suite on ubuntu-latest and
windows-latest under Python 3.11 and 3.12 and runs install.ps1 end to end
under both pwsh and Windows PowerShell 5.1, and on 2026-09-09 one person drove
this candidate on one Windows machine — a bash call's Korean output came back
as Korean, the model reported it was on PowerShell and used PowerShell syntax
instead of &&, and the TUI drew correctly on a Windows console. That is the
whole of it: one person, one machine, one locale, plus a green leg. No
long-running use, no second machine, no third locale, and three of this release's
Windows fixes are argued from source and CI alone.
A program that opens the Windows console directly — a git credential prompt,
Read-Host -AsSecureString, Get-Credential — can still prompt there and burn a
command's whole timeout. Nothing in this release touches that, and no test on the
leg reaches it.
Which fix is measured how, and what is still open:
getting-started → Windows and
SLICE-STATUS.md; the port is tracked in
#110.
Quick start
aelix # interactive agent (TUI)
aelix --print "what changed in this repo?" # one-shot, headless
aelix --model anthropic/claude-haiku-4-5 "summarise this repo"
aelix status # trust, extensions, TLS — starts no session
aelix docs # the guides, bundled in the wheel
Aelix needs a provider credential: set ANTHROPIC_API_KEY / OPENAI_API_KEY /
OPENROUTER_API_KEY, run /login inside the TUI (Copilot / subscription OAuth), pass
--api-key, or configure ~/.aelix/agent/models.json. See the
providers guide.
On first use of grep or find, Aelix downloads ripgrep and fd into
~/.aelix/agent/bin so both honour .gitignore. These are the only binaries fetched at
runtime, --offline skips them, and copies already on your PATH are preferred.
The @ file menu uses that same fd when it can find one, so it stops offering the
files git ignores — type the directory to reach them anyway (@target/), or turn
/settings → Gitignore in @ menu off. Without an fd it falls back to a directory
walk that applies no ignore rules. Either enumerator stops after 20 000 paths, and with
ignore rules off a big ignored build tree can eat that budget before your own
directories are reached.
Why Aelix
- 🐍 Extensions are just Python. A tool is a plain function — no plugin language, no
out-of-process bridge. The same
ExtensionAPIregisters tools, slash commands, providers, renderers, themes and your own/loginflow, and every extension hot-reloads without a restart. Even policy and guardrails are swappable built-in extensions. - 💳 Runs on the budget you already own. Anthropic, OpenAI, OpenRouter, Gemini/Vertex, Cloudflare and the GitHub Copilot seat you already sign in with. Route cheap work and hard reasoning to different models in one session. No metered credits, no new vendor.
- 🔍 Auditable and self-hosted. Fully open source, no telemetry, built for closed
networks.
--offlineturns off the requests Aelix makes for itself. Trust lives in code you can read — the answer to "why run an agent I didn't write?" - ⚙️ Scriptable and headless.
--print, line-delimited--mode json, and a--mode rpcJSONL protocol make Aelix embeddable in pipelines, CI and evaluation loops.
Extensions are just Python — query your data stack in-process
An extension is a setup(aelix) function. No plugin language, no bridge, so a tool imports
your existing stack and hands results straight back to the model:
# my_ext.py — loads with: aelix -e ./my_ext.py
from typing import Any
import duckdb # your own dependency, imported in-process
from aelix_coding_agent.extensions.api import ExtensionAPI
from aelix_agent_core.types import AgentTool
from aelix_ai.tools import ToolExecutionContext, ToolResult
from aelix_ai.messages import TextContent
async def _query(args: dict[str, Any], context: ToolExecutionContext) -> ToolResult:
# DuckDB reads Parquet/CSV/JSON in place — no load step, no copy.
rel = duckdb.sql(args["sql"]).limit(args.get("limit", 20))
return ToolResult(content=[TextContent(text=str(rel))])
def setup(aelix: ExtensionAPI) -> None:
aelix.register_tool(AgentTool(
name="duckdb_query",
description="Run DuckDB SQL straight against Parquet/CSV/JSON files. No load step.",
parameters={
"type": "object",
"properties": {
"sql": {"type": "string", "description": "SELECT … FROM 'data/*.parquet'"},
"limit": {"type": "integer", "description": "Max rows returned (default 20)."},
},
"required": ["sql"],
},
execute=_query,
))
Embed it anywhere Python runs — a notebook, an Airflow/Prefect/Dagster task, a CI job:
aelix --print "which channels in data/orders.parquet have missing churn scores?"
aelix --mode json "run the eval suite and summarise failures" # line-delimited events
See writing an extension for the full surface, and the Aelix Marketplace — the catalog Aelix reads by default. It ships empty for the beta and is open for submissions.
Providers
Adapters are hand-written and keyed by wire protocol, not by vendor — no litellm, no
generic wrapper layer — so provider-specific behaviour (Anthropic thinking-block replay,
per-model /responses vs /chat/completions routing, Copilot enterprise host resolution)
is preserved rather than flattened. Six adapters exist, and catalog providers ride them:
OpenRouter and Cloudflare Workers AI both run on openai-completions, while every bundled
OpenAI model runs on openai-responses.
| Provider | Runs on | Status |
|---|---|---|
| Anthropic | anthropic-messages |
✅ supported |
| OpenRouter | openai-completions |
✅ supported |
| GitHub Copilot (individual / Business) | mixed | ✅ supported |
| OpenAI | openai-responses |
🧪 experimental |
| GitHub Copilot (Enterprise) | mixed | 🧪 not live-tested |
| Google Gemini / Vertex | google-* |
🧪 experimental |
| Cloudflare Workers AI | openai-completions |
🧪 experimental |
Every bundled OpenAI model routes through openai-responses, so choosing one puts you on the
experimental row; the openai-completions adapter's real traffic is OpenRouter, Cloudflare and
other OpenAI-compatible hosts.
Copilot Enterprise is implemented and unit-tested — host resolution, domain prompting, persistence — but has never been exercised against a live Enterprise seat.
Three catalogued providers have no adapter in this build (amazon-bedrock,
azure-openai-responses, mistral). The /model picker hides them and dispatch refuses them
with a message naming the protocols it does support — but --list-models will still print them
if you set their API key. See the providers guide.
Trust and self-hosting
Built for closed networks and customer-site deployment. --offline turns off the outbound
calls Aelix makes for itself — the rg/fd download, the catalog fetch, index-less extension
installs, the update check — but not the provider you configured, so a closed network still
needs a reachable or self-hosted model endpoint. Two gaps worth knowing: --offline before an
extension subcommand is not seen (pass it after), and a git+https:// install target
proceeds regardless. Policy and guardrails run as built-in
extensions, so every tool call and context mutation is an auditable hook event.
Built extension artifacts carry a signed supply chain that survives an air-gapped install —
aelix extension keygen | sign | trust add, and install --require-signature is fail-closed.
It covers artifacts installed by path or from an index; a git+ target and an editable
directory are refused under that flag rather than verified. It is also not on by
default: no first-party keys are provisioned yet, so without the flag a missing signature is
accepted on first use.
One input is deliberately not gated: an AGENTS.md found between your working directory
and the filesystem root is read into the system prompt whether or not you trusted the project,
and its text then goes to your configured provider. --no-context-files turns that off. See
SECURITY.md and the project trust guide.
Known limitations (beta)
Six things worth knowing before you point Aelix at something that matters.
A run has no spend ceiling. No iteration cap, no duplicate-call detection, no
cumulative token or cost budget — a model that keeps calling tools keeps costing
money until it finishes or you stop it. Esc, the 600 s bash default timeout
(an explicit per-call value is honoured up to an hour) and automatic compaction are
real backstops; none of them bounds spend
(#14,
#6,
#52).
Headless mode auto-approves mutating tools, and the two safety nets only see
built-in ones. --print, --mode json and --mode rpc have no terminal for an
approval dialog, so write, edit and bash run without asking; and both
backstops match a fixed list of built-in tool names, so a tool from an MCP server,
a skill or a third-party extension reaches neither GuardrailExtension nor the
--permission-mode plan block. Give a headless run a container or a checkout you
can throw away (#188).
One session, one terminal. Session JSONL is append-only and nothing locks it,
so opening the same session twice makes one terminal's work a branch that no
--resume walks — valid on disk, gone from the transcript
(#137).
Transcripts keep everything, forever, unredacted. Every prompt, tool argument
and tool result is written verbatim; there is no scrubbing pass. They are
owner-only on macOS and Linux (0600 inside 0700), and Windows has no mode-bit
equivalent for Aelix to set — either way the exposure is to whatever copies your
home directory: backups, sync clients, support bundles
(#138).
A successful bash call can silently lose the tail of its output. With the
reader thread starved across the command's exit, up to ~64 KiB can be dropped from
the end — exit_code is 0, nothing says anything went missing, and the tail is the
part the model is shown. It did not reproduce in ~3,300 ordinary rounds
(#260).
Delegation's spend is invisible to /cost, and its cleanup is not equal on every
OS. A child's tokens never enter the parent's session — read each delegation's
own footer — and a headless parent consents to spawns on its own. If Aelix itself
dies, Linux's PR_SET_PDEATHSIG and a Windows job object's kill_on_close end the
child; macOS has neither, and a grandchild that made its own session escapes the
process group that is all the containment there is
(#110).
Architecture
Three packages (a uv workspace), orchestrated by Agent and AgentHarness:
aelix-ai— provider-agnostic messages, streaming primitives, tool definitions. No loop, no hooks.aelix-agent-core— the agent loop,Agent,AgentHarness, and the typedHookBus. No extension deps.aelix-coding-agent—ExtensionAPI, extension loader, built-inPolicyExtension/GuardrailExtension.
Small kernel, broad extension surface; policy and guardrails as built-in extensions rather
than core; an explicit hook bus for auditability. Full rationale in docs/.
Docs
Getting started · Providers & models · Custom models · Agent profiles · Writing an extension · Project trust · Private catalog · Releasing
Every guide except RELEASING.md ships inside the wheel, so an installed machine reads them
with no network and no checkout — aelix docs, aelix docs project-trust,
aelix docs --search register_tool.
Homepage → · Extension catalog →
Building from source
uv sync # create .venv and install all workspace packages
uv run pytest # run the test suite
uv run aelix --help # the real CLI
Copy .env.example to .env for live-provider credentials. A .env is admitted for provider
credentials and a short list of provider-configuration names, and nothing else — it is read
before Aelix knows whether it trusts the directory. That admission list is narrow but it is not
nothing: a cloned repo's .env can supply the API key your session then runs on, so the
prompts go to the attacker's account. What it cannot do is execute a program, relocate the
credentials store, widen its own gate, or move a provider off its real host
(ADR-0203). CA bundles, SDK knobs and base
URLs belong in your shell.
License & attribution
Apache-2.0, with an explicit patent grant. The name and logo are separate from
the code licence, and TRADEMARK.md grants more than Apache-2.0 §6 does:
describing your work as built on, compatible with, or an extension of Aelix needs no
permission, and neither does naming your package aelix-<something>.
Substantial portions of Aelix are a TypeScript-to-Python port of
pi (reference commit 734e08e), Copyright © 2025
Mario Zechner, MIT licensed. The bundled model catalog derives
from models.dev (MIT). Full third-party licence texts ship in every
wheel and sdist (NOTICE, THIRD-PARTY-NOTICES.md); the
dependency inventory is a CycloneDX SBOM under sbom/.
Anthropic, OpenAI, Google Gemini, GitHub Copilot, OpenRouter and Cloudflare are trademarks of their respective owners; Aelix is an independent project, and names are used only to identify the services it can connect to.
Release files for aelix 0.1.0b2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| aelix-0.1.0b2.tar.gz | 5.5 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aelix-0.1.0b2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 5.5 MB
Release files / aelix-0.1.0b2.tar.gz
| Download URL | aelix-0.1.0b2.tar.gz |
|---|---|
| Size | 5.5 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
28a3e22e3f654fcd4cdf32fe609504b9d831b38b6feb321d0e2cfa29ddfbf487
|
|
BLAKE2b-256 checksum How to use checksums |
35931f9ddf156e59d4819d0ff311a7feb55e784cd1d705b6807e1fb304fa822a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 9, 2026.
Transparency logRelease files / aelix-0.1.0b2-py3-none-any.whl
| Download URL | aelix-0.1.0b2-py3-none-any.whl |
|---|---|
| Size | 21.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
98a9201be2c84c96a1e3944bd003ba7b7346e6e0807dfbfaae3a00ef8e4994b7
|
|
BLAKE2b-256 checksum How to use checksums |
f605fabe2a1aa29c1e798eb55bd5aa913a85f0b993d622cc6926600608e68e1c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 9, 2026.
Transparency log