Skip to content

Repository files navigation

Self-hosted AI GitHub bot for automated software development

Label an issue, and watch your bot plan, implement, and open a PR.
Polycode brings AI automation to your repos — no black box, no SaaS, your infra.


PythonFastAPICrewAIGitHub App

LicenseGitHub starsPython packageDockerPostgreSQLRedis


Key Features

  • Multi-agent workflows with CrewAI framework
  • GitHub App integration for multi-repo automation
  • Webhook-driven automation triggered by labels
  • Push to external repos via GitHub App tokens
  • Label-to-flow mapping (e.g., ralphralph_flow)
  • Fast iterative workflows with automated verification

Table of Contents


Tech Stack

Polycode (Backend)

ComponentTechnology
LanguagePython 3.13
FrameworkFastAPI
Multi-AgentCrewAI
Background JobsCelery
Message BrokerRedis
DatabasePostgreSQL
ORMSQLAlchemy / SQLModel
ValidationPydantic
Package Manageruv

Landing (Frontend)

ComponentTechnology
LanguageTypeScript 5.9
FrameworkReact 19
Build ToolVite 8
StylingTailwind CSS 3.4
AnimationFramer Motion
IconsLucide React
Package Managerpnpm

Project Structure

polycode/
├── apps/
│ ├── polycode/ # Python backend application
│ │ ├── src/
│ │ │ ├── crews/ # CrewAI crew definitions
│ │ │ │ ├── plan_crew/ # Planning crew
│ │ │ │ ├── ralph_crew/ # Ralph implementation crew
│ │ │ │ ├── implement_crew/
│ │ │ │ ├── review_crew/
│ │ │ │ ├── test_crew/
│ │ │ │ ├── verify_crew/
│ │ │ │ └── conversation_crew/
│ │ │ ├── ralph/ # Ralph Loop workflow
│ │ │ ├── feature_dev/ # Feature development workflow
│ │ │ ├── github_app/ # GitHub App webhook server
│ │ │ ├── project_manager/ # Project management utilities
│ │ │ ├── celery_tasks/ # Async task processing
│ │ │ ├── persistence/ # Database layer (PostgreSQL)
│ │ │ ├── channels/ # Real-time communication (SocketIO)
│ │ │ ├── tools/ # Custom CrewAI tools
│ │ │ └── flowbase.py # Base flow classes
│ │ ├── tests/ # Test files
│ │ ├── task_templates/ # Task template files
│ │ ├── pyproject.toml # Python project configuration
│ │ ├── uv.lock # Dependency lock file
│ │ ├── Dockerfile # Docker build file
│ │ ├── entrypooint.sh # Container entrypoint
│ │ └── Makefile # Build commands
│ │
│ └── landing/ # React frontend (marketing page)
│ ├── src/
│ │ ├── components/ # Reusable UI components
│ │ │ ├── Header.tsx
│ │ │ ├── Footer.tsx
│ │ │ └── ThemeToggle.tsx
│ │ ├── pages/ # Page components
│ │ │ └── Home.tsx
│ │ ├── lib/ # Utilities
│ │ ├── assets/ # Static assets
│ │ ├── App.tsx # Root component
│ │ ├── main.tsx # Entry point
│ │ └── index.css # Global styles
│ ├── public/ # Static files
│ ├── dist/ # Build output
│ ├── package.json # NPM dependencies
│ ├── pnpm-lock.yaml # Dependency lock
│ ├── vite.config.ts # Vite configuration
│ ├── tailwind.config.js # Tailwind configuration
│ ├── tsconfig.json # TypeScript configuration
│ └── index.html # HTML template
│
├── .github/
│ └── workflows/
│ └── landingpage.yaml # GitHub Actions deployment
│
├── .pre-commit-config.yaml # Pre-commit hooks
└── .gitignore

Prerequisites

For Polycode (Backend)

  • Python 3.13 or higher
  • uv package manager (install guide)
  • PostgreSQL 15+ (or Docker)
  • Redis 7+ (or Docker)
  • GitHub App credentials (for webhook integration)

For Landing (Frontend)

  • Node.js 22 or higher
  • pnpm package manager

Getting Started

1. Clone the Repository

git clone https://github.com/xeroc/polycode.git
cd polycode

2. Backend Setup (Polycode)

Install Dependencies

cd apps/polycode
uv sync

Environment Configuration

Copy the example environment file:

cp .env.example .env

Configure the following variables (see Environment Variables for details):

