This repository contains a dependency-free implementation of a minimal agentic AI runtime:
agent = model + state + tools + policy loop
Current version: 0.1.0
Start here:
- Published Project Page
- Local Project Page Source
- Agentic AI: The Loop
- Install Guide
- Use Cases
- Learning Loop
- Example Screenshots
- GitHub Pages Deploy
Install the agentic-loop command on Linux or macOS with the bootstrap script:
curl -fsSL https://raw.githubusercontent.com/Bowen-AI/AgenticLocal/main/scripts/install.sh \
-o install-agentic-loop.sh
bash install-agentic-loop.sh --with-ollama
agentic-loop --versionOr run it directly:
curl -fsSL https://raw.githubusercontent.com/Bowen-AI/AgenticLocal/main/scripts/install.sh \
| bash -s -- --with-ollamaFrom a local checkout, use the same installer:
scripts/install.sh
agentic-loop --versionThe installer creates an isolated environment under
~/.local/share/agentic-loop, writes a launcher to ~/.local/bin, prompts for
Ollama when it is missing, and pulls the default qwen3.5:4b-mlx model when
Ollama is available. Use --no-model-pull to skip the model download.
Common install modes:
scripts/install.sh --with-ollama
scripts/install.sh --ollama-model qwen3.5:4b-mlx
scripts/install.sh --no-ollamaStart an interactive agent chat:
python3 -m agentic_loop chatInteractive chat defaults to Ollama with qwen3.5:4b-mlx; when a selected
startup model or /model switch is missing, the CLI asks whether to download it
before continuing. Start chat with opt-in public web/news tools:
python3 -m agentic_loop chat --enable-network-toolsThen try:
Search the internet for agentic AI.
Search news about robotics.
Fetch https://example.com and summarize it.
List files through the agent loop:
python3 -m agentic_loop "List files in the workspace."Inspect a CSV through a tool call:
python3 -m agentic_loop "Inspect data/sample.csv as a dataset."Write to the default configured outputs/ write root:
python3 -m agentic_loop "Write a note saying hello from the agent."Add another named write root:
python3 -m agentic_loop \
--write-root drafts \
"Save a draft note."Return structured JSON:
python3 -m agentic_loop "Inspect data/sample.csv" --jsonShow the CLI version:
python3 -m agentic_loop --versionStart the local HTTP agent service:
python3 -m agentic_loop serve --host 127.0.0.1 --port 8765The service defaults to Ollama with qwen3.5:4b-mlx, but clients can choose provider and
model per request or per session. Use --provider rule when you want the
dependency-free deterministic provider.
Public web/news/fetch tools are enabled by default for the local service. Start without those network tools when you want a narrower server:
python3 -m agentic_loop serve \
--host 127.0.0.1 \
--port 8765 \
--disable-network-toolsThen open the embedded voice mode:
http://127.0.0.1:8765/voice
By default /voice tries Gemini Live when GEMINI_API_KEY or
GOOGLE_API_KEY is set, then falls back to the browser Web Speech API. Keep
voice local-browser only with --voice-provider browser, or request the live
path with --voice-provider gemini-live. Override the preview Live model with
--voice-model or AGENTIC_LOOP_GEMINI_LIVE_MODEL.
Or call it from another terminal:
curl -s http://127.0.0.1:8765/health
curl -s http://127.0.0.1:8765/events
curl -N "http://127.0.0.1:8765/events?follow=1&timeout=30"
curl -s http://127.0.0.1:8765/memory
curl -s http://127.0.0.1:8765/registry/models
curl -s http://127.0.0.1:8765/registry/rules
curl -s http://127.0.0.1:8765/registry/workflows
curl -s http://127.0.0.1:8765/voice/config
curl -s http://127.0.0.1:8765/learning/drafts
curl -s http://127.0.0.1:8765/skills
curl -s -X POST http://127.0.0.1:8765/chat \
-H "Content-Type: application/json" \
-d '{"message":"Inspect data/sample.csv as a dataset.","workflow":"loop"}'Choose a served model per request:
curl -s -X POST http://127.0.0.1:8765/chat \
-H "Content-Type: application/json" \
-d '{"message":"hello","model":{"provider":"ollama","name":"your-local-model"}}'
curl -s -X POST http://127.0.0.1:8765/chat \
-H "Content-Type: application/json" \
-d '{"message":"hello","model":{"provider":"openai","name":"your-openai-model","api_key":"..."}}'Use the CLI against a running server:
python3 -m agentic_loop client --models
python3 -m agentic_loop client --provider ollama --model your-local-model "hello"By default, durable app state is stored in:
.agentic/agentic.db
That SQLite database stores sessions, messages, run steps, long-term memory,
learning experiences/drafts/skills, events/traces, tool/UI registry metadata,
and rule/workflow registry metadata.
JSONL memory and trace files are still available as optional legacy/export
paths through --memory and --trace.
Rules and workflows can be listed from the CLI:
python3 -m agentic_loop --rules
python3 -m agentic_loop --workflows
python3 -m agentic_loop --models
python3 -m agentic_loop --workflow loop "Inspect data/sample.csv"
python3 -m agentic_loop chat --enable-network-toolsInside chat, use /rules, /rule on max_effort, /models,
/model ollama qwen3.5:4b-mlx, /learn, /skills, /loop, /search, and
/release.
Learning runs in conservative draft mode by default. Completed runs are summarized into SQLite, repeatable patterns become draft memories or procedural skills, and nothing is activated until you approve it:
/learn
/learn approve ID
/learn reject ID
/skills
/skill KEY
/skill archive KEY
Use --learning off to disable the loop, or --learning-threshold N to change
how many repeated patterns are needed before proposing a procedural skill.
Served mode exposes the same review surface through /learning/drafts and
/skills. See Learning Loop.
When chat starts without --provider, it uses --provider ollama --model qwen3.5:4b-mlx.
Use --provider rule for deterministic offline demos and tool-loop tests.
Explicit Ollama model choices in chat, one-shot runs, serving, and local client
requests prompt to download the model first when it is not already installed.
Run the full release check. This is the main command for a normal release:
scripts/check_release.shRun optional checks when the environment supports them:
python3 scripts/smoke_server.py
python3 scripts/smoke_ollama.py --model gemma3:270mThe server smoke test opens a local loopback socket. Some sandboxes block that, so it is separate from the default release check.
The Ollama smoke test requires Ollama to be running and the requested model to be installed. For Gemma 3 270M:
ollama pull gemma3:270mRun the full smoke test, including unit tests and real CLI executions:
scripts/smoke_test.shRun the richer end-to-end showcase:
python3 scripts/showcase_e2e.pyThis demonstrates CLI runs, SQLite memory across processes, configurable write roots, approval-required roots, HTTP chat, durable API views, registries, SSE events, and provider/voice adapter boundaries. It starts a local loopback HTTP server for the HTTP/SSE section.
Run only the unit tests:
python3 -m unittest discover -s tests -vCurrent coverage checks:
- loop/controller execution
- multi-tool responses (all
tool_callsexecuted in one step) - blocking
approval_callbackfor risky writes when callers supply one - native
on_event/max_stepspassthrough onAgentController.runand chat - repeated identical tool-call loop guard
- tool calls
- opt-in public web/news/fetch tools
- workspace policy enforcement
- denied unsafe reads/writes
- configurable write roots
- approval-required write roots
- interactive chat session state
- SQLite memory remember/recall
- durable server sessions
- persisted workflow events
- tool/UI/rule/workflow registry metadata
- SSE event formatting
- CSV inspection
- max-step stopping
- structured result shape
- provider adapter selection
- voice adapter interface
- learning loop storage, review commands, and skill reuse
- Ollama adapter parsing/fallback behavior (including tools-unsupported)
This project is dependency-free and targets Python 3.11+.
Run without installing:
python3 -m agentic_loop "List files in the workspace."Install the agentic-loop command from a Linux or macOS checkout:
scripts/install.sh
agentic-loop --versionThe installer prefers an isolated venv under ~/.local/share/agentic-loop and
creates a launcher in ~/.local/bin. If your system Python lacks venv/pip
support, it prints the platform package to install.
Ollama is a system application, not a Python wheel dependency. The installer will prompt to install Ollama when it is missing and pulls the default model when Ollama is available:
scripts/install.sh --with-ollama
scripts/install.sh --ollama-model qwen3.5:4b-mlx
scripts/install.sh --no-model-pull
scripts/install.sh --no-ollamaBuild release artifacts:
scripts/package_release.sh
ls dist/This emits a universal wheel and source tarball without requiring pip,
wheel, or python -m build.
Install as an editable local package when pip is already available:
python3 -m pip install -e .
agentic-loop "Inspect data/sample.csv as a dataset."CI runs scripts/check_release.sh on Linux and macOS for Python 3.11 and 3.12.
agentic_loop/
controller.py # loop
model.py # model interface, scripted model, deterministic demo model
ollama_model.py # Ollama chat adapter
providers/ # OpenAI-compatible and LocalAI adapter scaffolding
tools.py # tool schemas and implementations
policy.py # permissions
context.py # context construction
learning.py # local observe/reflect/distill learning loop
skills.py # procedural skill markdown and matching
memory.py # JSONL long-term memory
storage.py # SQLite sessions, events, memory, skills, traces, registries
state.py # agent state
evals.py # completion/safety evaluation
logs.py # JSONL traces
cli.py # runnable command-line demo
chat.py # interactive terminal chat
server.py # local HTTP service
voice.py # embedded browser voice page
voice_adapters.py # provider-neutral voice adapter interfaces
session.py # multi-turn chat sessions
factory.py # controller construction
The main runtime shape is:
User / UI
-> CLI, terminal chat, HTTP API, browser voice page
-> Agent Runtime
-> Context Builder
-> Model Adapter
-> Rule Resolver
-> Workspace Policy
-> Tool Registry
-> Learning Loop
-> Event Logger
-> Evaluator
-> SQLite Storage
-> sessions, messages, memory, skills, events, traces, registries
-> Workspace Files
-> read roots, write roots, approval-gated roots
Detailed architecture:
User / UI
-> Terminal chat, HTTP chat, browser voice page, tool timeline
HTTP API
-> POST /chat
-> POST /run
-> POST /models/select
-> GET /events SSE event stream snapshot
-> GET /events?follow=1&timeout=30
-> GET /tools tool schemas + registry metadata
-> GET /memory long-term memory records
-> GET /learning/drafts
-> GET /skills
-> GET /skills/{key}
-> GET /sessions durable session list
-> GET /registry/ui UI component registry metadata
-> GET /registry/rules
-> GET /registry/workflows
-> GET /registry/models
-> POST /learning/drafts/approve
-> POST /learning/drafts/reject
-> POST /skills/archive
Agent Runtime
-> Context Builder
-> Brain / Model Adapter
- Rule model
- Ollama
- OpenAI-compatible
- optional MLX (`mlx-lm`) local engine
- Gemini/OpenAI-compatible endpoints
- LocalAI
- other provider API keys through the adapter boundary
-> Policy / Resolution Engine
- configured read roots
- configured write roots
- approval-required roots
- optional blocking approval callback for risky tools
- active rule checks
- symlink/path escape checks
-> Tool Registry
- local file tools
- CSV inspection
- memory tools
- opt-in web/news/fetch tools
- multi-tool parallel calls from one model response
- future paper, dataset, MCP tools
-> Learning Loop
- observe completed run summaries
- reflect into structured draft artifacts
- reuse approved procedural skills by trigger matching
-> Event Logger (SQLite + optional in-process `on_event` callback)
-> Evaluator
Storage
-> SQLite .agentic/agentic.db
- sessions + messages
- working state + steps
- long-term memory
- learning experiences + drafts
- procedural skills + skill uses
- tool registry metadata
- UI registry metadata
- rule registry metadata + settings
- workflow registry metadata
- traces/events
-> Workspace files
- configured read roots
- configured write roots
- approval-gated risky roots
Voice
-> Gemini Live browser audio when configured
- ephemeral tokens minted by the local server
- 16 kHz PCM microphone input over browser WebSocket
- 24 kHz PCM spoken replies from Gemini Live
-> Browser Web Speech fallback
-> Same policy/tools/memory/runtime underneath
Memory/state split:
Short-term context
Prompt messages sent to the model on the current turn.
Working memory
AgentState and step/task state for the current run.
Session memory
Conversation transcript persisted by session_id in SQLite.
Long-term memory
Deliberate remember/recall facts persisted across sessions.
Procedural skills
Approved local Markdown workflows matched by lightweight triggers and injected
only when relevant.
Retrieval memory
Future searchable project/code/docs chunks, separate from long-term facts.
Related notes: