From 02e3b426d5091b890755774cbe03108f067166b5 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 23 Nov 2025 19:25:30 +0000 Subject: [PATCH 1/2] Remove file-based config and ensure consistent naming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove from_file() and to_file() methods from MeshBotConfig - Configuration now uses only: defaults → env vars → CLI args - Fix CLI argument naming for consistency: - --meshcore-type → --meshcore-connection-type - --node-name → --meshcore-node-name - Update all documentation and examples to use new CLI args - Update Docker files with new argument names - All tests passing --- AGENTS.md | 10 ++++---- Dockerfile | 2 +- README.md | 57 +++++++++---------------------------------- docker-compose.yml | 6 ++--- src/meshbot/config.py | 33 ------------------------- src/meshbot/main.py | 30 +++++++++++------------ 6 files changed, 35 insertions(+), 103 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index a433b10..946edea 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -221,19 +221,19 @@ pytest tests/ -k "integration" -v ### 4. Local Testing ```bash # Test CLI with mock connection -meshbot test user1 "hello" --meshcore-type mock +meshbot test user1 "hello" --meshcore-connection-type mock # Test with custom prompt file -meshbot test user1 "hello" --custom-prompt my_prompt.txt --meshcore-type mock +meshbot test user1 "hello" --custom-prompt my_prompt.txt --meshcore-connection-type mock # Test with custom node name -meshbot test user1 "hello" --node-name TestBot --meshcore-type mock +meshbot test user1 "hello" --meshcore-node-name TestBot --meshcore-connection-type mock # Run with verbose logging -meshbot run -vv --meshcore-type mock +meshbot run -vv --meshcore-connection-type mock # Run with all options via command-line -meshbot run --node-name MyBot --meshcore-type serial --meshcore-port /dev/ttyUSB0 +meshbot run --meshcore-node-name MyBot --meshcore-connection-type serial --meshcore-port /dev/ttyUSB0 # Run examples python examples/basic_usage.py diff --git a/Dockerfile b/Dockerfile index cd3333c..3f5086b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,7 @@ USER meshbot # Default command (can be overridden) ENTRYPOINT ["meshbot"] -CMD ["run", "--meshcore-type", "mock"] +CMD ["run", "--meshcore-connection-type", "mock"] LABEL org.opencontainers.image.source="https://github.com/ipnet-mesh/meshbot" LABEL org.opencontainers.image.description="AI agent for MeshCore network communication" diff --git a/README.md b/README.md index 2752f1b..871203b 100644 --- a/README.md +++ b/README.md @@ -105,13 +105,13 @@ pip install -e ".[dev]" ```bash # Run with mock connection (for testing) -meshbot test --meshcore-type mock +meshbot test --meshcore-connection-type mock # Run with serial connection -meshbot --meshcore-type serial --meshcore-port /dev/ttyUSB0 +meshbot --meshcore-connection-type serial --meshcore-port /dev/ttyUSB0 # Run with custom prompt file -meshbot --custom-prompt my_prompt.txt --meshcore-type mock +meshbot --custom-prompt my_prompt.txt --meshcore-connection-type mock ``` ### Environment Variables @@ -153,7 +153,7 @@ Run with the custom prompt: ```bash # Via command line -meshbot --custom-prompt my_prompt.txt --meshcore-type mock +meshbot --custom-prompt my_prompt.txt --meshcore-connection-type mock # Via environment variable export CUSTOM_PROMPT_FILE=my_prompt.txt @@ -192,7 +192,7 @@ meshbot 4. **Configuration** (`config.py`) - Environment-based configuration - - JSON file support + - Command-line argument overrides - Validation ### Message Handling @@ -236,48 +236,13 @@ Sent as: ```bash # Interactive testing with mock MeshCore -meshbot test --meshcore-type mock +meshbot test --meshcore-connection-type mock # The test command provides an interactive prompt: # Enter messages to send (or 'quit' to exit) # > Hello! ``` -### Configuration File - -Create `config.json`: - -```json -{ - "meshcore": { - "connection_type": "serial", - "port": "/dev/ttyUSB0", - "baudrate": 115200, - "debug": false, - "auto_reconnect": true - }, - "ai": { - "model": "openai:gpt-4o-mini", - "base_url": null, - "max_tokens": 500, - "temperature": 0.7, - "listen_channel": "0", - "max_message_length": 120 - }, - "memory": { - "storage_path": "logs" - }, - "logging": { - "level": "INFO" - } -} -``` - -Run with config: -```bash -meshbot --config config.json -``` - ### Programmatic Usage ```python @@ -519,13 +484,13 @@ For production use with real MeshCore hardware without Docker: ```bash # Serial connection -meshbot --meshcore-type serial --meshcore-port /dev/ttyUSB0 +meshbot --meshcore-connection-type serial --meshcore-port /dev/ttyUSB0 # TCP connection -meshbot --meshcore-type tcp --meshcore-host 192.168.1.100 +meshbot --meshcore-connection-type tcp --meshcore-host 192.168.1.100 # BLE connection -meshbot --meshcore-type ble --meshcore-address XX:XX:XX:XX:XX:XX +meshbot --meshcore-connection-type ble --meshcore-address XX:XX:XX:XX:XX:XX ``` ### Environment Setup @@ -555,10 +520,10 @@ export LOG_LEVEL=INFO ```bash # Enable verbose logging -meshbot -vv --meshcore-type mock +meshbot -vv --meshcore-connection-type mock # Test with specific prompt -meshbot test --custom-prompt debug_prompt.txt -vv +meshbot test --custom-prompt debug_prompt.txt -vv --meshcore-connection-type mock ``` ### Viewing Logs diff --git a/docker-compose.yml b/docker-compose.yml index 84f8ef8..189395e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,11 +16,11 @@ services: # Optional: Override default command with arguments # Examples: # - Run with serial connection: - # command: ["run", "--meshcore-type", "serial", "--meshcore-port", "/dev/ttyUSB0"] + # command: ["run", "--meshcore-connection-type", "serial", "--meshcore-port", "/dev/ttyUSB0"] # - Run with custom node name and serial connection: - # command: ["run", "--node-name", "MyBot", "--meshcore-type", "serial", "--meshcore-port", "/dev/ttyUSB0", "--meshcore-baudrate", "115200"] + # command: ["run", "--meshcore-node-name", "MyBot", "--meshcore-connection-type", "serial", "--meshcore-port", "/dev/ttyUSB0", "--meshcore-baudrate", "115200"] # - Run with verbose logging: - # command: ["run", "-vv", "--meshcore-type", "serial", "--meshcore-port", "/dev/ttyUSB0"] + # command: ["run", "-vv", "--meshcore-connection-type", "serial", "--meshcore-port", "/dev/ttyUSB0"] # Optional: Set environment variables (alternative to command-line arguments) # environment: diff --git a/src/meshbot/config.py b/src/meshbot/config.py index ed6b753..18d9804 100644 --- a/src/meshbot/config.py +++ b/src/meshbot/config.py @@ -127,39 +127,6 @@ class MeshBotConfig: memory: MemoryConfig = field(default_factory=MemoryConfig) logging: LoggingConfig = field(default_factory=LoggingConfig) - @classmethod - def from_file(cls, config_path: Optional[Path]) -> "MeshBotConfig": - """Load configuration from JSON file.""" - import json - - if not config_path or not config_path.exists(): - return cls() - - with open(str(config_path), "r") as f: - data = json.load(f) - - return cls( - meshcore=MeshCoreConfig(**data.get("meshcore", {})), - ai=AIConfig(**data.get("ai", {})), - memory=MemoryConfig(**data.get("memory", {})), - logging=LoggingConfig(**data.get("logging", {})), - ) - - def to_file(self, config_path: Path) -> None: - """Save configuration to JSON file.""" - import json - - data = { - "meshcore": self.meshcore.__dict__, - "ai": self.ai.__dict__, - "memory": self.memory.__dict__, - "logging": self.logging.__dict__, - } - - config_path.parent.mkdir(parents=True, exist_ok=True) - with open(str(config_path), "w") as f: - json.dump(data, f, indent=2) - def validate(self) -> None: """Validate configuration.""" # Validate MeshCore config diff --git a/src/meshbot/main.py b/src/meshbot/main.py index d53c955..34699cf 100644 --- a/src/meshbot/main.py +++ b/src/meshbot/main.py @@ -58,11 +58,11 @@ def cli() -> None: "--max-message-length", type=int, help="Maximum message length in characters" ) @click.option( - "--meshcore-type", + "--meshcore-connection-type", type=click.Choice(["mock", "serial", "tcp", "ble"]), help="MeshCore connection type", ) -@click.option("--node-name", help="Node name to advertise on the mesh network") +@click.option("--meshcore-node-name", help="Node name to advertise on the mesh network") @click.option("--meshcore-port", help="Serial port for MeshCore connection") @click.option("--meshcore-host", help="TCP host for MeshCore connection") @click.option("--meshcore-address", help="BLE address for MeshCore connection") @@ -91,8 +91,8 @@ def run( model: Optional[str], listen_channel: Optional[str], max_message_length: Optional[int], - meshcore_type: Optional[str], - node_name: Optional[str], + meshcore_connection_type: Optional[str], + meshcore_node_name: Optional[str], meshcore_port: Optional[str], meshcore_host: Optional[str], meshcore_address: Optional[str], @@ -135,10 +135,10 @@ def run( app_config.ai.custom_prompt_file = custom_prompt # MeshCore configuration - if meshcore_type: - app_config.meshcore.connection_type = meshcore_type - if node_name: - app_config.meshcore.node_name = node_name + if meshcore_connection_type: + app_config.meshcore.connection_type = meshcore_connection_type + if meshcore_node_name: + app_config.meshcore.node_name = meshcore_node_name if meshcore_port: app_config.meshcore.port = meshcore_port if meshcore_host: @@ -241,12 +241,12 @@ async def run_agent(agent: MeshBotAgent) -> None: "--max-message-length", type=int, help="Maximum message length in characters" ) @click.option( - "--meshcore-type", + "--meshcore-connection-type", type=click.Choice(["mock", "serial", "tcp", "ble"]), default="mock", help="MeshCore connection type (default: mock)", ) -@click.option("--node-name", help="Node name to advertise on the mesh network") +@click.option("--meshcore-node-name", help="Node name to advertise on the mesh network") @click.option("--meshcore-port", help="Serial port for MeshCore connection") @click.option("--meshcore-host", help="TCP host for MeshCore connection") @click.option("--meshcore-address", help="BLE address for MeshCore connection") @@ -276,8 +276,8 @@ def test( model: Optional[str], listen_channel: Optional[str], max_message_length: Optional[int], - meshcore_type: str, - node_name: Optional[str], + meshcore_connection_type: str, + meshcore_node_name: Optional[str], meshcore_port: Optional[str], meshcore_host: Optional[str], meshcore_address: Optional[str], @@ -319,9 +319,9 @@ def test( app_config.ai.custom_prompt_file = custom_prompt # MeshCore configuration - app_config.meshcore.connection_type = meshcore_type - if node_name: - app_config.meshcore.node_name = node_name + app_config.meshcore.connection_type = meshcore_connection_type + if meshcore_node_name: + app_config.meshcore.node_name = meshcore_node_name if meshcore_port: app_config.meshcore.port = meshcore_port if meshcore_host: From b0defa49b3116a8e796bc6ca515760bd80e5bf77 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 23 Nov 2025 19:25:53 +0000 Subject: [PATCH 2/2] Update .env.example with naming convention docs --- .env.example | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 2d900d8..3127240 100644 --- a/.env.example +++ b/.env.example @@ -1,11 +1,15 @@ # MeshBot Environment Configuration # -# Configuration Priority: +# Configuration Priority (12-factor app principles): # 1. Command-line arguments (highest priority) # 2. Environment variables (this file) # 3. Default values (lowest priority) # -# All settings can be overridden via command-line arguments. +# Naming Convention: +# - Environment variables: UPPER_SNAKE_CASE (e.g., MESHCORE_PORT) +# - CLI arguments: kebab-case with -- prefix (e.g., --meshcore-port) +# - Config attributes: snake_case (e.g., meshcore.port) +# # See: meshbot run --help or meshbot test --help # LLM Configuration (OpenAI-compatible endpoints)