An open API service indexing awesome lists of open source software.

https://github.com/maz557/coding-agent-free

Interactive AI coding agent using free OpenRouter models with real tool calling
https://github.com/maz557/coding-agent-free

agent ai-agent cli code-generation coding-agent free free-llm full-stack groq llamacpp llm llm-agents llm-tools lm-studio local-llm ollama openrouter programming tool-calling typescript

Last synced: about 6 hours ago
JSON representation

Interactive AI coding agent using free OpenRouter models with real tool calling

Awesome Lists containing this project

README

          

# Coding Agent Free


Stars
License
Last Commit
TypeScript
CI


Why This Agent? β€’
Quick Start β€’
CLI β€’
Web β€’
Examples


🌐
English β€’
فارسی β€’
Ψ§Ω„ΨΉΨ±Ψ¨ΩŠΨ© β€’
TΓΌrkΓ§e β€’
EspaΓ±ol β€’
FranΓ§ais β€’
اردو

An interactive AI coding assistant that runs in your **terminal** or **web browser** β€” powered by **free** cloud APIs (OpenRouter, Groq, Google, DeepSeek, Mistral) and **local** models (Ollama, LM Studio, Llama.cpp). It reads, writes, searches, copies, moves, and deletes files, and runs shell commands β€” all through natural language tool calling.

> πŸ’‘ **Offline-ready**: With a local server, the agent works fully offline β€” no internet required, no data leaves your machine.

## 🧠 Why This Agent?

| Problem | How This Agent Solves It |
|---------|--------------------------|
| Coding assistants cost $20/month (ChatGPT+, Claude Pro) | **100% free** β€” uses free-tier OpenRouter, Groq, Google, DeepSeek, Mistral + local models |
| One provider goes down / rate-limited | **8 providers** β€” auto-fallback on 429 + manual `/model ` |
| No internet access / restricted region | **Local models** (Ollama, LM Studio, Llama.cpp) β€” fully offline |
| Privacy concerns with cloud APIs | Run **local models only** β€” zero data leaves your machine |
| Setup is too complex | **`npm run setup`** β€” interactive wizard, no manual `.env` editing |
| AI runs dangerous commands | **Safe mode** (`/safe`) β€” whitelist-only shell commands |
| Agent gets stuck in loops | **Smart detection** β€” stops after 3Γ— identical tool calls |
| Provider rate-limited | **Auto-fallback** β€” switches provider automatically on 429 |
| Long tool results waste tokens | **Token compression** β€” head+tail truncation + duplicate removal |
| Want to use your IDE with free models | **OpenAI-compatible API** β€” `npm run setup-ide` connects Cline, Continue.dev, Cursor |

## Quick Start

```bash
git clone https://github.com/maz557/coding-agent-free.git
cd coding-agent-free
npm install
```

Run the interactive setup wizard (recommended):
```bash
npm run setup
```

Or create `.env` manually (pick at least one provider):
```bash
# OpenRouter (easiest β€” single key for 18+ free tool-calling models)
echo "OPENROUTER_API_KEY=sk-or-v1-..." >> .env

# Optional providers:
echo "GROQ_API_KEY=gsk_..." >> .env # Ultra-fast inference
echo "GOOGLE_API_KEY=AIza..." >> .env # Gemini models
echo "DEEPSEEK_API_KEY=sk-..." >> .env # DeepSeek
echo "MISTRAL_API_KEY=..." >> .env # Mistral models
```

**Fully offline (no API keys needed):**
```bash
# 1. Clone and install (requires internet once)
git clone https://github.com/maz557/coding-agent-free.git
cd coding-agent-free
npm install

# 2. Start your local model server (pick one):
# ollama run qwen3:14b # Ollama
# # or run LM Studio / llama-server

# 3. Launch the agent:
npm start

# 4. Inside the agent, add your local model:
# You: /add 6 ollama:auto
# You: /model 6
```

## CLI Interface

```bash
npm start
```

