# Oduflow

> AI-first Odoo development and CI tool powered by reusable database templates. Provisions isolated, ephemeral Odoo environments on Docker — one per git branch — and exposes them to AI coding agents via MCP.

## Installation

### System Requirements

- Docker (Docker Engine or Docker Desktop)
- Python 3.10+
- Git
- fuse-overlayfs (for filestore overlay mounting; not needed on macOS)

### Install

Recommended — install via [uv](https://docs.astral.sh/uv/):

```bash
uv tool install oduflow
```

Alternative — install via pip:

```bash
pip install oduflow
```

### Configure

All settings are configured via `oduflow.toml` (searched in `/etc/oduflow/` then `~/.oduflow/`, or set `ODUFLOW_TOML`).

Minimal configuration:

```toml
[team.1]
hostname = "localhost"
```

Full configuration reference:

```toml
[server]
host = "0.0.0.0"                     # HTTP bind address
port = 8000                           # HTTP port

[routing]
mode = "port"                         # "port" | "traefik" (auto-HTTPS)
# acme_email = "admin@example.com"    # required for traefik mode

[oauth]
# oauth_base_url = "https://oduflow.example.com"  # enable self-hosted OAuth (for Claude.ai); auth_token = client_id = client_secret = access token

[database]
user = "odoo"
password = "odoo"                     # auto-generated on first init; set to override
image = "postgres:15"

[storage]
# data_dir = "/srv/oduflow"           # default: /srv/oduflow or ~/.oduflow/data
overlay_threshold_mb = 50             # filestore size threshold for overlay vs copy

[lifecycle]
auto_stop_hours = 48                  # auto-stop after N hours without MCP/dashboard work; 0 disables
auto_delete_hours = 0                 # auto-delete N hours after stop; 0 disables (opt-in; DESTRUCTIVE)

# Per-team coding agent (dashboard Agent Chat / Agent CLI); opt-in, off by default.
# [agent]
# image = "oduist/oduflow-coder:latest"

[team.1]
hostname = "localhost"
auth_token = ""                       # MCP bearer token (empty = auth disabled)
ui_password = ""                      # Web UI password (empty = UI open)
port_range = [50000, 50100]           # port range for Odoo containers
# agent_enabled = false               # enable the per-team coding agent (Agent Chat / Agent CLI)
# agent_default = "claude"            # "claude" | "codex" — default agent for consoles/chats
# [team.1.agent_env]                  # provider credentials injected into the agent container
# CLAUDE_CODE_OAUTH_TOKEN = ""
# ANTHROPIC_API_KEY = ""
# OPENAI_API_KEY = ""
```

### Initialize

No separate init step is needed. On first launch Oduflow automatically creates a default `oduflow.toml` (if none exists) and initializes shared infrastructure (Docker network, PostgreSQL, team directories). Just start the server (below).

### Upgrade

```bash
uv tool upgrade oduflow
```

During upgrade, bundled files are overwritten. Add `# KEEP` as the first line of any customized file to prevent it from being overwritten.

### Set up a template

```bash
# From scratch
oduflow init-template --odoo-image odoo:19.0 --template-name default

# From production dump
# Place dump.sql and filestore/ into {data_dir}/team_1/templates/default/ then:
oduflow reload-template default

# Sync template from S3 or local path and reload DB
oduflow reload-template default --source s3://mybucket/prod/ [--quiet]
oduflow reload-template default --source /backups/prod-latest/
```

### Start the MCP server

```bash
oduflow
```

The server starts on `http://0.0.0.0:8000`. MCP endpoint: `http://<host>:8000/mcp`.

## MCP Client Configuration

### Cursor / Windsurf

`.cursor/mcp.json` or `.windsurf/mcp.json`:

```json
{
  "mcpServers": {
    "oduflow": {
      "type": "http",
      "url": "https://<your-oduflow-host>/mcp",
      "headers": {
        "Authorization": "Bearer <your-token>"
      }
    }
  }
}
```

### Claude Desktop / Amp

Same JSON format in `claude_desktop_config.json` or `.amp/settings.json`.

### Claude.ai (self-hosted OAuth)

For OAuth-based MCP clients like Claude.ai Remote MCP, set `[oauth].oauth_base_url` to this instance's public URL. Oduflow then runs its own OAuth 2.1 Authorization Server (no external IdP). In Claude.ai add a custom MCP at `https://<your-oduflow-host>/mcp` and enter the team's `auth_token` as **both** Client ID and Client Secret. The issued access token equals the `auth_token`, so the same value also works as a plain Bearer token.

## Core MCP Tools

- `create_environment` — provision a new Odoo environment for a branch (optional `env_vars` injects container environment variables)
- `delete_environment` — tear down an environment
- `start_environment` / `stop_environment` / `restart_environment` — lifecycle control
- Idle environments auto-stop after 48h without work (`[lifecycle].auto_stop_hours`). Auto-delete of long-stopped environments is opt-in and off by default (`auto_delete_hours = 0`; set a positive value to enable — destructive; protected environments are exempt). Container-level tools (pull_and_apply, shell/tests/installs/file ops) wake a stopped environment automatically and note it in the response
- `update_environment` — re-create the container preserving DB and filestore (optional `odoo_image` switches image, `env_vars` replaces container environment variables)
- `install_odoo_modules` — install Odoo modules
- `upgrade_odoo_modules` — upgrade Odoo modules
- `run_odoo_tests` — run Odoo tests for specific modules
- `pull_and_apply` — pull latest code and auto-install/upgrade/restart as needed
- `get_environment_logs` — retrieve container logs
- `run_odoo_command` — execute shell commands inside the Odoo container
- `run_odoo_shell` — execute Python code in the Odoo shell with full ORM access
- `read_file_in_odoo` — read a text file or list a directory inside the container (supports line ranges)
- `write_file_in_odoo` — write a text file inside the container (CSV imports, scripts, configs)
- `search_in_odoo` — search for a pattern (fixed-string grep) in files inside the container
- `http_request_to_odoo` — make an HTTP request to the running Odoo instance (controllers, JSON-RPC, REST)
- `list_installed_modules` — list Odoo modules and their states with name/state filtering
- `run_db_query` — execute SQL queries against the environment's PostgreSQL database
- `reset_admin_password` — reset the admin user password (default: "test")
- `read_output` — read from a cached tool output by ID (paginate, grep, errors, tail)
- `list_environments` / `get_environment_info` — inspect environments
- `create_service` / `delete_service` / `restart_service` / `update_service` / `list_services` / `get_service_info` / `get_service_logs` / `run_service_command` — manage auxiliary services
- `create_volume` / `list_volumes` / `inspect_volume` / `delete_volume` — manage Docker volumes
- `read_file_in_volume` / `write_file_in_volume` / `search_in_volume` / `delete_file_in_volume` — manage files inside Docker volumes
- `list_service_presets` / `restore_service` / `delete_service_preset` — manage service presets
- `save_as_template` / `delete_template` / `list_templates` — template management
- `import_template_from_odoo` — import a template from a running Odoo instance
- `refresh_template` — re-apply a template's filestore to live overlay environments (preserves env changes by default; `reset_env_changes=True` is destructive)
- `setup_repo_auth` — cache git credentials for private repositories
- `add_extra_repo` / `list_extra_repos` / `update_extra_repo` / `delete_extra_repo` — manage extra addons repositories
- `get_agent_instructions` — get AI agent instructions for using Oduflow
- `get_odoo_development_guide` — get Odoo development standards guide for a specific version (15–19)

## Coding Agent (hosting)

An opt-in, per-team hosting feature: Oduflow runs one coding-agent container per team (`oduist/oduflow-coder`, Claude Code + OpenAI Codex) and exposes two dashboard surfaces — **Agent CLI** (the agent's TUI in the browser) and **Agent Chat** (a browser ACP chat with durable per-environment sessions). The agent edits its own git checkout, `git push`es, and drives the environment only through the Oduflow MCP server with a scoped per-environment token. It is off by default; enable it per team with `agent_enabled` and set provider credentials under `[team.X.agent_env]`. The agent UI is hidden for live-mount (`local_path`) environments.

## Typical Agent Workflow

1. Call `list_environments` to check if an environment for the branch exists
2. If not, call `create_environment` with `branch`, `template_name`, `repo_url`, and `odoo_image`
3. Write code, `git push`, then call `pull_and_apply` (auto-detects what to do)
4. Use `install_odoo_modules` / `run_odoo_tests` / `get_environment_logs` to verify
5. Call `delete_environment` when the task is done

## Links

- Repository: <https://github.com/oduist/oduflow>
- Documentation: <https://docs.oduflow.dev>
- License: BUSL-1.1 (Business Source License 1.1) — free for non-commercial use; commercial use requires a paid license; converts to MPL 2.0 four years after publication
- Website: <https://oduflow.dev>
