Confucius Code Agent
Build a code agent with scaffolding patterns from the paper "Confucius Code Agent". Implement hierarchical memory, persistent notes, and meta-agent loops.
Why Confucius?
AX (Agent Experience)
Hierarchical memory keeps context clean and stable
UX (User Experience)
Persistent Markdown notes for transparency
DX (Developer Experience)
Modular extensions for easy evolution
Meta-Agent (F4)
Build → Test → Improve configuration loop
Agent Architecture
Step 1: Environment Setup
No API Key Required: Heuristic mode demonstrates scaffolding without LLM calls!
# 1. Navigate to project
cd Handson/Confucius-Agent
# 2. Run WebUI with Docker Compose
docker compose up
# 3. Open in browser
# http://127.0.0.1:7862
# Optional: With OpenAI
export OPENAI_API_KEY='your-key'
docker compose up
# Install Poetry
pip install poetry
# Install dependencies
cd Handson/Confucius-Agent
poetry install
# Run WebUI (Heuristic mode - no API key needed)
poetry run python webui.py
# Or run CLI demo
poetry run python mini_confucius.py
# With LLM providers
poetry install --with llm
export OPENAI_API_KEY='your-key'
poetry run python webui.py
# Install dependencies
pip install -r requirements.txt
# Run WebUI
python webui.py
# Or run CLI demo
python mini_confucius.py
# With OpenAI (optional)
export OPENAI_API_KEY='your-key'
python mini_confucius.py --provider openai
Key Concepts
WorkingMemory
Hierarchical state: goal, plan, key_facts, recent, compressed_history
Orchestrator
Think → Act → Observe loop with trajectory logging
Tools
Modular: search_files, read_file, write_file, run_tests
write_notes()
Generates Markdown notes with hindsight learning
The WorkingMemory is a dataclass that maintains hierarchical context for the agent.
from dataclasses import dataclass, field
@dataclass
class WorkingMemory:
"""Hierarchical context for clean AX (Agent Experience)."""
goal: str # What we're trying to achieve
plan: list[str] = field(default_factory=list) # High-level steps
key_facts: list[str] = field(default_factory=list) # Important discoveries
recent: list[str] = field(default_factory=list) # Last N observations
compressed_history: str = "" # Summarized older context
def maybe_compress(self, turns: list, max_recent: int = 5):
"""Compress older entries to prevent context overflow."""
if len(self.recent) > max_recent:
old = self.recent[:-max_recent]
self.compressed_history += "\n".join(old)
self.recent = self.recent[-max_recent:]
Tools are modular functions the agent can invoke to interact with the codebase.
class Tools:
"""Modular tool implementations (DX principle)."""
def __init__(self, repo_root: Path):
self.repo_root = repo_root
def search_files(self, pattern: str) -> str:
"""Search for pattern in all Python files."""
matches = []
for path in self.repo_root.rglob("*.py"):
content = path.read_text()
if pattern in content:
matches.append(str(path.relative_to(self.repo_root)))
return "\n".join(matches) if matches else "No matches found"
def read_file(self, path: str) -> str:
"""Read file contents."""
return (self.repo_root / path).read_text()
def write_file(self, path: str, content: str) -> str:
"""Write content to file."""
(self.repo_root / path).write_text(content)
return f"Wrote {len(content)} chars to {path}"
def run_tests(self) -> str:
"""Execute tests and return results."""
result = subprocess.run(
["python", "-m", "pytest", "-q"],
cwd=self.repo_root,
capture_output=True, text=True
)
return result.stdout + result.stderr
The Orchestrator runs the Think → Act → Observe loop and manages working memory.
class Orchestrator:
"""Core loop: Think → Act → Observe."""
def __init__(self, llm, tools: Tools, wm: WorkingMemory):
self.llm = llm
self.tools = tools
self.wm = wm
self.turns = []
def run(self, task: str, max_steps: int = 8) -> bool:
"""Execute agent loop until success or max steps."""
last_obs = ""
for step in range(max_steps):
# Build prompt from working memory
prompt = self._build_prompt(task) + f"\nLAST_OBS: {last_obs}"
# Think: LLM generates thought + action
response = self.llm.generate(prompt)
thought, action = self._parse_action(response)
# Act: Execute tool
if action:
tool_name, args = action
result = self._invoke_tool(tool_name, args)
last_obs = result.output
# Update memory
self.wm.recent.append(f"[{step}] {tool_name} → {last_obs[:200]}")
self.wm.maybe_compress(self.turns)
# Check success
if "passed" in last_obs.lower():
return True
return False
After each run, generate Markdown notes with trajectory and hindsight for user transparency.
def write_notes(self, title: str) -> Path:
"""Generate Markdown notes for UX transparency."""
notes_dir = self.run_dir / "notes"
notes_dir.mkdir(parents=True, exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
path = notes_dir / f"{timestamp}-{title}.md"
content = f"""# {title}
Date: {datetime.now().isoformat()}
## Goal
{self.wm.goal}
## Plan
{chr(10).join('- ' + p for p in self.wm.plan)}
## Key Events (Trajectory)
{chr(10).join('- **' + t.action.tool + '** → ' + ('OK' if t.action.ok else 'ERR') for t in self.turns)}
## Hindsight (Failures / Lessons)
{chr(10).join('- ' + f for f in self.wm.key_facts if 'FAILED' in f.upper())}
"""
path.write_text(content)
return path
Expected Output
🧠 Confucius Code Agent Demo
=============================
Setting up demo repository...
✓ Created demo_repo/calc.py (with bug: add subtracts instead)
✓ Created demo_repo/test_calc.py
Starting agent...
Step 0: run_tests → FAILED test_calc.py: Expected 5 but got -1
Step 1: search_files {'pattern': 'def add'} → calc.py
Step 2: read_file {'path': 'calc.py'} → found bug: return a - b
Step 3: write_file {'path': 'calc.py'} → fixed: return a + b
Step 4: run_tests → PASSED
✓ Agent complete! Notes: demo_repo/.confucius/notes/20260110-demo.md
Learning Checklist
Quick Quiz
According to the Confucius paper, what is the key differentiator in code agents?