CI Coverage

OpenClaw-env-manager is a Python CLI for defining an OpenClaw agent environment in one declarative openclawenv.toml file and turning it into deterministic Docker artifacts.

When run without arguments, the CLI opens an interactive terminal menu for bot management.

It is inspired by Poetry's manifest-plus-lock workflow:

  • openclawenv.toml describes intent
  • openclawenv.lock captures deterministic build inputs
  • clawopenenv scan runs an optional preflight security scan for materialized skills
  • clawopenenv export dockerfile renders a standalone Dockerfile
  • clawopenenv export compose renders a bot-specific docker-compose file
  • clawopenenv build builds the image and enforces a build-time skill scan gate

Table Of Contents

CI And Coverage

GitHub Actions runs the test suite for every push to main, every pull request, and on manual dispatch. A separate coverage job runs the tests under coverage.py, uploads the raw reports as workflow artifacts, validates the MkDocs build, and publishes the generated MkDocs site to GitHub Pages for pushes to main. The same deployed Pages site also contains the HTML coverage report plus the generated coverage badge.

Once GitHub Pages is enabled for the repository with Build and deployment configured to GitHub Actions, the published docs site is available at fipciu1996.github.io/OpenClaw-env-manager/, while the coverage report stays under fipciu1996.github.io/OpenClaw-env-manager/coverage/.

Releases And PyPI

Package publication to PyPI is handled by .github/workflows/publish-pypi.yml.

The release workflow is intentionally narrow:

  • it runs only on pushed release tags matching 1.2.3 or v1.2.3
  • it verifies that the tag version matches [project].version in pyproject.toml
  • it builds both sdist and wheel
  • it checks the generated distributions with twine
  • it publishes to PyPI through Trusted Publishing with GitHub OIDC

Example release tag:

make install-hooks
make release-tag VERSION=1.0.1 TAG_MESSAGE="OpenClaw-env-manager 1.0.1"
git push origin 1.0.1

Git does not provide a native pre-tag hook, so OpenClaw-env-manager uses a practical replacement:

  • python .github/scripts/create_release_tag.py <tag> or make release-tag VERSION=<tag> updates pyproject.toml and CHANGELOG.md, creates a release commit, and only then creates the annotated tag
  • .githooks/pre-push verifies that every pushed release tag still matches the package version and blocks the push when they diverge
  • changelog entries are managed through changelog-cli, which is installed as part of .[dev]

To activate the repository-managed hooks locally:

make install-hooks

Useful changelog-cli commands:

changelog entry added --message "Describe a new feature"
changelog entry changed --message "Describe a behavior change"
changelog entry fixed --message "Describe a bug fix"
changelog current

Once the package is published, installation from PyPI is:

python -m pip install OpenClaw-env-manager

On Debian and Ubuntu systems with PEP 668 enabled, direct installation into the system Python may fail with externally-managed-environment. The safest installation options for the published CLI are:

  1. pipx for a standalone CLI install:
apt update
apt install -y pipx python3-venv
pipx install OpenClaw-env-manager
~/.local/bin/clawopenenv --help
  1. virtualenv for an isolated Python environment:
apt update
apt install -y python3-venv
python3 -m venv /opt/openclaw-env-manager
source /opt/openclaw-env-manager/bin/activate
pip install -U pip
pip install OpenClaw-env-manager
clawopenenv --help

The installed console command is:

clawopenenv

Before the first release, configure a PyPI Trusted Publisher for:

  • owner: fipciu1996
  • repository: OpenClaw-env-manager
  • workflow: .github/workflows/publish-pypi.yml

Documentation

Project documentation is generated with MkDocs + mkdocstrings and uses the mkdocs-shadcn theme. The docs/ directory holds narrative pages, while the API reference is generated directly from the internal Python package implementation. The MkDocs config also uses a small local hook so the shadcn theme does not require global Git safe.directory changes just to build docs.

The docs also include a dedicated reference page for the generated openclawenv.toml structure, including the top-level sections, field meanings, and managed-bot file layout.

