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
8 changes: 6 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
10 changes: 5 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
57 changes: 11 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link

Copilot AI Nov 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test command requires two positional arguments (FROM_ID and MESSAGE), but this example only shows the optional flags. The correct syntax should be:

meshbot test user1 "Hello!" --meshcore-connection-type mock

This matches the pattern used in AGENTS.md lines 224-230.

Suggested change
meshbot test --meshcore-connection-type mock
meshbot test user1 "Hello!" --meshcore-connection-type mock

Copilot uses AI. Check for mistakes.

# 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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -192,7 +192,7 @@ meshbot

4. **Configuration** (`config.py`)
- Environment-based configuration
- JSON file support
- Command-line argument overrides
- Validation

### Message Handling
Expand Down Expand Up @@ -236,48 +236,13 @@ Sent as:

```bash
# Interactive testing with mock MeshCore
meshbot test --meshcore-type mock
meshbot test --meshcore-connection-type mock
Copy link

Copilot AI Nov 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test command requires two positional arguments (FROM_ID and MESSAGE), but this example only shows the optional flags. The correct syntax should be:

meshbot test user1 "Hello!" --meshcore-connection-type mock

This matches the pattern used in AGENTS.md lines 224-230.

Suggested change
meshbot test --meshcore-connection-type mock
meshbot test user1 "Hello!" --meshcore-connection-type mock

Copilot uses AI. Check for mistakes.

# 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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Copy link

Copilot AI Nov 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test command requires two positional arguments (FROM_ID and MESSAGE), but this example only shows the optional flags. The correct syntax should be:

meshbot test user1 "Hello!" --custom-prompt debug_prompt.txt -vv --meshcore-connection-type mock

This matches the pattern used in AGENTS.md lines 224-230.

Suggested change
meshbot test --custom-prompt debug_prompt.txt -vv --meshcore-connection-type mock
meshbot test user1 "Hello!" --custom-prompt debug_prompt.txt -vv --meshcore-connection-type mock

Copilot uses AI. Check for mistakes.
```

### Viewing Logs
Expand Down
6 changes: 3 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
33 changes: 0 additions & 33 deletions src/meshbot/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 15 additions & 15 deletions src/meshbot/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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],
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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],
Expand Down Expand Up @@ -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:
Expand Down
Loading