From b1d6cc68b2b71fb1049fec0c5daa13b226a2fdbd Mon Sep 17 00:00:00 2001 From: Adam Banky Date: Mon, 12 Jan 2026 02:22:49 +0100 Subject: [PATCH] fix(runtime): add missing AGENT_ID environment variables to watcher services Watcher containers were failing to start with error: "AGENT_ID environment variable is required" The docker-compose.yml template was missing the AGENT_ID environment variable for all six watcher services. The run_watcher.py script requires this variable to identify which agent it should run. Changes: - Added AGENT_ID environment variable to all watcher services in docker-compose template with correct values (meta, architect, openapi, ui, integration, test) - Updated troubleshooting documentation with error description and resolution steps - Added regression test to validate AGENT_ID is set for all watcher services Fixes issue where all agent watchers would exit immediately on startup. --- docs/troubleshooting.md | 17 +++++--- src/weft/templates/docker-compose.yml | 36 +++++++++++++++++ tests/unit/weft/cli/test_runtime.py | 58 +++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 5 deletions(-) diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index ee1b1ee..82bc7d8 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -59,22 +59,29 @@ Ensure you are running commands from the project root. ### API key not detected -**Problem** -Weft reports that no API key is available. +**Problem** +Docker Compose warns: `The "ANTHROPIC_API_KEY" variable is not set` **Fix** +1. **Create .env file in project root:** ```bash -export ANTHROPIC_API_KEY=sk-ant-... +echo "ANTHROPIC_API_KEY=sk-ant-your-key" > .env ``` -Restart the runtime after setting the key: +2. **Or export in shell:** +```bash +export ANTHROPIC_API_KEY=sk-ant-your-key +``` +3. **Restart the runtime:** ```bash weft down weft up ``` +**Note:** After running `weft init`, `.weft/.env.weft.common` should exist. If missing, run `weft init --force` to regenerate. + --- ### Invalid configuration @@ -146,7 +153,7 @@ Most commonly caused by missing API keys or Docker misconfiguration. ### Agents are not processing work -**Problem** +**Problem** Agents start but no output is produced. **Fix** diff --git a/src/weft/templates/docker-compose.yml b/src/weft/templates/docker-compose.yml index 9482ff2..c9c9599 100644 --- a/src/weft/templates/docker-compose.yml +++ b/src/weft/templates/docker-compose.yml @@ -24,6 +24,12 @@ services: watcher-meta: <<: *watcher-common container_name: weft-watcher-meta + environment: + - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + - WEFT_ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + - WEFT_CODE_REPO_PATH=${CODE_REPO_PATH:-/tmp} + - WEFT_AI_HISTORY_PATH=${AI_HISTORY_PATH:-/tmp} + - AGENT_ID=meta env_file: - .env.weft.common - agents/00-meta/.env @@ -32,6 +38,12 @@ services: watcher-architect: <<: *watcher-common container_name: weft-watcher-architect + environment: + - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + - WEFT_ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + - WEFT_CODE_REPO_PATH=${CODE_REPO_PATH:-/tmp} + - WEFT_AI_HISTORY_PATH=${AI_HISTORY_PATH:-/tmp} + - AGENT_ID=architect env_file: - .env.weft.common - agents/01-architect/.env @@ -40,6 +52,12 @@ services: watcher-openapi: <<: *watcher-common container_name: weft-watcher-openapi + environment: + - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + - WEFT_ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + - WEFT_CODE_REPO_PATH=${CODE_REPO_PATH:-/tmp} + - WEFT_AI_HISTORY_PATH=${AI_HISTORY_PATH:-/tmp} + - AGENT_ID=openapi env_file: - .env.weft.common - agents/02-openapi/.env @@ -48,6 +66,12 @@ services: watcher-ui: <<: *watcher-common container_name: weft-watcher-ui + environment: + - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + - WEFT_ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + - WEFT_CODE_REPO_PATH=${CODE_REPO_PATH:-/tmp} + - WEFT_AI_HISTORY_PATH=${AI_HISTORY_PATH:-/tmp} + - AGENT_ID=ui env_file: - .env.weft.common - agents/03-ui/.env @@ -56,6 +80,12 @@ services: watcher-integration: <<: *watcher-common container_name: weft-watcher-integration + environment: + - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + - WEFT_ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + - WEFT_CODE_REPO_PATH=${CODE_REPO_PATH:-/tmp} + - WEFT_AI_HISTORY_PATH=${AI_HISTORY_PATH:-/tmp} + - AGENT_ID=integration env_file: - .env.weft.common - agents/04-integration/.env @@ -64,6 +94,12 @@ services: watcher-test: <<: *watcher-common container_name: weft-watcher-test + environment: + - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + - WEFT_ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + - WEFT_CODE_REPO_PATH=${CODE_REPO_PATH:-/tmp} + - WEFT_AI_HISTORY_PATH=${AI_HISTORY_PATH:-/tmp} + - AGENT_ID=test env_file: - .env.weft.common - agents/05-test/.env diff --git a/tests/unit/weft/cli/test_runtime.py b/tests/unit/weft/cli/test_runtime.py index d20c887..ff90f06 100644 --- a/tests/unit/weft/cli/test_runtime.py +++ b/tests/unit/weft/cli/test_runtime.py @@ -3,6 +3,7 @@ from pathlib import Path from unittest.mock import Mock, patch +import yaml from click.testing import CliRunner from weft.cli.runtime import down, logs, up @@ -542,3 +543,60 @@ def test_logs_from_subdirectory( # Verify docker compose was called with correct path call_args = mock_run.call_args[0][0] assert "-f" in call_args + + +class TestDockerComposeTemplate: + """Tests for docker-compose.yml template validation.""" + + def test_template_includes_agent_id_for_all_services(self): + """Test that docker-compose template has AGENT_ID set for all watcher services.""" + # Read the docker-compose template + template_path = ( + Path(__file__).parent.parent.parent.parent.parent + / "src" + / "weft" + / "templates" + / "docker-compose.yml" + ) + assert template_path.exists(), f"Template not found at {template_path}" + + with open(template_path) as f: + compose_config = yaml.safe_load(f) + + # Expected agents and their AGENT_ID values + expected_agents = { + "watcher-meta": "meta", + "watcher-architect": "architect", + "watcher-openapi": "openapi", + "watcher-ui": "ui", + "watcher-integration": "integration", + "watcher-test": "test", + } + + # Verify each service has AGENT_ID environment variable + for service_name, expected_agent_id in expected_agents.items(): + assert ( + service_name in compose_config["services"] + ), f"Service {service_name} not found in template" + + service = compose_config["services"][service_name] + assert "environment" in service, f"Service {service_name} missing environment section" + + env_list = service["environment"] + assert isinstance( + env_list, list + ), f"Service {service_name} environment should be a list" + + # Check if AGENT_ID is in the environment list + agent_id_found = False + for env_var in env_list: + if isinstance(env_var, str) and env_var.startswith("AGENT_ID="): + agent_id_value = env_var.split("=", 1)[1] + assert agent_id_value == expected_agent_id, ( + f"Service {service_name} has AGENT_ID={agent_id_value}, " + f"expected AGENT_ID={expected_agent_id}" + ) + agent_id_found = True + break + + assert agent_id_found, f"Service {service_name} missing AGENT_ID environment variable"