Install the docs toolchain:

python -m pip install -e .[docs]

Build the docs locally:

python -m mkdocs build --strict

Run the local preview server:

python -m mkdocs serve

Equivalent make shortcuts:

make install-docs
make docs-build
make docs-serve

The latest documentation is also published from GitHub Actions directly through the repository's GitHub Pages workflow on pushes to main.

Versioned documentation publishing remains configured for GitLab Pages in .gitlab-ci.yml. The GitLab deployment model is:

  • default branch: published at the root Pages URL
  • other branches: published under branch-<ref-slug>/
  • tags: published under tag-<ref-slug>/

This setup uses GitLab Pages parallel deployments through pages.path_prefix. According to the current GitLab documentation, that feature is available on GitLab Premium and Ultimate. Branch previews are configured to expire after 30 days, while the default-branch and tag deployments are kept indefinitely.

Host Prerequisites

Before using OpenClaw-env-manager on a workstation or CI runner, install:

  • Docker with docker compose support
  • Python 3.12+ with pip
  • optionally git
  • optionally make on Linux/macOS if you want to use the provided Makefile

Quick verification:

docker version
docker compose version
python --version
python -m pip --version

Expected result: Docker CLI is available, docker compose works, and Python is at least 3.12.

Windows

  1. Install Docker Desktop for Windows: official Docker Desktop for Windows guide.
  2. Prefer the WSL 2 backend. Docker's current documentation requires WSL 2.1.5+ and a supported Windows 10/11 build.
  3. Install Python 3.12+ from python.org/downloads or through the Python Install Manager described in the official Windows documentation.
  4. Restart the terminal and verify:
wsl --version
docker version
docker compose version
python --version

macOS

  1. Install Docker Desktop for Mac: official Docker Desktop for Mac guide.
  2. Install Python 3.12+ from python.org/downloads. The official macOS installer is a universal2 build and works on both Apple Silicon and Intel Macs.
  3. See the official Python on macOS guide for installer details and shell path setup.
  4. Verify:
docker version
docker compose version
python3 --version
python3 -m pip --version

Linux

  1. Install Docker Engine from the official Docker Engine install overview and pick your distribution-specific page there. If you prefer Docker Desktop and your distro is supported, see the official Docker Desktop for Linux guide.
  2. For common distros, Docker maintains dedicated instructions for Ubuntu and Debian, and the install overview links the rest of the supported platforms.
  3. Check whether your distro already ships Python 3.12+:
python3 --version
  1. If your distro Python is older than 3.12, use a newer distro package or install CPython from the latest source release published on python.org/downloads, following the official Unix installation guide.
  2. Verify:
docker version
docker compose version
python3 --version
python3 -m pip --version

Notes

  • OpenClaw-env-manager assumes a Docker environment with Compose available as docker compose.
  • On Linux, the Python executable is often python3 rather than python.
  • Docker Desktop licensing can require a paid subscription in larger commercial organizations; check Docker's current terms before rolling it out company-wide.

V1 Scope

OpenClaw-env-manager v1 is intentionally narrow:

  • OpenClaw-first
  • Python-first
  • one inline manifest
  • Docker image output
  • secret references only
  • no session or auth state snapshotting

The current locker accepts exact Python requirements only:

  • package==version
  • name @ URL

It also accepts exact Node.js requirements only:

  • package@version
  • @scope/package@version

That constraint keeps the lockfile deterministic without shipping a full Python dependency resolver in v1.

OpenClaw-env-manager can also integrate with Cisco's Skill Scanner, which the upstream project describes as a best-effort scanner for agent skills with static, behavioral, and optional LLM-based analysis.

Five catalog skills are treated as always installed defaults across manifests, managed bots, and generated images:

  • deus-context-engine
  • self-improving-agent
  • skill-security-review
  • freeride (free-ride inside the workspace)
  • agent-browser-clawdbot

Security Notes

OpenClaw-env-manager follows a secure-by-default model, but it does not silently override explicit operator intent. Secure defaults are applied to newly generated manifests and artifacts, while consciously weaker settings remain available and are surfaced as non-blocking security advisories.

