A LangGraph-based agent runtime with MCP integration, shell tooling, configurable tool approval modes, optional embedding-based retrieval, and a prompt manager.
- Agent
- Stateful agent runtime: Uses LangGraph with in-memory conversation state and streaming output.
- 5-level tool approval policy: Ranges from fully manual to fully automatic (
work.auto_mode). - MCP tool federation: Loads tools from configured MCP servers; unavailable servers are skipped.
- Shell command tool: Executes commands with configurable timeout and working directory.
- Embedding Knowledge Base (EKB): Supports semantic retrieval over indexed files.
- Prompt manager (
prompt_manager/): Builds lorebook JSON fromprompts/lorebooks/*/entries/*.md(or loads existing JSON), then each turn runs match → filter → expand → sort → budgeted inject, and splices the result into the preset skeleton (core, character, persona, and optional depth anchors). See doc/prompt_manager.md. - Hydra-based configuration: Hierarchical YAML composition with command-line overrides.
- Container support: Includes Docker scripts for build and startup.
Set these variables before starting the agent.
Required for LLM requests:
| Variable | Required | Description |
|---|---|---|
OPENAI_API_KEY |
Yes | API key used by config/llm/deepseek.yaml. |
OPENAI_API_BASE |
Yes | Base URL used by config/llm/deepseek.yaml (for example DeepSeek-compatible endpoint). |
Example:
export OPENAI_API_KEY="your_api_key"
export OPENAI_API_BASE="https://your-provider.example/v1"- Install uv.
- Ensure required ports for MCP servers are available (default:
8000,8001,8002).
git clone git@github.com:zeroDtree/agent.git
cd agent
git submodule update --init --recursiveThe mcp submodule contains MCP server implementations used by the startup scripts.
bash shell_scripts/start.sh [hydra overrides...]This command starts MCP servers defined in mcp/config.yaml, waits for ports to become ready, then launches the agent. MCP servers are stopped when the process exits.
bash shell_scripts/build_docker.sh
bash shell_scripts/start.docker.sh [hydra overrides...]The container mounts:
- Project directory:
/tmp/proj_dir - Writable working directory:
/tmp/work_dir shell_scripts/start.shauto-creates/tmp/work_dir/.venvwhen++work.working_directory=/tmp/work_diris set.
In Docker, use this split as a best practice:
- Read source files from
/tmp/proj_dir(mounted project root). - Write generated artifacts to
/tmp/work_dir(mounted writable workspace). - Keep task-level Python dependencies in
/tmp/work_dir/.venv.
Use Hydra override syntax to customize runtime behavior at launch:
bash shell_scripts/start.sh \
++work.auto_mode=whitelist_accept \
++work.working_directory=/tmp/work_dirWhen ++work.working_directory is set to a non-. path, startup initializes a dedicated .venv under that directory once. This task-level environment is separate from UV_PROJECT (the runtime environment used to launch main.py).
After bash shell_scripts/start.sh (or bash shell_scripts/start.docker.sh in Docker), the CLI prompt accepts the following. Any other line is sent to the model as a normal user turn; each turn may print lorebook entries that matched for that message.
| Command | Description |
|---|---|
exit / quit |
Exit the CLI. |
!help |
Print this command summary. |
!tool list |
List available tools (local plus MCP). |
!tool <name> [json_args] |
Invoke a tool with JSON arguments (defaults to {} if omitted). |
!char list |
List character roles from the configured role prompt directory (char.prompt_dir, default prompts/chars). |
!char show |
Show the active role and its prompt file path. |
!char set <role> |
Switch the active role for subsequent turns. |
!save <filename> |
Save the conversation to JSON. Bare filenames are resolved under conversation_dir from chat config; absolute paths or paths with a parent segment are used as given. |
!load <filename> |
Load conversation JSON from disk (same path rules as !save). |
!preset |
Print the last assembled preset messages sent to the model (before the latest user message). |
!clear |
Clear in-memory conversation history. |
!history |
Print conversation history (each message truncated to 120 characters). |
| Variable | Required | Description |
|---|---|---|
UV_PROJECT |
No | Path passed to uv run --project in startup scripts. If unset, scripts use the default project path. |
Optional variables for the knowledge_graph MCP server (Neo4j):
| Variable | Default | Description |
|---|---|---|
NEO4J_URI |
bolt://localhost:7687 |
Neo4j connection URI. |
NEO4J_USER |
neo4j |
Neo4j username. |
NEO4J_PASSWORD |
password |
Neo4j password. |
NEO4J_DATABASE |
neo4j |
Neo4j database name. |
NEO4J_QUERY_TIMEOUT_SECONDS |
6 |
Query timeout in seconds. |
KG_DEFAULT_LIMIT |
20 |
Default result limit for graph queries. |
KG_MAX_LIMIT |
100 |
Upper bound for graph query results. |
Agent configuration is composed from files under config/:
| File | Purpose |
|---|---|
config/config.yaml |
Top-level defaults composition |
config/llm/deepseek.yaml |
LLM endpoint, model, sampling parameters |
config/work/default.yaml |
Working directory, timeout, auto mode |
config/tool/default.yaml |
Safe and dangerous tools/commands |
config/mcp/default.yaml |
MCP endpoints for tool discovery |
config/system/default.yaml |
History length, recursion limit, thread |
config/log/default.yaml |
Log directory and log level |
config/chat/default.yaml |
Conversation persistence (conversation_dir) |
config/char/default.yaml |
Character card, lorebook ids, preset segment toggles/order |
config/ekb/default.yaml |
Vector DB paths, embedding model, chunking, search limits |
MCP runtime behavior comes from two sources:
mcp/config.yaml: MCP server process launch settings (transport,host,port,enabled)config/mcp/default.yaml: Agent-side MCP endpoints for tool discovery
Default configured MCP servers:
| Server | Launch transport (mcp/config.yaml) |
Launch address | Agent endpoint (config/mcp/default.yaml) |
|---|---|---|---|
math |
streamable-http |
0.0.0.0:8000 |
http://127.0.0.1:8000/mcp |
code_lint |
streamable-http |
0.0.0.0:8001 |
http://127.0.0.1:8001/mcp |
knowledge_graph |
streamable-http |
0.0.0.0:8002 |
http://127.0.0.1:8002/mcp |
Configure approval behavior with work.auto_mode:
| Mode | Config | When to use it |
|---|---|---|
| Manual | manual |
You want confirmation for every tool call |
| Blacklist Reject | blacklist_reject |
You want dangerous calls rejected, others confirmed manually |
| Universal Reject | universal_reject |
You want a strict no-tool execution mode |
| Whitelist Accept | whitelist_accept |
You want trusted calls auto-approved, others confirmed |
| Universal Accept | universal_accept |
You want fully automatic tool execution without confirmations |
Safe and dangerous lists are defined in config/tool/default.yaml.
This project exposes both local Python tools and MCP-discovered remote tools.
| Tool name | Enabled by default | Source | Description |
|---|---|---|---|
run_shell_command_popen_tool |
Yes | tools/shell.py |
Execute shell commands and return output |
search_knowledge_base |
Yes | tools/embedding_knowledge_base.py |
Search the EKB vector database |
todo_list_tool |
No | tools/todo_list.py |
Manage todo items in conversation context |
MCP tools are loaded dynamically from endpoints defined in config/mcp/default.yaml. Available tool sets depend on enabled servers in mcp/config.yaml (for example math, code_lint, knowledge_graph).
- Implement the tool under
tools/. - Register it in
tools.get_all_tools().
No change in main.py is required for local tool registration.
- EKB usage and commands: doc/embedding_knowledge_base.md
- Prompt manager (pipeline, types, build vs runtime): doc/prompt_manager.md