▓█████ ██╗ ██╗ ██████ ██████ ████████╗
▓█ ▀ ╚██╗██╝ ██╔═══██╗██╔══██╗╚══██╔══╝
██████╗ ╚███╝ ██║ ██║██████╔╝ ██║
▓█ ▀ ██╔██╗ ██║ ██║██╔══██╗ ██║
██████╗ ██╔╝ ██╗ ╚██████╔╝██║ ██║ ██║
╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
🌐 Website: askexort.github.io/exort-website
An autonomous AI agent that reasons, acts, and learns through direct tool interaction. Runs on free-tier APIs or fully offline — no credit card, no gatekeepers.
Getting Started · What It Does · Architecture · Providers · Telegram Bot · Python API · Contributing
Most AI agent frameworks are built for enterprises with big budgets. Exort is built for everyone:
- $0 to start — works with Groq's free API (no credit card needed)
- Runs offline — use Ollama and your data never leaves your machine
- Real capabilities — search the web, run code, manage files, not just chat
- Own your data — conversations stored locally in SQLite, not on someone's cloud
- Hackable — clean Python, no magic, easy to extend
git clone https://github.com/askexort/exort.git
cd exort
pip install -e .Option A: Groq (free, fast — best for starting out)
# 1. Get a free key at https://console.groq.com (no credit card)
# 2. Save it:
mkdir -p ~/.exort
echo "GROQ_API_KEY=gsk_your_key_here" > ~/.exort/.envOption B: Ollama (100% local, 100% free)
# 1. Install Ollama: https://ollama.ai
# 2. Pull a model:
ollama pull llama3.1
# No API key needed.Option C: OpenAI / Anthropic (paid, higher quality)
echo "OPENAI_API_KEY=sk-..." > ~/.exort/.env
# or
echo "ANTHROPIC_API_KEY=sk-ant-..." > ~/.exort/.envexort shell # interactive terminal
exort ask "hello" # one-shot question
exort bot # telegram botThat's it. You now have an AI agent with real-world capabilities.
Exort is not a chatbot. It's an agent — it reasons about your request, decides what tools to use, executes them, reads the results, and iterates until it has a real answer.
You: "What are the top 3 Python web frameworks and their GitHub stars?"
Exort thinks → calls web_search("Python web frameworks 2025")
↓ reads results
Exort thinks → calls fetch_url("https://github.com/pallets/flask")
↓ reads page
Exort thinks → calls fetch_url("https://github.com/django/django")
↓ reads page
Exort responds with a ranked comparison table
| Gear | What It Does |
|---|---|
web_search |
Search the internet (DuckDuckGo, no API key) |
fetch_url |
Read any web page's content |
read_file |
View files with line numbers |
write_file |
Create or overwrite files |
list_directory |
Browse folders |
search_files |
Find files or search inside them |
run_shell |
Execute system commands |
exec_python |
Run Python code |
load_image |
Prepare images for vision analysis |
All gear is opt-in by the engine — it only calls tools when they're useful.
exort/
├── engine.py ← The reasoning core (perceive → reason → act → reflect)
├── cli.py ← The Exort Shell (interactive terminal)
├── config.py ← YAML config + .env loading
├── utils.py ← Terminal formatting, IDs
├── providers/ ← LLM backends
│ ├── base.py ← Abstract provider interface
│ ├── groq_provider.py
│ ├── openai_provider.py
│ ├── ollama_provider.py
│ └── anthropic_provider.py
├── tools/ ← Built-in gear
│ ├── gear.py ← GearBox (registration + discovery)
│ ├── web.py ← Web search + URL fetch
│ ├── file_ops.py ← File CRUD
│ ├── shell.py ← Shell execution
│ ├── code.py ← Python execution
│ └── vision.py ← Image loading
├── memory/
│ └── store.py ← SQLite conversation store
├── playbooks/ ← Knowledge files (markdown)
│ └── library.py ← Playbook loader + search
└── bot/
└── telegram_bot.py ← Telegram frontend
┌─────────────┐
│ PERCEIVE │ Read user input + tool results
└──────┬──────┘
▼
┌─────────────┐
│ REASON │ LLM decides: answer now, or call a tool?
└──────┬──────┘
▼
┌─────────────┐ ┌──────────┐
│ ACT │────▶│ GEAR │ Execute tool, get result
└──────┬──────┘ └──────────┘
▼
┌─────────────┐
│ REFLECT │ Observe result → loop back to REASON
└──────┬──────┘
▼
[answer]
This is not a fixed pipeline — the engine decides its own path based on what the user needs. Some questions need zero tools. Others need five.
| Provider | Cost | Speed | Setup |
|---|---|---|---|
| Groq | Free (30 req/min) | Ultra-fast | console.groq.com |
| Ollama | Free (local) | Depends on hardware | ollama.ai |
| OpenAI | Pay-per-token | Fast | platform.openai.com |
| Anthropic | Pay-per-token | Fast | console.anthropic.com |
| Custom | Varies | Varies | Any OpenAI-compatible API |
Switch at runtime:
exort ▸ :switch ollama
exort ▸ :model llama3.1
All API keys are stored in ~/.exort/.env (one KEY=value per line).
# Built-in providers — just add the key:
echo "GROQ_API_KEY=gsk_your_key" > ~/.exort/.env
echo "OPENAI_API_KEY=sk-your_key" >> ~/.exort/.env
echo "ANTHROPIC_API_KEY=sk-ant-your_key" >> ~/.exort/.env
# Multiple providers at once:
cat > ~/.exort/.env << 'EOF'
GROQ_API_KEY=gsk_your_groq_key
OPENAI_API_KEY=sk-your_openai_key
ANTHROPIC_API_KEY=sk-ant-your_anthropic_key
TELEGRAM_BOT_TOKEN=your_telegram_token
EOFOr use the interactive wizard:
exort setup# View current keys (values are masked)
cat ~/.exort/.env
# Update a specific key — edit the file directly:
# On Linux/Mac:
sed -i 's/GROQ_API_KEY=.*/GROQ_API_KEY=gsk_new_key/' ~/.exort/.env
# On Windows (PowerShell):
(Get-Content ~/.exort/.env) -replace 'GROQ_API_KEY=.*', 'GROQ_API_KEY=gsk_new_key' | Set-Content ~/.exort/.env
# Or just open it in any text editor:
nano ~/.exort/.env # Linux
notepad ~/.exort/.env # WindowsExort works with any OpenAI-compatible API — Together AI, Fireworks, DeepSeek, Mistral, OpenRouter, LM Studio, vLLM, etc.
Add a custom provider in ~/.exort/config.yaml:
providers:
together:
key_var: TOGETHER_API_KEY
endpoint: https://api.together.xyz/v1
model: meta-llama/Llama-3-70b-chat-hf
openrouter:
key_var: OPENROUTER_API_KEY
endpoint: https://openrouter.ai/api/v1
model: meta-llama/llama-3-70b-instruct
deepseek:
key_var: DEEPSEEK_API_KEY
endpoint: https://api.deepseek.com/v1
model: deepseek-chat
lmstudio:
key_var: null # local, no key needed
endpoint: http://localhost:1234/v1
model: local-modelThen add the API key to ~/.exort/.env:
echo "TOGETHER_API_KEY=your_key" >> ~/.exort/.env
echo "OPENROUTER_API_KEY=your_key" >> ~/.exort/.env
echo "DEEPSEEK_API_KEY=your_key" >> ~/.exort/.envUse it:
exort shell -p together
exort shell -p openrouter
# or inside the shell:
exort ▸ :switch togetherexort config show # all settings
exort config get engine.provider # current provider
exort config get engine.model # current model
exort providers # list available providers# Via config commands (persists to config.yaml):
exort config set engine.provider openai
exort config set engine.model gpt-4o
exort config set engine.temperature 0.3
# Via shell commands (session only):
exort ▸ :switch ollama
exort ▸ :model llama3.1runtime args (--provider, --model) > env vars > config.yaml > built-in defaults
Any API that implements the OpenAI Chat Completions format works:
POST /v1/chat/completionswithmessages,model,temperature,max_tokens- Returns
choices[0].message.contentand optionaltool_calls - Streaming via
stream: truewith SSE chunks
Examples of compatible APIs: Together AI, Fireworks AI, DeepSeek, Mistral, OpenRouter, Groq, LM Studio, Ollama, vLLM, text-generation-inference, LiteLLM, and many more.
▓█████ ██╗ ██╗ ██████ ██████ ████████╗
...
provider: groq model: llama-3.3-70b-versatile gear: 9
type :help for commands, :quit to exit
exort ▸ :help
Exort Commands
─────────────────────────────────────
:help Show this list
:new Start a fresh session
:status Provider, model, token stats
:gear List available gear (tools)
:providers List LLM backends
:switch <prov> Switch LLM provider
:model <name> Switch model
:history Show current conversation
:sessions List saved sessions
:load <id> Resume a session
:clear Clear screen
:quit Exit
exort ▸ What is the Fibonacci sequence?
exort ▸ The Fibonacci sequence is a series where each number
is the sum of the two preceding ones: 0, 1, 1, 2, 3, 5, 8, 13...
Run Exort as a Telegram bot — AI agent in your pocket.
# 1. Message @BotFather on Telegram → /newbot → copy token
# 2. Save it:
echo "TELEGRAM_BOT_TOKEN=your_token" >> ~/.exort/.env
# 3. Launch:
exort botFeatures:
- Per-user conversation memory
- Full gear access (web search, code execution, etc.)
- Rate limiting
- Group chat support (@mention to trigger)
from exort import Engine
# Simple
e = Engine()
print(e.talk("What is Rust?"))
# Streaming
for chunk in e.talk("Explain quantum computing", stream=True):
print(chunk, end="", flush=True)
# With memory
e.open("my project")
e.talk("Build a REST API with FastAPI")
e.talk("Now add authentication") # remembers context
e.close()
# Local (Ollama)
e = Engine(provider="ollama", model="llama3.1")
print(e.talk("Hello!"))~/.exort/config.yaml:
engine:
provider: groq
model: llama-3.3-70b-versatile
max_rounds: 20
max_tokens: 4096
temperature: 0.7
memory:
enabled: true
window: 50
gear:
enabled: true
allow_unsafe: false
display:
stream: true
show_gear_calls: true
show_tokens: trueexort config show # view all
exort config set engine.provider openai # change provider
exort config set engine.temperature 0.3 # tune creativity
Create exort/tools/my_gear.py:
def _my_tool(param: str) -> dict:
"""Your logic here."""
return {"result": f"Processed: {param}"}
def register(gearbox):
gearbox.add(
name="my_tool",
info="What it does",
params={
"type": "object",
"properties": {
"param": {"type": "string", "description": "Input"}
},
"required": ["param"]
},
handler=_my_tool,
)The engine auto-discovers it on next startup.
# Interactive shell
docker compose run cli shell
# Telegram bot
docker compose up botWe welcome contributions — especially new gear, new providers, and documentation.
git clone https://github.com/askexort/exort.git
cd exort
pip install -e ".[full,dev]"
make test # run tests
make lint # check styleSee CONTRIBUTING.md for details.
- New providers (Google Gemini, Mistral, Cohere)
- New gear (PDF reader, database queries, image generation)
- Platform bots (Discord, Slack, WhatsApp)
- Playbook packs (domain-specific knowledge)
- Documentation and tutorials
MIT — use it, fork it, ship it. No strings attached.
Built for everyone who believes AI should be free and open.
Star · Issues · Discussions