Existing default mechanisms include:

  • read_only_root = true for newly generated OpenClaw sandbox configuration
  • localhost-only binds for generated gateway and bridge ports
  • cap_drop: [ALL], no-new-privileges:true, read-only root filesystems, tmpfs, pids_limit, and ulimits in generated Compose services
  • sidecar .env files for secrets so sensitive values are not baked into images
  • build-time and preflight skill scanning with cisco-ai-skill-scanner
  • mandatory baseline skills that keep operational and security guardrails present
  • warnings when the operator chooses riskier settings such as wildcard tool policies, shell_command allowlists, unpinned base images, public host binds, or writable root filesystems

The default image/runtime baseline also includes a fixed starter set of skills and tools:

  • mandatory skills: deus-context-engine, self-improving-agent, skill-security-review, freeride, and agent-browser-clawdbot
  • default tooling in the image: chromium, node, npm, npx, agent-browser, and cisco-ai-skill-scanner

That baseline is meant to make generated images immediately usable for OpenClaw execution, browser automation, and skill security checks, while still allowing the operator to add more Python, Node.js, and system dependencies through the manifest.

Important boundary:

  • these defaults reduce common mistakes, but they do not replace host-level hardening. Docker daemon access, docker.sock mounts, firewalling, rootless Docker, user namespaces, seccomp/AppArmor/SELinux, and patch management still need to be handled operationally.

The baseline is aligned with the OWASP Cheat Sheet Series, especially the Docker Security Cheat Sheet and the AI Agent Security Cheat Sheet. There is also a dedicated Security Notes page in this documentation set.

Manifest Shape

openclawenv.toml contains five top-level sections:

  • project
  • runtime
  • agent
  • skills
  • openclaw

Example:

schema_version = 1

[project]
name = "ops-agent"
version = "1.2.3"
description = "Deterministic OpenClaw image for operations support"
runtime = "openclaw"

[runtime]
base_image = "python:3.12-slim"
python_version = "3.12"
system_packages = ["git", "curl", "chromium"]
python_packages = ["requests==2.32.3", "rich==13.9.4"]
node_packages = ["typescript@5.8.3"]
env = { PYTHONUNBUFFERED = "1" }
user = "agent"
workdir = "/workspace"

[[runtime.secret_refs]]
name = "OPENAI_API_KEY"
source = "env:OPENAI_API_KEY"
required = true

[agent]
agents_md = """# Agent Contract"""
soul_md = """# Soul"""
user_md = """# User"""
memory_seed = ["Remember the operating model."]

[[skills]]
name = "incident-brief"
description = "Prepare concise incident reports."
content = """
---
name: incident-brief
description: Prepare concise incident reports.
---
"""

[openclaw]
agent_id = "main"
agent_name = "Operations Agent"

[openclaw.sandbox]
mode = "workspace-write"
scope = "session"
workspace_access = "full"
network = "bridge"
read_only_root = true

The agent section supports both inline markdown content and relative .md file references. For example, agents_md = "AGENTS.md" will load AGENTS.md from the same directory as openclawenv.toml.

Even if they are not declared manually, OpenClaw-env-manager normalizes manifests so that deus-context-engine, self-improving-agent, skill-security-review, freeride, and agent-browser-clawdbot remain present in the effective skill set. openenv init writes them explicitly into the starter manifest.

Security-sensitive defaults are also generated automatically: - read_only_root = true for the OpenClaw sandbox by default - explicit openclaw.tools.allow / deny lists by default, while risky wildcard or broad tool scopes remain possible as explicit operator choices and are surfaced as security warnings - localhost-only host port bindings in generated Compose files - cap_drop: [ALL], no-new-privileges, read-only root filesystems, tmpfs, and process/file descriptor limits in generated Compose services

