Skip to content

lsimons/lsimons-agent

This is a demo CLI coding agent for use by Leo Simons (@lsimons) and his bot (@lsimons-bot).

It's inspired by stuff like

Things I want:

  • A simple hello-world example of such a coding agent more than a daily use system.
  • Optimized for readability and understandability.
  • Implemented in python and using uv.
  • Low on external dependencies to keep complexity down.
  • Keep the python code simple and don't use advanced coding constructs.
  • The CLI should also launch a simple webserver on localhost with a web UI.
  • Electron application that is a thin wrapper around that web frontend.
  • Use vibe coding to build the coding agent.
  • Experiment with the Ralph Wiggum style of vibe coding to build this, https://awesomeclaude.ai/ralph-wiggum .
  • Use a monorepo setup with multiple packages (core cli, react frontend, web server, web api, frontend server, electron app, etc).
  • Get any secrets from 1password.
  • Simple unit tests without mocking frameworks or complex structures.

Things I don't want or need:

  • MCP
  • Skills
  • Async
  • Performance
  • Image support
  • Themes (just dark mode is fine)
  • Configurability (just load some env vars, hardcode the rest in python)

Project Structure

lsimons-agent/
├── packages/
│   ├── lsimons-agent/           # Core agent logic (python)
│   │   ├── pyproject.toml
│   │   └── src/lsimons_agent/
│   │       ├── agent.py         # Main agent loop + process_message()
│   │       ├── tools.py         # Tool definitions (read, write, edit, bash)
│   │       └── llm.py           # LLM client (OpenAI-compatible API)
│   ├── lsimons-agent-web/       # FastAPI backend + HTML frontend
│   │   ├── pyproject.toml
│   │   ├── src/lsimons_agent_web/
│   │   │   ├── server.py        # FastAPI app with WebSocket terminals
│   │   │   ├── terminal.py      # PTY-based terminal management
│   │   │   └── client.py        # CLI client for chat endpoint
│   │   ├── templates/           # HTML templates (terminal UI)
│   │   └── static/              # Static assets (favicon, logo)
│   ├── mock-llm-server/         # Mock LLM server for testing
│   │   ├── pyproject.toml
│   │   ├── scenarios.json       # Canned responses
│   │   └── src/mock_llm/
│   │       └── server.py
│   ├── lsimons-agent-electron/  # Electron wrapper
│   │   ├── package.json
│   │   └── main.js
│   └── lsimons-agent-e2e-tests/ # Playwright end-to-end tests
│       ├── package.json
│       ├── playwright.config.js
│       └── tests/
├── scripts/                     # Build scripts
│   ├── build_backend.py         # PyInstaller build for backend
│   └── build_icons.py           # Generate app icons
├── pyproject.toml               # Root project config (uv workspace)
└── README.md

Development Setup

# Install uv if not already installed
curl -LsSf https://astral.sh/uv/install.sh | sh

# Create virtual environment and install dependencies
uv sync --all-packages

# Run the CLI
uv run lsimons-agent

# Run the web server
uv run lsimons-agent-web

# Run mock LLM server (for testing)
uv run mock-llm-server

# Run Python tests
uv run pytest

GUI

Development Mode

Run the Electron app in development (launches web server automatically):

cd packages/lsimons-agent-electron && npm install && npm start

Building for Distribution

Build standalone desktop apps that bundle the Python backend:

cd packages/lsimons-agent-electron

# Build for current platform
npm run build

# Build for specific platform
npm run build:mac      # macOS (.dmg)
npm run build:win      # Windows (.exe)
npm run build:linux    # Linux (.AppImage)

The build process:

  1. Generates app icons from docs/Leo-Bot.png
  2. Bundles Python backend with PyInstaller
  3. Packages everything with electron-builder

Built apps are in packages/lsimons-agent-electron/dist/.

Playwright E2E Tests

The e2e tests use Playwright to test the full stack:

  • chat.spec.js - Tests the web UI against mock server
  • electron.spec.js - Tests the Electron app (launches electron, which starts web server)
# Install Playwright and dependencies
cd packages/lsimons-agent-e2e-tests
npm install
npx playwright install

# Run web UI tests (auto-starts mock-llm and web servers)
npm run test:web

# Run Electron tests (requires electron package to be set up)
cd ../lsimons-agent-electron && npm install && cd ../lsimons-agent-e2e-tests
npm run test:electron

# Run all tests
npm test

# Run tests in headed mode (see the browser)
npm run test:headed

Test Flow

Playwright → Electron → Web Server → Core Agent → Mock LLM
     ↓          ↓           ↓            ↓           ↓
  browser    desktop     FastAPI    process_message  canned
  tests       app         SSE        + tools       responses

Environment Variables

This project uses lsimons-llm for LLM client functionality. Get LLM_API_KEY from 1password:

LLM_API_KEY=sk-...             # From 1password
LLM_BASE_URL=https://litellm.sbp.ai/v1
LLM_MODEL=azure/gpt-5-1

See the lsimons-llm README for full environment variable documentation.

For testing, leave these unset to use defaults (mock server on localhost:8000).

Tech Stack

  • Python 3.14+ - Main language
  • uv - Package management and virtual environments
  • FastAPI - Web framework for the API
  • Electron - Desktop app wrapper
  • Playwright - End-to-end testing
  • pytest - Python unit testing (no mocking frameworks)

Design Principles

  1. Readable code over clever code - Favor explicit, simple implementations
  2. Minimal dependencies - Only add what's truly needed
  3. No abstractions until needed - Start concrete, abstract later if patterns emerge
  4. Synchronous by default - Async adds complexity, avoid unless necessary
  5. Fail fast - Simple error handling, let exceptions propagate

Linting

Use ruff for linting and formatting:

uv run ruff check .          # Check for errors
uv run ruff check . --fix    # Auto-fix errors
uv run ruff format .         # Format code

Run linting before committing. All code must pass ruff check with no errors.

Testing

uv run pytest                # Run all tests
uv run pytest tests/test_tools.py  # Run one file
uv run pytest -k "test_read"       # Run tests matching name

Rules:

  • Write tests for new functions
  • Tests go in tests/ directory
  • Name test files test_*.py
  • Name test functions test_*
  • No mocking - use real implementations or the mock LLM server
  • Keep tests simple: setup, action, assert

Git Workflow

  1. Work on main branch (no feature branches for this project)
  2. Make small, focused commits
  3. Run uv run ruff check . before committing
  4. Run uv run pytest before committing
  5. Write clear commit messages: what changed and why

Commit message format:

Short summary (50 chars or less)

Optional longer description if needed.

Documentation

  • Specifications - Detailed feature specs for CLI, tools, web, and electron

Future Ideas

  • Conversation persistence
  • Syntax highlighting
  • Token usage display

About

Custom coding agent just for lsimons and lsimons-bot

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors