Skip to content

Repository files navigation

Agentic AI Loop

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:

Quick Install

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 --version

Or run it directly:

curl -fsSL https://raw.githubusercontent.com/Bowen-AI/AgenticLocal/main/scripts/install.sh \
  | bash -s -- --with-ollama

From a local checkout, use the same installer:

scripts/install.sh
agentic-loop --version

The 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-ollama

Run The Demo

Start an interactive agent chat:

python3 -m agentic_loop chat

Interactive 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-tools

Then 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" --json

Show the CLI version:

python3 -m agentic_loop --version

Start the local HTTP agent service:

python3 -m agentic_loop serve --host 127.0.0.1 --port 8765

The 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-tools

Then 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-tools

Inside 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.

Verification

Run the full release check. This is the main command for a normal release:

scripts/check_release.sh

Run optional checks when the environment supports them:

python3 scripts/smoke_server.py
python3 scripts/smoke_ollama.py --model gemma3:270m

The 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:270m

Run the full smoke test, including unit tests and real CLI executions:

scripts/smoke_test.sh

Run the richer end-to-end showcase:

python3 scripts/showcase_e2e.py

This 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 -v

Current coverage checks:

  • loop/controller execution
  • multi-tool responses (all tool_calls executed in one step)
  • blocking approval_callback for risky writes when callers supply one
  • native on_event / max_steps passthrough on AgentController.run and 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)

Package

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 --version

The 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-ollama

Build 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.

Components

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

System Diagram

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

Architecture Direction

See Architecture Decision.

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:

About

Allow any model to be agentic and able to use tools and MCP.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages