Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions Development.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Development Guide

Detailed guidance for contributors working on the OpenHands CLI.

## 1) Managing dependencies with Poetry/uv

This repo includes both pyproject sections for hatch/uv and Poetry for compatibility.

- Add a runtime dependency (using uv):
```bash
uv add <package>
```
- Add a dev dependency (linters, build tools, etc.):
```bash
uv add --dev <package>
```
- Sync environment:
```bash
uv sync --extra dev
```

If you use Poetry instead of uv:
```bash
poetry add <package>
poetry add --group dev <package>
poetry install
```

Commit the updated pyproject.toml (and lockfile if applicable) with your change.

## 2) Packaging with PyInstaller: spec file tips

PyInstaller uses a spec file (openhands-cli.spec) to describe what to include in the binary.
Two common knobs when something is missing in the built executable:

- hiddenimports: Python modules that PyInstaller fails to detect automatically.
Use when imports are dynamic or optional.
Example in spec:
```python
hiddenimports=[
'openhands_cli.tui',
'openhands_cli.pt_style',
*collect_submodules('prompt_toolkit'),
*collect_submodules('openhands.core'),
*collect_submodules('openhands.tools'),
]
```

- datas (a.k.a. data files): Non-Python files required at runtime (templates, config, etc.).
Use collect_data_files to include them.
Example in spec:
```python
datas=[
*collect_data_files('tiktoken'),
*collect_data_files('openhands.core.agent.codeact_agent', includes=['prompts/*.j2']),
]
```

Differences:
- hiddenimports is for modules to be packaged as bytecode.
- datas is for external resource files copied into the bundle.

If a library fails at runtime with "ModuleNotFoundError" inside the binary, add it to hiddenimports.
If a library complains about missing template/config/resource files, add those paths to datas.

## 3) Build locally and test

- Quick build (recommended):
```bash
./build.sh --install-pyinstaller
```
This ensures PyInstaller is present via uv and then runs build.py.

- Manual build:
```bash
uv add --dev pyinstaller
uv run pyinstaller openhands-cli.spec --clean
```

- Test the binary:
```bash
./dist/openhands-cli # macOS/Linux
# or dist/openhands-cli.exe # Windows
```

If the binary fails to start:
- Run the Python entrypoint to confirm the app itself works:
```bash
uv run openhands-cli
```
- Re-run build with --no-clean to inspect build artifacts, or add more hiddenimports/datas.

## 4) Linting and formatting

- Run all pre-commit hooks:
```bash
make lint
```
- Format code:
```bash
make format
```

## 5) Notes on agent credentials

To actually converse with a model, export one of the supported keys before running the CLI/binary:
```bash
export OPENAI_API_KEY=... # or
export LITELLM_API_KEY=...
```
149 changes: 27 additions & 122 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,140 +1,45 @@
# OpenHands CLI

A command-line interface for OpenHands AI Agent with Terminal User Interface (TUI) support.
A lightweight CLI/TUI to interact with the OpenHands agent (powered by agent-sdk). Build and run locally or as a single executable.

## Development
## Quickstart

### Setup

1. Install dependencies:
```bash
make install-dev
```

2. Install pre-commit hooks:
```bash
make install-pre-commit-hooks
```

### Code Quality

This project uses pre-commit hooks to ensure code quality. The following tools are configured:

- **Ruff**: Fast Python linter and formatter
- **MyPy**: Static type checking
- **Pre-commit hooks**: Various code quality checks

#### Running Linters

```bash
# Run all pre-commit hooks
make lint

# Format code
make format # Format code with ruff
```

#### Pre-commit Hooks

Pre-commit hooks will automatically run on every commit. To run them manually:
- Prerequisites: Python 3.12+, curl
- Install uv (package manager):
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
# Restart your shell so "uv" is on PATH, or follow the installer hint
```

### Run the CLI locally
```bash
# Run on all files
uv run pre-commit run --all-files

# Run on staged files only
uv run pre-commit run
```

### Available Commands

Run `make help` to see all available commands:

```bash
make help
```

## Binary Packaging

The OpenHands CLI can be packaged into a standalone executable binary using PyInstaller. This allows distribution of the CLI without requiring users to install Python or dependencies.

### Building the Executable

#### Quick Build
# Install dependencies (incl. dev tools)
make install-dev

Use the provided build script to create a standalone executable:
# Optional: install pre-commit hooks
make install-pre-commit-hooks

```bash
# Using shell script (recommended - handles installation automatically)
./build.sh --install-pyinstaller

# Using Python script directly (requires PyInstaller to be pre-installed)
uv run python build.py
# Start the CLI
make run
# or
uv run openhands-cli
```

#### Manual Build

You can also build manually using PyInstaller with uv:

Tip: Set your model key (one of) so the agent can talk to an LLM:
```bash
# Install PyInstaller as dev dependency
uv add --dev pyinstaller

# Build using the spec file
uv run pyinstaller openhands-cli.spec --clean
export OPENAI_API_KEY=...
# or
export LITELLM_API_KEY=...
```

### Build Options

The build script supports several options:

### Build a standalone executable
```bash
# Install PyInstaller and build (shell script handles installation)
# Build (installs PyInstaller if needed)
./build.sh --install-pyinstaller

# Build without testing the executable
./build.sh --install-pyinstaller --no-test

# Build without cleaning previous artifacts
./build.sh --install-pyinstaller --no-clean

# Use a custom spec file
./build.sh --install-pyinstaller --spec custom.spec

# Show help
./build.sh --help
# The binary will be in dist/
./dist/openhands-cli # macOS/Linux
# dist/openhands-cli.exe # Windows
```

**Note:** The shell script (`build.sh`) automatically handles PyInstaller installation when using the `--install-pyinstaller` flag. The Python script (`build.py`) can be used directly but requires PyInstaller to be pre-installed.

### Output

The build process creates:
- `dist/openhands-cli` - The standalone executable
- `build/` - Temporary build files (automatically cleaned)

The executable is typically 10-15 MB and includes all necessary dependencies.

### Testing the Executable

The build script automatically tests the executable, but you can also test manually:

```bash
# Run the executable
./dist/openhands-cli

# Check that it displays the CLI interface
```

### Packaging Configuration

The packaging is configured through:
- `openhands-cli.spec` - PyInstaller specification file
- `build.py` - Build automation script
- `build.sh` - Shell wrapper script

The spec file is optimized for:
- Single-file executable
- Minimal size through exclusions
- All required dependencies included
- Console application mode
For advanced development (adding deps, updating the spec file, debugging builds), see Development.md.