These defaults are intentionally aligned with the OWASP Cheat Sheet Series, especially the official Docker Security Cheat Sheet and AI Agent Security Cheat Sheet. OpenClaw-env-manager uses them as the baseline for generated images, Compose stacks, tool scoping, and agent runtime guardrails. The project keeps a secure-by-default posture without silently overriding explicit operator intent: if a manifest or runtime override weakens the baseline, validate, export, and build flows emit clear non-blocking security warnings instead of preventing the change outright.

CLI

Create a starter manifest:

clawopenenv init

Open the interactive bot menu:

clawopenenv

Validate the manifest:

clawopenenv validate

Generate the lockfile:

clawopenenv lock

Run a skill security scan:

clawopenenv scan -- --policy strict --fail-on-severity high

Build the image with a stricter build-time scan policy:

clawopenenv build --scan-policy strict --scan-fail-on-severity medium

Export the Dockerfile:

clawopenenv export dockerfile --output Dockerfile

Export the bot compose file:

clawopenenv export compose

clawopenenv export compose also writes a sibling Dockerfile, so the generated compose bundle can rebuild the bot image locally without any extra wiring.

Build the image:

clawopenenv build

clawopenenv build also writes a compose file named after the bot, for example docker-compose-operations-agent.yml, next to the manifest. When runtime.base_image is not pinned with @sha256, OpenClaw-env-manager first checks for the image locally and automatically tries docker image pull <image> if it is missing before failing lock generation.

Module-oriented execution is also available through:

python -m clawopenenv

Makefile

Common workflows are also available through Makefile targets:

make install
make install-dev
make install-scan
make test
make coverage
make coverage-html
make menu
make validate
make lock
make scan SCAN_ARGS="-- --policy strict --fail-on-severity high"
make dockerfile
make compose
make build

You can override defaults, for example:

make lock MANIFEST=examples/demo.openclawenv.toml LOCKFILE=examples/demo.openclawenv.lock
make dockerfile DOCKERFILE=build/Dockerfile
make build TAG=openclawenv/demo:dev

Interactive Bot Menu

Running clawopenenv without parameters opens a menu that lets you:

  • choose Polish or English as the interface language on entry
  • list managed bots
  • from the bot selection screen, generate a shared stack at bots/all-bots-compose.yml with one gateway and one bot service per managed bot
  • open a listed bot and generate openclawenv.lock, Dockerfile, and bot-specific docker-compose artifacts
  • open a listed bot and improve its *.md documents through OpenRouter tool calling, with the resulting markdown normalized to consistent English
  • list running bots launched from bots/<bot-slug>/docker-compose-*.yml
  • open a running bot and preview recent container logs
  • open a running bot and create a skill snapshot, which inspects installed skills in the running container and updates openclawenv.toml with any new discoveries
  • add a new bot by answering interactive questions about role, skill sources, dependencies, secrets, sites, and databases
  • the interactive skill prompt only asks for additional skills, because deus-context-engine, self-improving-agent, skill-security-review, freeride, and agent-browser-clawdbot are always included automatically
  • edit an existing bot and rewrite its stored manifest data
  • delete an existing bot together with its stored manifest data

Managed bots are stored under bots/<bot-slug>/openclawenv.toml. For bots created from the interactive menu, secret refs are stored in bots/<bot-slug>/.env instead of [[runtime.secret_refs]] blocks inside the manifest. Agent documents are stored as sibling markdown files such as bots/<bot-slug>/AGENTS.md, SOUL.md, USER.md, IDENTITY.md, TOOLS.md, and memory.md, while the manifest keeps only relative references to those files. The OpenRouter-backed document improvement action looks for OPENROUTER_API_KEY in the system environment first and then in the project root .env. If the key is missing and the action is selected, the menu prompts for it and writes OPENROUTER_API_KEY=... to the project root .env.

Generated Image Contents