# Required
GITHUB_APP_ID=12345
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n..."
DATABASE_URL=postgresql://user:password@localhost:5432/polycode
REDIS_HOST=localhost
REDIS_PORT=6379
OPENAI_API_KEY=sk-your_key_here
# Optional
OLLAMA_HOST=http://localhost:11434

Start PostgreSQL (Docker)

docker run --name postgres \
-e POSTGRES_USER=polycode \
-e POSTGRES_PASSWORD=polycode \
-e POSTGRES_DB=polycode \
-p 5432:5432 \
-d postgres:16

Start Redis (Docker)

docker run --name redis \
-p 6379:6379 \
-d redis:7-alpine

Run Database Migrations

The application uses SQLAlchemy with auto-table creation. On first run:

uv run python -c "from persistence.postgres import Base, engine; Base.metadata.create_all(engine)"

Start the API Server

uv run webhook-server webhook --host 0.0.0.0 --port 8000

Or use the entrypoint:

APP_RUN=api uv run python -m entrypoint

Start the Celery Worker (Background Jobs)

uv run celery -A celery_tasks.worker.app worker -Ofair --queues celery,default --loglevel=info

Start Flower (Celery Monitoring)

uv run celery -A celery_tasks.worker.app flower --address=0.0.0.0 --port=5555

3. Frontend Setup (Landing)

Install Dependencies

cd apps/landing
pnpm install

Environment Configuration

Create .env file:

VITE_N8N_WEBHOOK_URL=https://your-webhook-url.com/webhook/xxx

Start Development Server

pnpm dev

Open http://localhost:5173 in your browser.


Architecture

System Overview

┌─────────────────────────────────────────────────────────────────┐
│ GitHub Webhooks │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ FastAPI Server │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ GitHub App │ │ Label Mapper │ │ Webhook Router │ │
│ │ Integration │ │ │ │ │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Celery Task Queue │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Ralph Flow │ │ Feature Flow │ │ Custom Flows │ │
│ │ Tasks │ │ Tasks │ │ Tasks │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ CrewAI Agents │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Plan Crew │ │ Implement Crew │ │ Review Crew │ │
│ │ (Planning) │ │ (Coding) │ │ (QA) │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Test Crew │ │ Verify Crew │ │
│ │ (Testing) │ │ (Validation) │ │
│ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ PostgreSQL │ │ Redis │ │ GitHub │
│ (State) │ │ (Queue) │ │ (Repos) │
└──────────────┘ └──────────────┘ └──────────────┘

Request Lifecycle

  1. GitHub webhook triggers on issue/PR event
  2. FastAPI receives webhook, validates signature
  3. Label mapper determines which flow to trigger
  4. Task dispatched to Celery queue
  5. Celery worker picks up task
  6. CrewAI agents execute the workflow
  7. Results pushed back to GitHub (PR, comments, commits)
  8. State persisted to PostgreSQL

Ralph Flow

The Ralph Flow is an iterative development workflow with built-in verification:

┌─────────────┐ ┌─────────────┐ ┌─────────────────┐
│ Setup │────▶│ Plan │────▶│ Ralph Loop │
│ (Worktree) │ │ (Stories) │ │ (Iterative) │
└─────────────┘ └─────────────┘ └─────────────────┘
│
┌───────────────────────────┤
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Verify │◀────────────│ Commit │
│ Build │ │ Story │
└─────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ Push │
│ & PR │
└─────────────┘

Ralph Loop Control Flow

  • retry → Continue loop with error context (max 3 iterations per story)
  • story_done → Commit current story, proceed to next
  • done → All stories complete, run final verification

Database Schema

-- Flow requests tracking
requests
├── id (serial, PK)
├── issue_number (int, not null)
├── request_text (text, not null)
├── status (varchar, not null)
├── commit (varchar, nullable)
└── created_at (timestamp)
-- Payment tracking
payments
├── id (serial, PK)
├── issue_number (int)
├── payment_id (varchar)
├── amount (int)
├── currency (varchar)
├── payment_method (varchar)
├── status (varchar)
├── created_at (timestamp)
└── verified_at (timestamp, nullable)

Environment Variables

Polycode Backend

Required

VariableDescriptionExample
GITHUB_APP_IDGitHub App ID12345
GITHUB_APP_PRIVATE_KEYGitHub App private key (PEM)-----BEGIN RSA PRIVATE KEY-----\n...
DATABASE_URLPostgreSQL connection stringpostgresql://user:pass@localhost:5432/polycode
REDIS_HOSTRedis hostnamelocalhost
REDIS_PORTRedis port6379
OPENAI_API_KEYOpenAI API key for LLM callssk-xxx

Optional