> On Windows, double-click `run-cli.bat`.
> πŸ“ **RTL languages (Persian, Arabic, Urdu, Hebrew, etc.):** If your terminal displays right-to-left text incorrectly, use `run-cli-rtl.bat` instead β€” it launches via [WezTerm](https://wezfurlong.org/wezterm/) with proper BiDi support.

## Web Interface

```bash
npm run web
# Open http://localhost:3000 in your browser
```

> On Windows, double-click `run-web.bat`.

The web UI supports the same features as the terminal β€” streaming responses, tool calls, model switching (all 8 providers + user presets), safe mode toggle, allow path, and conversation reset. Multiple browser tabs are supported with independent sessions. CLI and Web share the same model configuration (`src/config/models.ts`) and tool engine (`fileManager.ts`).

**New in v1.10 β€” Web UI enhancements:**
- **Diff Viewer** β€” when a file is written, replaced, or appended, the UI shows a side-by-side line-level diff (green + / red –) so you can see exactly what changed.
- **Session Manager** β€” create multiple sessions, switch between them, see auto-generated titles from the first message, model used, and message count.
- **Slash Commands** β€” type `/active`, `/model 2`, `/safe`, `/allow "C:\path"`, `/reset`, `/models`, `/exit` directly in the web input.
- **Help Modal** β€” click the `?` button for a complete usage guide including model switching, commands reference, and diff viewer explanation.
- **SSE streaming** β€” uses `fetch` + `ReadableStream` (no `EventSource` dependency) for reliable streaming.

The web server also exposes an **OpenAI-compatible API** at `http://localhost:3000/v1/chat/completions`, so any OpenAI-compatible client (Cline, Continue.dev, Cursor, etc.) can use your configured providers through a single endpoint with auto-fallback support.

Configure your IDE automatically:
```bash
npm run setup-ide
```

This will configure **Cline**, **Continue.dev**, and **Cursor** to point to the local API proxy, using your `.env` provider keys through the same routing.

**Example session:**

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ πŸ’¬ Coding Agent [πŸ”’ Safe] [🌐 P] β”‚
β”‚ ──────────────────────────────────────────────────────── β”‚
β”‚ β”‚
β”‚ You: create a hello.py that prints "Hello from Web UI" β”‚
β”‚ β”‚
β”‚ ⏳ Thinking... [Model: openrouter/free] β”‚
β”‚ β”‚
β”‚ πŸ›  write_file(path="hello.py", content="...") β”‚
β”‚ βœ” File written (25 bytes) β”‚
β”‚ β”‚
β”‚ πŸ›  run_command(command="python hello.py") β”‚
β”‚ βœ” Hello from Web UI β”‚
β”‚ β”‚
β”‚ Done! Created hello.py and verified it prints: β”‚
β”‚ Hello from Web UI β”‚
β”‚ ──────────────────────────────────────────────────────── β”‚
β”‚ [Message input... ] [Send] β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

> The model dropdown lets you switch between all 8 providers and your saved presets mid-session. Streaming responses appear token-by-token in real time.
> Click the **`?`** button in the header to open a help modal with usage guide, model switching instructions, and CLI command equivalents.

## Example Interactions

**"Create a Python script that prints Fibonacci numbers"**

The agent will create the file, write the code, then run it to verify:

```
You: write a fibonacci.py that prints first 20 numbers
⏳ Thinking...
πŸ”§ write_file({"path":"fibonacci.py","content":"..."})
πŸ”§ run_command({"command":"python fibonacci.py"})
Agent: Done! Created fibonacci.py and verified output: 0, 1, 1, 2, 3, 5...
```

**"Find all TypeScript files that call fetch() and replace it with axios"**

```
You: find all .ts files with fetch() calls and change them to axios
πŸ”§ search_content({"pattern":"fetch(","filePattern":"*.ts"})
πŸ”§ read_file({"path":"src/api.ts"})
πŸ”§ replace_in_file({"path":"src/api.ts","old_str":"fetch(","new_str":"axios."})
Agent: Updated 3 files (api.ts, users.ts, auth.ts).
```

**"Debug this error: Cannot read property 'map' of undefined"**

The agent reads the relevant file, analyzes the code, suggests and applies a fix.

## Features

- **8 providers** β€” OpenRouter, Groq, Google, DeepSeek, Mistral + Ollama, LM Studio, Llama.cpp
- **5 built-in presets** β€” start with `openrouter/free` (auto-discovers working free models)
- **User presets** β€” save/add/remove your own models with `/save`, `/add`, `/remove`
- **Fallback chain** β€” auto-fallback across providers on rate limit (429), plus model-level fallbacks
- **13 tools** β€” read, write, list (with details), create_folder, delete_file, delete_folder (recursive), append_file, copy_file, move_file, file_info, search_content, replace_in_file, and run_command
- **Token compression** β€” head+tail truncation of long tool results + automatic duplicate removal
- **Sliding window context** β€” keeps the last 20 exchanges by default, auto-trims to avoid token limit errors (configurable via `MAX_EXCHANGES` / `MAX_TOOL_RESULT_LENGTH`)
- **Smart loop detection** β€” stops if a tool is called 3+ times identically or 5+ times consecutively
- **Safe mode** (`--safe` / `/safe`) β€” whitelist-only shell commands
- **Setup wizard** β€” `npm run setup` interactively configures .env
- **Automatic retry** β€” exponential backoff + 120s timeout (300s for local models)
- **Zod validation** β€” runtime type-checking of every tool input and output
- **CLI & Web unified** β€” shared model config, system prompt, tool engine, provider definitions, and user presets across both interfaces
- **AGENTS.md support** β€” drop `AGENTS.md` in your project root to give the agent project-specific context automatically
- **opencode.json** β€” comprehensive permission rules (100+ safe command patterns auto-allowed) and truncated tool output for cleaner prompts
- **Tool output truncation** β€” all tool results capped at 5000 chars (`MAX_TOOL_RESULT_LENGTH`) to keep context clean
- **Conversation persistence** β€” auto-save/restore sessions across restarts
- **Structured logging** β€” via `pino` (stderr, doesn't interfere with UI)
- **Diff Viewer (Web UI)** β€” line-level LCS diffs for `write_file`, `replace_in_file`, `append_file`
- **Session Manager (Web UI)** β€” create/switch/list sessions with auto-title & metadata
- **Slash Commands (Web UI)** β€” `/active`, `/model `, `/safe`, `/allow`, `/reset`, `/models`, `/exit`
- **Help Modal (Web UI)** β€” usage guide, commands reference, diff viewer explanation

## Available Tools

| Tool | Description |
|------|-------------|
| `read_file` | Read contents of a file |
| `write_file` | Write content to a file (creates/overwrites) |
| `list_files` | List directory contents. Use `details:true` for size + timestamps |
| `create_folder` | Create a new folder |
| `delete_file` | Delete a single file |
| `delete_folder` | Delete a folder. Set `recursive:true` for non‑empty folders |
| `append_file` | Append content to an existing file |
| `copy_file` | Copy a file from source to destination |
| `move_file` | Move or rename a file |
| `file_info` | Get detailed metadata (size, permissions, timestamps) |
| `search_content` | Search for exact text in files. Supports `filePattern` (e.g. `*.ts`) and `maxResults` (default 50). Skips files >1MB |
| `replace_in_file` | Replace the first occurrence of exact text (case‑sensitive) |
| `run_command` | Run a shell command in the workspace |

## Commands

| Command | Description |
|---------|-------------|
| `/model ` | Switch to preset n |
| `/save ` | Save current model as preset n |
| `/add ` | Add model m as preset n (`provider:model` or just `model`) |
| `/remove ` | Remove a user preset |
| `/allow

` | Allow model to access a path outside workspace |
| `/safe` | Toggle safe mode (whitelist-only shell commands) |
| `/models` | Show all presets |
| `/active` | Show current active model |
| `/reset` | Clear conversation history (start fresh) |
| `/list-providers` | Show providers with valid keys (and local providers) |
| `/exit` | Quit |

## Multi-Provider Usage

Each preset is tied to a provider. Switching presets with `/model ` recreates the API client automatically:

```
You: /add 6 groq:openai/gpt-oss-120b
βœ… Added preset 6: [Groq] openai/gpt-oss-120b

You: /model 6
βœ… Switched to preset 6: [Groq] openai/gpt-oss-120b
(now using Groq's API with gpt-oss-120b)

You: /model 1
βœ… Switched to preset 1: [OpenRouter] openrouter/free
(back to OpenRouter)
```

### Adding models from other providers

```
/add :
```

Examples:
```
/add 10 groq:llama-3.3-70b-versatile
/add 11 google:gemini-2.0-flash-exp
/add 12 deepseek:deepseek-chat
/add 13 mistral:codestral-latest
```

If you omit the provider (e.g. `/add 10 llama-3.3-70b-versatile`), it defaults to the current preset's provider.

## Local Models (Ollama, LM Studio, Llama.cpp)

The agent supports any OpenAI-compatible local server with zero configuration:

### Quick start

Make sure your local server is running, then:

```
You: /add 6 ollama:auto
βœ… Auto-detected model: llama3.2:latest
βœ… Added preset 6: [Ollama] llama3.2:latest

You: /model 6
βœ… Switched to preset 6: [Ollama] llama3.2:latest
```

Or for LM Studio:

```
You: /add 7 lmstudio:auto
βœ… Added preset 7: [LM Studio] qwen2.5-coder-7b-instruct
```

The `:auto` keyword tells the agent to connect to the local server and detect the loaded model automatically.

### Quick start β€” specific local model

```bash
# Ollama β€” pull and serve a tool-calling model
ollama pull llama3.2
ollama serve # starts on port 11434

# Llama.cpp β€” serve a GGUF model directly
llama-server -m qwen2.5-coder-1.5b-instruct-q4_k_m.gguf --port 8080

# LM Studio β€” uses the built-in lms CLI
lms get llama-3.2-3b-instruct # download a model
lms load llama-3.2-3b-instruct # load into memory
lms server start --port 1234 # start the API server
```

Then add the local model to the agent:
```
/add 6 ollama:auto
/add 7 lmstudio:auto
/add 8 llamacpp:auto
```

### Custom ports

Set in `.env`:
```bash
OLLAMA_HOST=http://localhost:11434/v1
LMSTUDIO_HOST=http://localhost:1234/v1
LLAMACPP_HOST=http://localhost:8080/v1
```

### Requirements

- **Ollama**: [Download](https://ollama.ai) β†’ `ollama pull llama3.2` β†’ `ollama serve`
- **LM Studio**: [Download](https://lmstudio.ai) β†’ `lms get llama-3.2-3b-instruct` β†’ `lms server start --port 1234`
- **Llama.cpp**: [Download](https://github.com/ggerganov/llama.cpp) β†’ Build or get a binary β†’ `llama-server -m model.gguf --port 8080`
- The model must support **tool calling** (function calling) for full agent functionality.
- No API key required β€” local providers are skipped during startup key validation.
- All local providers use the OpenAI-compatible API, so no additional packages are needed.

## Workspace & Permissions

By default, the agent can only access files inside `./workspace`. To access other paths:

### Option 1: Change default workspace (permanent)

Set `ALLOWED_DIR` in `.env`:
```
ALLOWED_DIR=. # project root β€” access everything
ALLOWED_DIR=C:\path # any absolute path
```

### Option 2: Allow paths on-demand (per session)

When the model tries to access a path outside the workspace:
```
❌ Tool Error: Access denied: "C:\path" is outside the allowed directory.
Use command: /allow "C:\path"
```

Grant access with:
```
You: /allow "C:\path"
βœ… Allowed: C:\path
```

Permissions last for the current session only.

## Built-in Presets

| # | Model | Provider | Speed | Notes |
|---|-------|----------|-------|-------|
| 1 | `openrouter/free` | OpenRouter | varies | Auto-routes to available free models |
| 2 | Qwen 3 Next 80B | OpenRouter | medium | Good general purpose |
| 3 | Nemotron 3 Super 120B | OpenRouter | medium | 1M context |
| 4 | OpenAI GPT-OSS 120B | OpenRouter | fast | Strong reasoning |
| 5 | Nemotron 3 Ultra 550B | OpenRouter | slow | Largest free model with tools |

## Recommended Free Coding Models by Provider

### OpenRouter
Use the `openrouter/free` router, or pin specific models with `/add :free`.

### Groq (fastest β€” LPU hardware)
```
/add 6 groq:openai/gpt-oss-120b # 120B, 500 t/s
/add 7 groq:llama-3.3-70b-versatile # 70B, 280 t/s
/add 8 groq:qwen/qwen3-32b # 32B, 400 t/s
/add 9 groq:meta-llama/llama-4-scout-17b-16e-instruct # 750 t/s
```
Rate limits: 30 RPM, ~1K RPD. All models support tool calling.

### Mistral (EU-hosted)
```
/add 10 mistral:codestral-latest # Dedicated coding model
/add 11 mistral:mistral-large-latest # Best quality
/add 12 mistral:mistral-small-latest # Lightweight & fast
/add 13 mistral:open-mistral-nemo # 128K context, open-weight
```
Free tier: ~1 req/s, 1B tokens/month.

### Google AI Studio
```
/add 14 google:gemini-2.0-flash-exp # Fast, good coding
```
Free tier: 5-15 RPM, 100-1K RPD.

### DeepSeek
```
/add 15 deepseek:deepseek-chat # General purpose
/add 16 deepseek:deepseek-reasoner # Strong reasoning
```
Free tier: ~500 RPM, 500M tokens/day.

## Example Session

```
You: /model 4
βœ… Switched to preset 4: openai/gpt-oss-120b:free

You: create a folder named demo and write a hello.py
⏳ Thinking...
[Model: openai/gpt-oss-120b:free]
πŸ”§ create_folder({"path":"demo"})
πŸ”§ write_file({"path":"demo/hello.py","content":"print('Hello, world!')\n"})
Agent: Done! Created demo/hello.py with a Hello World script.

You: run the file
⏳ Thinking...
[Model: openai/gpt-oss-120b:free]
πŸ”§ run_command({"command":"python demo/hello.py"})
Agent: Hello, world! β€” the script runs correctly.

You: /model 6
βœ… Switched to preset 6: [Groq] openai/gpt-oss-120b
(now using Groq β€” same model, 500 t/s)

You: list files
⏳ Thinking...
[Model: openai/gpt-oss-120b]
πŸ”§ run_command({"command":"ls -la"})
Agent: demo/hello.py ...
```

## Troubleshooting

| Error | Likely Cause | Fix |
|-------|-------------|------|
| `403 Forbidden` | API key missing or invalid | Check `.env` has the right key for that provider |
| `403 Forbidden` | Internet restrictions blocking API host | Enable VPN/proxy, set `HTTPS_PROXY`, or use local models: `/add 6 ollama:auto` |
| `429 Rate limit exceeded` | Free tier daily limit hit | Wait or let **auto-fallback** switch provider automatically. Manual: `/model ` |
| `Agent stopped: stuck detected` | Same tool called 3Γ—+ consecutively | Recovery message injected automatically β€” rephrase your request |
| `All 3 attempts failed` | Model unreachable or too slow | Try a smaller model, use local models, or switch provider with `/model ` |
| `tool_calls` with empty arguments | Model doesn't support tool calling | Use a different model |
| `ENOTFOUND` / `ECONNREFUSED` | Internet restrictions or proxy needed | Enable VPN/proxy, set `HTTPS_PROXY`, or use local models |

### Quick checks
- `/list-providers` β€” shows which API keys are configured
- `/safe` β€” toggle safe mode status
- `npm run setup` β€” re-run the setup wizard
- `npm start` β€” restart after any code update

## Project Structure

```
coding-agent-free/
β”œβ”€β”€ src/
β”‚ β”œβ”€β”€ agent.ts # CLI entry point
β”‚ β”œβ”€β”€ CodingAgent.ts # Agent loop, tool execution, stuck detection
β”‚ β”œβ”€β”€ ConversationState.ts # Sliding window, context trimming, message management
β”‚ β”œβ”€β”€ commands.ts # Preset formatting, showModels
β”‚ β”œβ”€β”€ detectLocalModel.ts # Auto-detect models on local providers
β”‚ β”œβ”€β”€ persistence.ts # Save/load conversation & presets (with Zod validation)
β”‚ β”œβ”€β”€ tokenEstimator.ts # Token estimation (length/4)
β”‚ β”œβ”€β”€ types.ts # Shared type definitions (ChatMessage, ToolCall, etc.)
β”‚ β”œβ”€β”€ validation.ts # Zod schemas for tool input/output
β”‚ β”œβ”€β”€ server.ts # Express web server (SSE streaming, session management, auto-title)
β”‚ β”œβ”€β”€ config/
β”‚ β”‚ └── models.ts # Provider definitions, presets, system prompt
β”‚ β”œβ”€β”€ tools/
β”‚ β”‚ └── fileManager.ts # 13 tools + safe mode + workspace restrictions
β”‚ └── __tests__/ # Unit tests
β”‚ β”œβ”€β”€ ConversationState.test.ts # 9 tests: trim, removeLastAssistantTurn, etc.
β”‚ β”œβ”€β”€ comprehensive.test.ts # 30 tests: all modules + integration
β”‚ β”œβ”€β”€ CodingAgent.test.ts # 11 tests: execute, stuck, retry, errors
β”‚ β”œβ”€β”€ loadProjectContext.test.ts # 7 tests: file lookup, walk, edge cases
β”‚ β”œβ”€β”€ fileManager.test.ts # 26 tests: all 13 tools + safe mode
β”‚ β”œβ”€β”€ agent.test.ts # 24 tests: CLI commands, regex parsing, createClient
β”‚ └── server.test.ts # 30 tests: API endpoints, session, safe-mode, proxy, diff events
β”œβ”€β”€ .github/
β”‚ └── workflows/
β”‚ └── ci.yml # CI: type check + tests on push/PR
β”œβ”€β”€ scripts/
β”‚ β”œβ”€β”€ check_models.js # List free OpenRouter models with tool support
β”‚ β”œβ”€β”€ cleanup.js # Kill stale processes on port 3000
β”‚ β”œβ”€β”€ comprehensive-test.js # 35 integration tests (npm test)
β”‚ β”œβ”€β”€ provider-integration-test.ts # 26 provider integration tests (npm run test:integration)
β”‚ β”œβ”€β”€ setup.js # Interactive setup wizard (npm run setup)
β”‚ β”œβ”€β”€ setup-ide.js # Configure IDEs to use local API proxy
β”‚ β”œβ”€β”€ test.js # Non-interactive CLI smoke test
β”‚ β”œβ”€β”€ test-improvements.js
β”‚ β”œβ”€β”€ tool-integration-test.ts
β”‚ └── wezterm-launcher.cmd # Helper for run-cli-rtl.bat
β”œβ”€β”€ local/ # Local tools (gitignored)
β”‚ β”œβ”€β”€ backup/src/ # Snapshot of src/ for quick rollback
β”‚ └── restore.ps1 # Restore src/ from backup
β”œβ”€β”€ workspace/ # Default working directory
β”œβ”€β”€ .env # API keys (gitignored)
β”œβ”€β”€ presets.json # User presets (gitignored)
β”œβ”€β”€ tsconfig.json
β”œβ”€β”€ AGENTS.md # Project-specific agent context (auto-loaded)
β”œβ”€β”€ run-cli.bat # CLI launcher (Windows)
β”œβ”€β”€ run-cli-rtl.bat # CLI launcher with RTL support (WezTerm)
└── run-web.bat # Web UI launcher (Windows)
```

> πŸ“ Run tests: `npm run test:unit` (137 unit tests) β€” `npm run test:integration` (26 provider tests) β€” `npm test` (35 integration tests)

## Environment Variables

| Variable | Required? | Description |
|----------|-----------|-------------|
| `OPENROUTER_API_KEY` | No* | OpenRouter API key β€” https://openrouter.ai/keys |
| `GROQ_API_KEY` | No* | Groq API key β€” https://console.groq.com/keys |
| `GOOGLE_API_KEY` | No* | Google AI Studio key β€” https://aistudio.google.com/apikey |
| `DEEPSEEK_API_KEY` | No* | DeepSeek API key β€” https://platform.deepseek.com |
| `MISTRAL_API_KEY` | No* | Mistral API key β€” https://console.mistral.ai |
| `OLLAMA_HOST` | No | Ollama server URL (default: `http://localhost:11434/v1`) |
| `LMSTUDIO_HOST` | No | LM Studio server URL (default: `http://localhost:1234/v1`) |
| `LLAMACPP_HOST` | No | Llama.cpp server URL (default: `http://localhost:8080/v1`) |
| `ALLOWED_DIR` | No | Directory for file operations (default: `./workspace`) |
| `LOCAL_TIMEOUT` | No | Timeout (ms) for local model requests (default: 300000) |
| `LOG_LEVEL` | No | Log level: `debug`, `info`, `warn`, `error` (default: `info`) |
| `MAX_EXCHANGES` | No | Max user ↔ assistant exchanges kept in sliding window (default: `20`) |
| `MAX_TOOL_RESULT_LENGTH` | No | Max chars before tool results are truncated (default: `5000`) |

\* At least one API key is required (not needed for local providers).

## Large Projects

For medium-to-large projects, the default sliding window (20 exchanges) may drop older context. Increase these values in `.env`:

```env
# Keep up to 50 user-assistant exchanges
MAX_EXCHANGES=50

# Allow tool results up to 20,000 characters
MAX_TOOL_RESULT_LENGTH=20000
```

You can also reset the conversation mid-session with `/reset` if the model gets confused by stale context.

## Limitations

- **System prompt adherence**: Some free models (e.g., Nvidia Nemotron 550B) may ignore or partially follow system instructions. Switch to a different model if you notice this.
- **Rate limits**: Free-tier API keys have daily rate limits (HTTP 429). The agent retries with exponential backoff (max 3 attempts), but persistent limits require switching providers or waiting.
- **Token window**: With a 128K context model and 20-exchange sliding window, large codebases may hit context limits. Increase `MAX_EXCHANGES` and `MAX_TOOL_RESULT_LENGTH` in `.env` for larger projects.
- **Stuck detection**: The agent stops after 3Γ— identical tool calls or 5Γ— consecutive same-name calls, injects a recovery system message, and removes the last tool results. Simply rephrase your request to continue.
- **Windows shell**: PowerShell pipeline operators (`|`, `&&`) may trigger verbose permission prompts under strict opencode.json rules. Simple commands work without prompts.
- **Relative vs absolute paths**: Models handle paths inconsistently β€” some use relative paths, others absolute. The agent normalizes paths within `ALLOWED_DIR`.

## Security

- All file operations restricted to `ALLOWED_DIR` β€” `sanitizePath` prevents traversal attacks
- Shell commands run inside the workspace directory
- API keys are stored in `.env` (listed in `.gitignore`, never committed)
- Safe mode (`/safe`) restricts commands to a whitelist
- Dangerous shell commands blocked by denylist (rm -rf, dd, mkfs, wget, etc.)
- Use `local/` scripts for backup/restore

## Contributing

Contributions are welcome! Feel free to open an [issue](https://github.com/maz557/coding-agent-free/issues) or submit a pull request. Star the repo if you find it useful β€” it helps others discover it.

## License

MIT