Developer Guide
This page summarizes the code layout, core interfaces, and the minimal steps needed to build a new client.
Monorepo layout
packages/meeseeks_core/: orchestration loop, session runtime, schemas, session storage, compaction, tool registry.
packages/meeseeks_tools/: tool implementations and integration glue.
packages/meeseeks_tools/src/meeseeks_tools/vendor/aider: vendored Aider utilities used by local file + shell tools.
apps/meeseeks_api/: Flask API that exposes the assistant over HTTP.
apps/meeseeks_chat/: Streamlit UI for interactive chat.
apps/meeseeks_cli/: terminal CLI for interactive sessions.
meeseeks_ha_conversation/: Home Assistant integration that routes voice requests to the API.
Core abstractions and interfaces
AbstractTool (meeseeks_core.classes): base class for local tools; implement get_state and set_state and return a MockSpeaker.
ToolRunner protocol (meeseeks_core.tool_registry): interface for tool runners with run(ActionStep).
ToolSpec / ToolRegistry (meeseeks_core.tool_registry): register tools with tool_id, metadata, and a factory.
ActionStep, Plan, TaskQueue (meeseeks_core.classes): planning and tool-execution payloads.
PermissionPolicy (meeseeks_core.permissions): allow/deny/ask rules for tool execution.
HookManager (meeseeks_core.hooks): pre/post hooks and compaction transforms.
SessionStore / SessionRuntime (meeseeks_core.session_store, meeseeks_core.session_runtime): transcripts and the shared runtime facade.
ChatModel protocol (meeseeks_core.llm): interface for LLM backends via build_chat_model.
New client walkthrough (concrete steps)
- Load config and initialize core services:
load_registry() for tool registration.
load_permission_policy() and approval_callback_from_config() for approvals.
SessionStore() and SessionRuntime() for transcripts and runs.
- Resolve or create a session id using
SessionRuntime.resolve_session().
- Handle core slash commands (
/compact, /status, /terminate) with parse_core_command().
- Execute the request:
run_sync() for synchronous use cases.
start_async() + load_events(after=...) for polling flows.
- Emit and consume session events:
action_plan when a plan is generated.
permission decisions when approvals are requested or denied.
tool_result for each tool execution (includes tool_id, operation, tool_input, and result).
step_reflection when the reflector requests a revision.
assistant and completion for final output and status.
- Logging:
- Use
get_logger() for module logging.
- Use
session_log_context(session_id) to capture per-session logs.
Minimal sync example
from meeseeks_core.common import get_logger
from meeseeks_core.permissions import approval_callback_from_config, load_permission_policy
from meeseeks_core.session_runtime import SessionRuntime, parse_core_command
from meeseeks_core.session_store import SessionStore
from meeseeks_core.tool_registry import load_registry
logger = get_logger("client")
session_store = SessionStore()
tool_registry = load_registry()
runtime = SessionRuntime(session_store=session_store)
session_id = runtime.resolve_session(session_tag="client")
user_text = "Hello from the client"
command = parse_core_command(user_text)
if command:
logger.info("Handled command: {}", command)
else:
result = runtime.run_sync(
session_id=session_id,
user_query=user_text,
tool_registry=tool_registry,
permission_policy=load_permission_policy(),
approval_callback=approval_callback_from_config(),
)
logger.info("Task result: {}", result.task_result)
Implementing a local tool
- Subclass
AbstractTool and implement get_state / set_state.
- Register the tool with a
ToolSpec factory in the registry.
from meeseeks_core.classes import AbstractTool, ActionStep
from meeseeks_core.common import get_mock_speaker
from meeseeks_core.tool_registry import ToolRegistry, ToolSpec
class ExampleTool(AbstractTool):
def __init__(self) -> None:
super().__init__(name="Example", description="Example tool")
def get_state(self, action_step: ActionStep | None = None):
return get_mock_speaker()(content="Example read")
def set_state(self, action_step: ActionStep | None = None):
return get_mock_speaker()(content="Example write")
registry = ToolRegistry()
registry.register(
ToolSpec(
tool_id="example_tool",
name="Example",
description="Example local tool",
factory=ExampleTool,
)
)
1---2name: developer-guide-33description: This page summarizes the code layout, core interfaces, and the minimal steps needed to build a new client.4---5# Developer Guide67This page summarizes the code layout, core interfaces, and the minimal steps needed to build a new client.89## Monorepo layout10- `packages/meeseeks_core/`: orchestration loop, session runtime, schemas, session storage, compaction, tool registry.11- `packages/meeseeks_tools/`: tool implementations and integration glue.12- `packages/meeseeks_tools/src/meeseeks_tools/vendor/aider`: vendored Aider utilities used by local file + shell tools.13- `apps/meeseeks_api/`: Flask API that exposes the assistant over HTTP.14- `apps/meeseeks_chat/`: Streamlit UI for interactive chat.15- `apps/meeseeks_cli/`: terminal CLI for interactive sessions.16- `meeseeks_ha_conversation/`: Home Assistant integration that routes voice requests to the API.1718## Core abstractions and interfaces19- `AbstractTool` (`meeseeks_core.classes`): base class for local tools; implement `get_state` and `set_state` and return a `MockSpeaker`.20- `ToolRunner` protocol (`meeseeks_core.tool_registry`): interface for tool runners with `run(ActionStep)`.21- `ToolSpec` / `ToolRegistry` (`meeseeks_core.tool_registry`): register tools with `tool_id`, metadata, and a factory.22- `ActionStep`, `Plan`, `TaskQueue` (`meeseeks_core.classes`): planning and tool-execution payloads.23- `PermissionPolicy` (`meeseeks_core.permissions`): allow/deny/ask rules for tool execution.24- `HookManager` (`meeseeks_core.hooks`): pre/post hooks and compaction transforms.25- `SessionStore` / `SessionRuntime` (`meeseeks_core.session_store`, `meeseeks_core.session_runtime`): transcripts and the shared runtime facade.26- `ChatModel` protocol (`meeseeks_core.llm`): interface for LLM backends via `build_chat_model`.2728## New client walkthrough (concrete steps)291. Load config and initialize core services:30 - `load_registry()` for tool registration.31 - `load_permission_policy()` and `approval_callback_from_config()` for approvals.32 - `SessionStore()` and `SessionRuntime()` for transcripts and runs.332. Resolve or create a session id using `SessionRuntime.resolve_session()`.343. Handle core slash commands (`/compact`, `/status`, `/terminate`) with `parse_core_command()`.354. Execute the request:36 - `run_sync()` for synchronous use cases.37 - `start_async()` + `load_events(after=...)` for polling flows.385. Emit and consume session events:39 - `action_plan` when a plan is generated.40 - `permission` decisions when approvals are requested or denied.41 - `tool_result` for each tool execution (includes `tool_id`, `operation`, `tool_input`, and `result`).42 - `step_reflection` when the reflector requests a revision.43 - `assistant` and `completion` for final output and status.446. Logging:45 - Use `get_logger()` for module logging.46 - Use `session_log_context(session_id)` to capture per-session logs.4748### Minimal sync example49```python50from meeseeks_core.common import get_logger51from meeseeks_core.permissions import approval_callback_from_config, load_permission_policy52from meeseeks_core.session_runtime import SessionRuntime, parse_core_command53from meeseeks_core.session_store import SessionStore54from meeseeks_core.tool_registry import load_registry5556logger = get_logger("client")5758session_store = SessionStore()59tool_registry = load_registry()60runtime = SessionRuntime(session_store=session_store)6162session_id = runtime.resolve_session(session_tag="client")63user_text = "Hello from the client"64command = parse_core_command(user_text)65if command:66 logger.info("Handled command: {}", command)67else:68 result = runtime.run_sync(69 session_id=session_id,70 user_query=user_text,71 tool_registry=tool_registry,72 permission_policy=load_permission_policy(),73 approval_callback=approval_callback_from_config(),74 )75 logger.info("Task result: {}", result.task_result)76```7778### Implementing a local tool791. Subclass `AbstractTool` and implement `get_state` / `set_state`.802. Register the tool with a `ToolSpec` factory in the registry.8182```python83from meeseeks_core.classes import AbstractTool, ActionStep84from meeseeks_core.common import get_mock_speaker85from meeseeks_core.tool_registry import ToolRegistry, ToolSpec8687class ExampleTool(AbstractTool):88 def __init__(self) -> None:89 super().__init__(name="Example", description="Example tool")9091 def get_state(self, action_step: ActionStep | None = None):92 return get_mock_speaker()(content="Example read")9394 def set_state(self, action_step: ActionStep | None = None):95 return get_mock_speaker()(content="Example write")9697registry = ToolRegistry()98registry.register(99 ToolSpec(100 tool_id="example_tool",101 name="Example",102 description="Example local tool",103 factory=ExampleTool,104 )105)106```