VariableDescriptionDefault
OLLAMA_HOSTOllama server URLhttp://localhost:11434
APP_RUNContainer run mode (api, worker, flower)api
APP_HOSTServer bind host0.0.0.0
APP_PORTServer port5000
LOG_LEVELLogging verbositycritical
FORWARDED_ALLOW_IPSTrusted proxy IPs*
SSH_KEYSSH private key for git operations-

Landing Frontend

VariableDescriptionRequired
VITE_N8N_WEBHOOK_URLN8N webhook for waitlist signupYes

Available Scripts

Polycode (Backend)

CommandDescription
uv syncInstall dependencies
uv add <package>Add new dependency
uv lockUpdate lock file
uv run ruff check .Lint code
uv run ruff check --fix .Auto-fix lint errors
uv run ruff format .Format code
uv run pyrightType check
uv run pytestRun all tests
uv run pytest tests/test_file.pyRun specific test file
uv run pytest -k "pattern"Run tests matching pattern
uv run webhook-server webhookStart FastAPI webhook server
uv run ralphRun Ralph flow example

Celery Commands

# Start worker
uv run celery -A celery_tasks.worker.app worker \
--queues celery,default \
--loglevel=info
# Start Flower monitoring
uv run celery -A celery_tasks.worker.app flower \
--address=0.0.0.0 \
--port=5555

Landing (Frontend)

CommandDescription
pnpm devStart development server
pnpm buildBuild for production (TypeScript + Vite)
pnpm previewPreview production build
pnpm lintRun ESLint

Docker Commands

# Build Docker image
make docker_build
# Push to registry
make docker_push
# Build and push (combined)
make docker

Testing

Backend Tests

# Run all tests
uv run pytest
# Run with verbose output
uv run pytest -v
# Run specific test file
uv run pytest tests/test_github_manager.py
# Run specific test function
uv run pytest tests/test_github_manager.py::test_has_label_returns_true_when_label_exists
# Run tests matching pattern
uv run pytest -k "label"

Test Structure

tests/
├── test_github_manager.py # GitHub API tests
├── test_project_manager.py # Project management tests
└── ...

Writing Tests

"""Test module docstring."""fromunittest.mockimportMagicMockfromproject_manager.githubimportGitHubProjectManagerfromproject_manager.typesimportProjectConfigdeftest_has_label_returns_true_when_label_exists():
"""Test that has_label returns True when the label is present."""# Arrangeconfig=ProjectConfig(
repo_owner="testowner",
repo_name="testrepo",
token="fake_token",
)
manager=GitHubProjectManager(config)
mock_repo=MagicMock()
mock_pr=MagicMock()
mock_pr.labels= [MagicMock(name="approved")]
mock_repo.get_pull.return_value=mock_prmanager.github_client.get_repo=MagicMock(return_value=mock_repo)
# Actresult=manager.has_label(123, "approved")
# AssertassertresultisTrue

Deployment

Landing Page (GitHub Pages)

The landing page is automatically deployed to GitHub Pages via GitHub Actions.

Trigger: Push to main branch

URL:https://polycod.ing

Manual deploy:

gh workflow run landingpage.yaml

Polycode Backend (Docker)

Build and Push

cd apps/polycode
# Build with timestamp version
make docker
# Or manually:
docker build -t ghcr.io/xeroc/polycode:$(date +%Y%m%d%H%M).
docker push ghcr.io/xeroc/polycode:$(date +%Y%m%d%H%M)

Run Container

# Run API server
docker run -p 5000:5000 \
-e DATABASE_URL=postgresql://... \
-e REDIS_HOST=redis \
-e GITHUB_APP_ID=12345 \
-e GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----..." \
-e OPENAI_API_KEY=sk-... \
ghcr.io/xeroc/polycode:latest api
# Run Celery worker
docker run \
-e DATABASE_URL=postgresql://... \
-e REDIS_HOST=redis \
-e GITHUB_APP_ID=12345 \
-e GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----..." \
-e SSH_KEY="$(cat ~/.ssh/id_rsa)" \
ghcr.io/xeroc/polycode:latest worker
# Run Flower monitoring
docker run -p 5555:5555 \
-e REDIS_HOST=redis \
ghcr.io/xeroc/polycode:latest flower

Docker Compose Example

