stage-1: project bootstrap

Structure, config loader, personality/tools/memory from clawd, venv, 22 tests passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
MoltBot Service
2026-02-13 10:20:55 +00:00
commit f2973aa76f
374 changed files with 59557 additions and 0 deletions

0
src/__init__.py Normal file
View File

0
src/adapters/__init__.py Normal file
View File

76
src/config.py Normal file
View File

@@ -0,0 +1,76 @@
"""
Config loader for Echo-Core.
Loads config.json from project root, provides dot-notation access,
save/reload support, and raw dict access.
"""
import json
from pathlib import Path
from typing import Any
_DEFAULT_CONFIG_PATH = Path(__file__).resolve().parent.parent / "config.json"
class Config:
"""Configuration manager with dot-notation get/set."""
def __init__(self, path: Path | str | None = None):
self._path = Path(path) if path else _DEFAULT_CONFIG_PATH
self._data: dict = {}
self.reload()
def reload(self) -> None:
"""Reload config from disk."""
with open(self._path, "r", encoding="utf-8") as f:
self._data = json.load(f)
def save(self) -> None:
"""Write current config back to disk."""
with open(self._path, "w", encoding="utf-8") as f:
json.dump(self._data, f, indent=2, ensure_ascii=False)
f.write("\n")
def get(self, key: str, default: Any = None) -> Any:
"""
Get a value using dot-notation.
Examples:
config.get("bot.name") -> "Echo"
config.get("channels") -> {}
config.get("missing", "fallback") -> "fallback"
"""
parts = key.split(".")
current = self._data
for part in parts:
if isinstance(current, dict) and part in current:
current = current[part]
else:
return default
return current
def set(self, key: str, value: Any) -> None:
"""
Set a value using dot-notation. Creates intermediate dicts as needed.
Examples:
config.set("bot.name", "NewName")
config.set("new.nested.key", 42)
"""
parts = key.split(".")
current = self._data
for part in parts[:-1]:
if part not in current or not isinstance(current[part], dict):
current[part] = {}
current = current[part]
current[parts[-1]] = value
def raw(self) -> dict:
"""Return the raw config dict (reference, not copy)."""
return self._data
def load_config(path: Path | str | None = None) -> Config:
"""Convenience function to create a Config instance."""
return Config(path)