The generated image writes:

  • the OpenClaw gateway/runtime itself by building on top of alpine/openclaw:main, so the resulting image can actually run node dist/index.js gateway
  • the OpenClaw workspace files such as AGENTS.md, SOUL.md, and USER.md
  • inline skills under <workspace>/skills/<skill-name>/
  • a generated openclaw.json
  • copies of openclawenv.toml and openclawenv.lock under /opt/openclawenv
  • Python plus Node.js tooling available in the image, including node, npm, and npx
  • exact runtime.node_packages installed globally with npm install --global
  • the agent-browser CLI installed globally by default, followed by agent-browser install during image build so the browser runtime is prepared
  • the cisco-ai-skill-scanner==2.0.4 CLI installed in the image for in-container skill scanning
  • Python packages installed into an image-local virtual environment under /opt/openclawenv/.venv, which keeps Docker builds compatible with PEP 668 system Python protections
  • the freeride skill installed from ClawHub into the real OpenClaw workspace and exposed through ~/.openclaw -> /opt/openclaw, so freeride auto updates the same openclaw.json used by the container
  • a build-time skill-scanner scan-all gate against <workspace>/skills, using balanced policy and failing on high severity by default

runtime.base_image is still preserved and pinned in openclawenv.lock, but it is used as the sandbox/agent image inside the generated openclaw.json, not as the outer gateway container base.

The tool can also generate a bot-specific OpenClaw-style compose file with openclaw-gateway and openclaw-cli services, host-mounted config/workspace directories, and a bot-specific env file such as .operations-agent.env. The gateway service includes a build: section that rebuilds the local image from the adjacent generated Dockerfile, and both services use the resulting tag through OPENCLAW_IMAGE. When a canonical sidecar bots/<bot-slug>/.env file exists, its secret values are merged into the generated compose env file together with OpenClaw defaults such as image tag, ports, bind mode, and workspace paths. The generated openclaw-cli service stays alive with an idle entrypoint by default, so docker compose up -d does not exit immediately into the OpenClaw help screen; run interactive commands with docker compose exec openclaw-cli openclaw ....

When clawopenenv scan is used, the CLI materializes skills to a temporary directory and runs skill-scanner scan-all ... --recursive against that tree as a local preflight check. During docker build, the generated Dockerfile also runs skill-scanner scan-all <workspace>/skills --recursive --check-overlap, so the image build fails when findings meet the configured severity threshold. For already running bot containers, the interactive menu can also create a skill snapshot by inspecting <workspace>/skills inside the container and merging any newly discovered skills back into the bot manifest. When freeride is present, the Docker build also runs npx clawhub@latest install free-ride before the skill scan gate. For manual local installation inside an existing OpenClaw workspace, use:

npx clawhub@latest install free-ride
cd ~/.openclaw/workspace/skills/free-ride
pip install -e .

After container start, set OPENROUTER_API_KEY and run freeride auto followed by openclaw gateway restart if you want FreeRide to rewrite the active OpenClaw model configuration. By default, Docker builds also run npm install -g agent-browser and agent-browser install to prepare browser automation, while the mandatory agent-browser-clawdbot skill documents how agents should use that tool. When using the exported Dockerfile directly, you can override the defaults with Docker build args such as OPENCLAWENV_SKILL_SCAN_POLICY=strict, OPENCLAWENV_SKILL_SCAN_FORMAT=json, and OPENCLAWENV_SKILL_SCAN_FAIL_ON_SEVERITY=medium. Use --keep-artifacts if you want to inspect the materialized skill bundle in .openclawenv-scan/.

Example GitHub Actions step for the exported Dockerfile:

- name: Build OpenClaw-env-manager image with skill scan gate
  run: |
    docker build \
      --file Dockerfile \
      --tag openclawenv/agent:ci \
      --build-arg OPENCLAWENV_SKILL_SCAN_POLICY=strict \
      --build-arg OPENCLAWENV_SKILL_SCAN_FAIL_ON_SEVERITY=medium \
      .

Secrets are never baked into the image. Sensitive values must be supplied at runtime through the generated .<bot-name>.env file.

Tests

Run the built-in unittest suite:

python -m unittest discover -s tests -t . -v

Generate a terminal coverage report:

python -m coverage run -m unittest discover -s tests -t . -v
python -m coverage report -m

Generate the HTML report under htmlcov/:

make coverage-html