version: "3.8"services:
postgres:
image: postgres:16environment:
POSTGRES_USER: polycodePOSTGRES_PASSWORD: polycodePOSTGRES_DB: polycodevolumes:
- postgres_data:/var/lib/postgresql/dataredis:
image: redis:7-alpinevolumes:
- redis_data:/dataapi:
image: ghcr.io/xeroc/polycode:latestcommand: apiports:
- "5000:5000"environment:
DATABASE_URL: postgresql://polycode:polycode@postgres:5432/polycodeREDIS_HOST: redisGITHUB_APP_ID: ${GITHUB_APP_ID}GITHUB_APP_PRIVATE_KEY: ${GITHUB_APP_PRIVATE_KEY}OPENAI_API_KEY: ${OPENAI_API_KEY}depends_on:
- postgres
- redisworker:
image: ghcr.io/xeroc/polycode:latestcommand: workerenvironment:
DATABASE_URL: postgresql://polycode:polycode@postgres:5432/polycodeREDIS_HOST: redisGITHUB_APP_ID: ${GITHUB_APP_ID}GITHUB_APP_PRIVATE_KEY: ${GITHUB_APP_PRIVATE_KEY}OPENAI_API_KEY: ${OPENAI_API_KEY}SSH_KEY: ${SSH_KEY}depends_on:
- postgres
- redisvolumes:
postgres_data:
redis_data:

Troubleshooting

Database Connection Issues

Error:could not connect to server: Connection refused

Solution:

  1. Verify PostgreSQL is running: docker ps or pg_isready
  2. Check DATABASE_URL format: postgresql://USER:PASSWORD@HOST:PORT/DATABASE
  3. Ensure database exists: createdb polycode

Redis Connection Issues

Error:ConnectionError: Error connecting to Redis

Solution:

  1. Verify Redis is running: docker ps or redis-cli ping
  2. Check REDIS_HOST and REDIS_PORT values
  3. If using Docker, ensure containers share a network

Celery Worker Not Processing Tasks

Symptoms: Tasks queued but never executed

Solution:

  1. Verify worker is running: celery -A celery_tasks.worker.app inspect active
  2. Check queue names match: --queues celery,default
  3. Review worker logs for errors

GitHub App Authentication Issues

Error:Bad credentials or 401 Unauthorized

Solution:

  1. Verify GITHUB_APP_ID and GITHUB_APP_PRIVATE_KEY are correctly set
  2. Ensure the private key is properly formatted (including newlines)
  3. For GitHub Apps, ensure app is installed on target repository

Import Errors (Module Not Found)

Error:ModuleNotFoundError: No module named 'xxx'

Solution:

# Sync dependencies
uv sync
# If using Docker, rebuild image
docker build --no-cache -t ghcr.io/xeroc/polycode:latest .

Landing Page Build Issues

Error:VITE_N8N_WEBHOOK_URL is not defined

Solution:

  1. Create .env file in apps/landing/
  2. Add required environment variables
  3. Rebuild: pnpm build

Pre-commit Hook Failures

Error:pyright or ruff failures

Solution:

# Auto-fix lint issues
uv run ruff check --fix .
uv run ruff format .# Run type check
uv run pyright
# Run all pre-commit hooks
pre-commit run --all-files

GitHub App Integration

Setup GitHub App

  1. Create GitHub App at https://github.com/settings/apps/new

  2. Configure permissions:

    • Issues: Read & Write
    • Projects: Read & Write
    • Contents: Read & Write
    • Pull requests: Read & Write
    • Metadata: Read (required)
  3. Set webhook URL:https://your-domain.com/webhook

  4. Generate private key and save to .env:

    GITHUB_APP_ID=12345
    GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n..."
    
  5. Install app on target repositories

Label-to-Flow Mapping

Configure which labels trigger which flows:

curl -X POST http://localhost:8000/mappings \
-H "Content-Type: application/json" \
-d '{ "installation_id": 12345, "label_name": "ralph", "flow_name": "ralph_flow" }'

Code Style

Python (Backend)

  • Line length: 120 characters
  • Enabled rules: E, F, I, N, W (E501 ignored)
  • Use modern Python 3.10+ type annotations (list[str] over List[str])
  • Run uv run ruff check --fix . before committing

TypeScript (Frontend)

  • ESLint with React Hooks and React Refresh plugins
  • Strict TypeScript configuration
  • Run pnpm lint before committing

Pre-commit Hooks

Configured hooks (.pre-commit-config.yaml):

  • trailing-whitespace: Remove trailing whitespace
  • commitizen: Conventional commits with gitmoji
  • markdownlint: Markdown linting
  • autoflake: Remove unused imports and variables
  • pyright: Python type checking

Run manually:

pre-commit run --all-files

Resources


License

MIT

About

Polycode is a 12-Factor compliant autonomous software development system built in Rust.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages