A model-agnostic TypeScript-based coding agent that works with multiple LLM providers (OpenAI, Anthropic). The agent receives natural language prompts, executes bash commands using function calling, and provides results interactively.
✨ Model Agnostic - Seamlessly switch between OpenAI and Anthropic with a single environment variable
🔧 Tool System - Built-in bash execution with support for pipes, chaining, redirects, and heredoc syntax
💻 Interactive CLI - Real-time conversation with streaming command output
📁 Clean Architecture - Separated concerns with models, tools, and agent logic
🚀 TypeScript - Full type safety with modern async/await patterns
- Node.js 18+
- API keys for your preferred LLM provider (OpenAI, Anthropic, or local Ollama)
-
Install dependencies:
npm install
-
Create
.envfile from example:cp .env.example .env
-
Configure
.envwith your credentials:- For OpenAI: Add your
OPENAI_API_KEYand setMODEL_PROVIDER=openai - For Anthropic: Add your
ANTHROPIC_API_KEYand setMODEL_PROVIDER=anthropic
See .env.example for all available configuration options and examples.
- For OpenAI: Add your
Default (OpenAI):
npm run startWith Anthropic:
npm run start:anthropicDevelopment mode (watch TypeScript compilation):
npm run devStart the agent and interact with natural language prompts:
[openai] >> list all files in current directory with timestamps
$ ls -la
total 456
drwxr-xr-x 12 user staff 384 Apr 26 12:09 .
...
[openai] >> create a file with "hello world"
$ cat > test.txt << 'EOF'
hello world
EOF
[openai] >> exit
The agent will:
- Parse your natural language request
- Generate appropriate bash commands via LLM
- Execute commands with tool calls
- Return results and continue conversation
- Support multi-turn interactions with full history
src/
├── agent.ts # Main model-agnostic agent loop
├── models/ # LLM provider implementations
│ ├── types.ts # Unified type definitions
│ ├── anthropic.ts # Anthropic provider
│ ├── openai.ts # OpenAI provider
│ └── index.ts # Provider factory
├── tools/ # Tool implementations
│ ├── bash.ts # Shell command execution tool
│ └── index.ts # Tool exports
For detailed architecture documentation, see ARCHITECTURE.md.
Start with the provided .env.example file as a template:
cp .env.example .envEdit .env with your API credentials and preferred settings.
| Variable | Description | Default | Required |
|---|---|---|---|
MODEL_PROVIDER |
Provider to use (openai, anthropic) |
openai |
No |
OPENAI_API_KEY |
OpenAI API key or compatible service | - | Yes (for OpenAI) |
OPENAI_BASE_URL |
OpenAI base URL or compatible endpoint | https://api.openai.com/v1 |
No |
OPENAI_MODEL |
OpenAI model name | gpt-4 |
No |
ANTHROPIC_API_KEY |
Anthropic API key | - | Yes (for Anthropic) |
ANTHROPIC_BASE_URL |
Anthropic base URL | https://api.anthropic.com |
No |
ANTHROPIC_MODEL |
Anthropic model name | claude-3-sonnet-20240229 |
No |
OpenAI (Default):
MODEL_PROVIDER=openai
OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-4NVIDIA API (OpenAI-compatible):
MODEL_PROVIDER=openai
OPENAI_API_KEY=nvapi-...
OPENAI_BASE_URL=https://integrate.api.nvidia.com/v1
OPENAI_MODEL=qwen/qwen3-coder-480b-a35b-instructLocal Ollama:
MODEL_PROVIDER=anthropic
ANTHROPIC_BASE_URL=http://localhost:11434
ANTHROPIC_MODEL=qwen3.5:9bAnthropic Claude:
MODEL_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-...
ANTHROPIC_MODEL=claude-3-opus-20240229Build TypeScript:
npm run buildWatch mode (auto-rebuild on file changes):
npm run devExecute shell commands with full support for:
- Pipelines:
ls | grep .ts - Command chaining:
cd src && ls -la - File I/O:
echo "content" > file.txt - Heredoc:
cat << 'EOF' ... EOF - Redirects:
command > output.txt,command >> append.txt
- Create
src/models/yourprovider.tsimplementing theModelProviderinterface - Register in
src/models/index.ts - Add environment variables to
.env
See ARCHITECTURE.md for detailed examples.
- Create
src/tools/yourtool.ts - Export from
src/tools/index.ts - Add tool definition to
TOOLSarray insrc/agent.ts
- OpenAI: GPT-4, GPT-3.5-Turbo, and compatible APIs (NVIDIA, Azure, etc.)
- Anthropic: Claude models via direct API or local Ollama
- Local: Ollama with Llama 2, Qwen, and other compatible models
- Node.js 18 or higher
- TypeScript 5.5+
- Valid API credentials for your chosen provider
- Continue until a complete response is generated
Example tasks:
Create a hello world file and show me the output
Set up a Node.js server that listens on port 3000
Explain what files are in this directory
Type q or exit to quit.
user input → append to history → agent.messages.create()
↓
if tool_use: spawn bash command → capture output
↓
append result to history → loop continues
↓
else (text response): display and break loop
-
src/s01_agent_loop.ts- Main entry point implementing:- Anthropic SDK client initialization with configurable model/endpoint
- System prompt setup (
process.cwd()as agent location) - Interactive CLI using
readline/promises - Conversation loop with message history management
- Tool use detection and response rendering
-
src/mini_shell.ts- Custom bash tool implementation:- Command parsing without shell injection vulnerabilities
- Pipeline support (
|,&&) for multi-step commands - Heredoc (
<<) and file redirection (>,>>) handling - 120s timeout via child_process spawn
- Process chaining with proper stdout/stderr piping
src/
s01_agent_loop.ts # Main agent loop (single-file implementation)
mini_shell.ts # Bash tool wrapper (separate for modularity)
dist/ # Compiled JavaScript output
.env # Environment configuration (gitignored)
ANTHROPIC_API_KEY- API key for authentication (can be "ollama" for local)ANTHROPIC_BASE_URL- Base URL for API calls (default: http://localhost:11434)ANTHROPIC_MODEL- Model to use (default: qwen3.5:9b)
Uses ES2022 target with ESNext modules, source maps, and declaration files for type support.
| Command | Description |
|---|---|
npm run build |
Compile TypeScript to JavaScript in dist/ |
npm run start |
Run compiled JavaScript from dist/ |
npm run dev |
Build and watch for hot-reload development |
npm test |
Test runner (placeholder - add tests later) |
The agent operates with these constraints:
- System Prompt: Sets working directory context
- Available Tool: Only
bashcommand execution - Output Limit: Command results truncated to 200 chars before returning to agent
- Termination: Stops on text response, error, or
q/exitinput
- Edit source in
src/s01_agent_loop.ts - Run
npm run devfor hot-reload development - Or build with
npm run buildthen run withnpm start
npm run buildSince there's no test framework yet, you can add Jest/Vitest later:
# Add test framework first
npm install --save-dev jest
# Update package.json scripts and add tests in __tests__/The custom shell implementation avoids shell injection by:
- Tokenizing commands outside quotes for splitting
- Validating exit codes
- Not inheriting dangerous environment variables
- CLAUDE.md - Detailed development guide for Claude Code
- Original Project