Morphix is an open-source, layered multi-agent orchestration platform for AI-assisted software engineering. It coordinates multiple AI agents through four wired workflow strategies, backed by a clean architecture with per-workspace PostgreSQL isolation and production-grade infrastructure patterns.
Documentation: Full documentation is available at the Morphix docs site. To browse locally:
poetry run mkdocs serve.
| Metric | Value |
|---|---|
| Python | 3.12 (>=3.12,<3.14), Poetry, package-mode = false |
| Tests | ~698 test functions across 78 test modules |
| Sprints / commits | 26 sprints (latest: sprint 26b) · ~270 commits |
| Type checking | mypy on core/ llm/ agents/ tools/ orchestration/ desktop/ — 0 errors |
| Default LLM | DeepSeek deepseek-v4-flash (all roles), fallback → Ollama (phi3:mini) |
| Tools | 12 registered |
| Agents | 5 profiles |
| Workflows | 4 wired routes |
Most AI coding tools are tightly coupled monoliths. Morphix is designed as a platform: a clean, layered architecture that separates concerns so each subsystem can be understood, tested, and extended independently.
- Clean layered architecture —
core/→llm/→agents/→tools/→orchestration/→desktop/. Each layer depends only on the layer below it. No circular imports. No UI leaking into business logic. - Per-workspace PostgreSQL schemas — every workspace lives in its own schema with isolated tables. No data leakage between projects. The active schema is set via
search_pathon every async session. - 4 workflow strategies — development (full orchestration with Safety Net), coordinated (DAG-based parallel execution with blackboard), collaborative (multi-agent panel debate with moderator consensus), and TDD (test-driven loop).
- Production patterns — circuit breaker with fallback, sliding-window rate limiter, RestrictedPython sandbox, FAISS vector memory with auto-healing, token budget with context compression, anti-distillation watermarking.
- ~698 test functions, 0 mypy errors — disciplined development across 26 sprints. Async tests with
pytest-asyncio. Full CI pipeline with PostgreSQL service containers. - Dynamic extensibility — tools as
.pyfiles loaded at runtime, agents as YAML profiles, hooks with 6 interception points, MCP integration for external tool servers.
⚠️ AI Disclosure / Divulgación de IAEnglish: This project was developed with assistance from artificial intelligence tools. Given the automated nature of some components, users are advised to review and test the code independently before integrating it into their own systems.
Español: Este proyecto fue desarrollado con asistencia de herramientas de inteligencia artificial. Dada la naturaleza automatizada de algunos componentes, se recomienda que los usuarios revisen y prueben el código independientemente antes de integrarlo en sus propios sistemas.
Coverage note: Test coverage is ~21%. The test suite uses mock-heavy patterns (387 MagicMock/AsyncMock, 238
patch()context managers) due to async LLM dependencies that require external API keys. Integration tests for orchestration paths are planned for future releases.
# Prerequisites: Python 3.12, PostgreSQL, Poetry
poetry install --with dev
cp example.env .env # edit DATABASE_URL + at least one API key (DEEPSEEK_API_KEY)
poetry run alembic upgrade head
poetry run python run.py # launch the desktop GUIAlembic migrations are manual.
startup_db()only creates tables directly; runpoetry run alembic upgrade headfor migration-based schema changes.
Desktop GUI (PySide6)
│
▼
WorkflowOrchestrator.run_full_workflow() ── routing precedence ──
1. Direct tool command "tool_name: action, key=val"
2. TDD loop (active workflow == "tdd")
3. Collaborative (template.type == "collaborative")
4. Coordinated (template.type == "coordinated")
5. Development (template.type == "development")
6. Default TaskAnalyzer → simple conversation | full orchestration
│
▼
Agent Loop (ReAct) ←→ ToolOrchestrator ──→ Tools (file/git/bash/code/search/MCP)
│ │
LLM provider Hooks (pre/post/error) · Permission UI ·
(DeepSeek/OpenAI/Ollama) Token budget + cache · Anti-distillation
Morphix follows a strict layered architecture with clean boundaries:
| Layer | Directory | Role |
|---|---|---|
| Core | core/ |
Business logic — database, config, memory (FAISS), security, MCP, path resolution |
| LLM | llm/ |
AI abstraction — role-based model selection, DeepSeek/OpenAI/Ollama providers |
| Agents | agents/ |
Agent system — registry, loader, profiles (5 agents), execution, audit |
| Tools | tools/ |
Tool system — specs, registry, orchestrator with hooks, 12 implementations |
| Orchestration | orchestration/ |
Workflow orchestration — analyzer, decomposer, router, supervisor, 4 workflows |
| Desktop | desktop/ |
PySide6 GUI — dashboard, cockpit, editor, analytics, history |
Every workspace is a separate PostgreSQL schema with its own tables (Conversation,
Message, Workflow, User, PausedSession). Schema names match [a-z][a-z0-9_]*. The active
schema is set via search_path on every async session. Switching workspaces runs
create_schema + create_tables_in_schema + set_async_schema, then reloads agents/tools.
core/database.pyrewritespostgresql://→postgresql+asyncpg://for the async engine.
- Global tools:
tools/*.py, loaded at startup viaload_global_tools(). - Workspace tools:
workspaces/<name>/tools/*.py, loaded/cleared on workspace switch. - Agents: templates in
templates/agents/*.yaml, copied toworkspaces/<name>/agents/on first switch, registered in the globalagents_registry. - Workflows: templates in
templates/workflows/*.yaml, resolved by name (workspace copy wins over global) byorchestration/loader.py.
| Workflow | Route trigger | Description |
|---|---|---|
| development | template.type == "development" |
Decompose → route → execute → supervise → aggregate. Full orchestration with Safety Net fallback (analysis agents never fabricate files). |
| collaborative | template.type == "collaborative" |
Multi-agent panel debate (3 rounds) with moderator consensus. Per-round 120s timeout. |
| coordinated | template.type == "coordinated" |
DAG-based parallel execution with shared blackboard (phase namespaces, cross-phase context). max_parallel: 4, per-subtask 180s timeout. |
| TDD | active workflow == "tdd" |
Test-driven loop: write tests → run → fix → repeat. 300s per iteration. |
Plus the direct tool command fast path (tool_name: action, key=val) and the default
route that analyzes the task and picks simple conversation vs full orchestration.
| Agent | Role | Tools | Best for |
|---|---|---|---|
| developer | agent | file_manager, git_manager, bash_manager, lsp_manager, code_exec, test_runner, diff_editor | Coding, building, testing |
| analista | reasoning | file_manager (read), lsp_manager, code_search, web_search | Analysis, review, architecture |
| architect | reasoning | file_manager (read), lsp_manager, code_search, web_search | Architecture design, code review |
| moderador | reasoning | none | Debate moderation, consensus |
| conversacional | agent | none | Quick chat, fallback agent |
Defaults: DEFAULT_AGENT=developer, FALLBACK_AGENT=conversacional.
Registered via @tools_registry.register("name") and described as OpenAI function-calling specs
in tools/specs.py. The registered name may differ from the filename.
| Registered name | Source file | Actions / purpose |
|---|---|---|
file_manager |
file_manager.py |
write / read / append / delete |
bash_manager |
bash_manager.py |
Run shell commands (command, cwd, timeout); sanitized |
git_manager |
git_manager.py |
init / add / commit / log / diff |
test_runner |
test_runner.py |
Run test suites (pytest etc.) |
lsp_manager |
lsp_manager.py |
definition / hover / diagnostics / references / ruff_check (jedi) |
code_exec |
code_execution.py |
Execute Python in a RestrictedPython sandbox |
diff_editor |
diff_editor.py |
apply / create unified diffs |
web_search |
web_search.py |
Web search (Google CSE — needs GOOGLE_API_KEY/GOOGLE_CX) |
web_fetch |
web_fetch.py |
Fetch + extract page content |
code_search |
code_search.py |
Pattern search across the codebase |
pdf_read |
pdf_reader.py |
Extract text from PDFs (pdfplumber) |
ask_clarification |
ask_clarification.py |
Pause workflow & ask the user a question |
ask_clarificationis not inTOOL_DEFINITIONS; it is intercepted directly in the agent loop (orchestration/loop.py) rather than invoked via function-calling.
Additional extensibility lives in tools/kits/ and tools/skills/.
- Circuit breaker (
circuit_breaker.py) — per-provider closed/open/half-open; opens after consecutive failures and falls back to Ollama. Guards bothcallandcall_stream. - Rate limiter (
rate_limiter.py) — sliding-window per-minute and per-hour quotas. - Memory (
core/memory/) — FAISS vector search +MemoryManager.faiss_indexer.py,embedding_provider.py(incore/) — vector indexing and embeddings. autoDream (self_healing_check()daemon, run by theDAEMON_MODEloop) —SELF_HEAL_INTERVAL, default 120s: quality critique, duplicate detection (FAISS sim > 92%), contradiction resolution (65–92%), pruning (unaccessed 30+ days). - Change tracker (
change_tracker.py) — undo/redo for file ops via.undo/.redo. - MCP (
mcp/) — Model Context Protocol client (connect external servers) + server (morphix-mcpexposes the 11 function-calling tools fromTOOL_DEFINITIONSover stdio JSON-RPC;ask_clarificationis interception-only and not exposed). - Sandbox (
sandbox/) — RestrictedPython executor with aSAFE_MODULESallowlist. - Security (
security/) — undercover mode, anti-distillation (rotating watermarks, pattern detection, escalation warn→throttle→honeypot→lock), frustration detector. - Health (
health.py) —run_health_check()runs 5 probe functions and emits 6 report rows: Database, LLM, Redis, Memory Dir, Templates, Workspace. - Token budget & cache (
token_counter.py,cache_manager.py,context_manager.py) — conversation compression at 90% ofMAX_CONTEXT_TOKENS; DeepSeek prompt-cache monitoring. - Hooks (
hooks_registry.py,hook_loader.py,hooks/) — generic registry; the 6 interception points dispatched bytools/orchestrator.pyaround every tool call areon_before_tool,on_after_tool,on_tool_error,on_permission_denied,on_token_budget_exceeded,on_tools_disabled. - Bootstrap / config / paths (
bootstrap.py,config.py,path_resolver.py,feature_flags.py) — startup, pydantic-settings, path resolution (never hardcode paths — usecore.path_resolver.paths), feature flags.
- Role-based config —
settings.model_rolesmaps roles (default,fast,reasoning,agent,creative,critique) to provider/model/temperature. All default todeepseek-v4-flash. - Providers — DeepSeek/OpenAI (OpenAI-compatible client) and Ollama. Falls back to Ollama
when
OFFLINE_MODE=trueor a connectivity check fails. - Strict mode —
DEEPSEEK_STRICT_MODE(default false) enablesstrict=true+additionalProperties=falseon non-MCP tool schemas to forcerequiredcompliance. - Parser / prompts / offline — response parsing, prompt assembly, offline orchestration.
from core.hooks_registry import hooks_registry, HookContext
@hooks_registry.register("on_before_tool")
def my_hook(ctx: HookContext) -> None:
print(f"About to execute: {ctx.tool_name}")Edit workspaces/<name>/mcp_servers.json (or the global one). Tools register as
mcp:<prefix>.<name>:
[
{
"name": "playwright",
"command": "npx",
"args": ["@playwright/mcp@latest"],
"tools_prefix": "browser",
"enabled": true
}
]Run Morphix itself as an MCP server: poetry run morphix-mcp (exposes the 11 function-calling
tools; ask_clarification is interception-only and not exposed).
Key .env variables (see example.env and core/config.py):
# Required
DATABASE_URL=postgresql://user:pass@localhost:5432/morphix
DEEPSEEK_API_KEY=sk-xxx # at least one LLM key required
# Optional LLM / search
OPENAI_API_KEY= # GROK_API_KEY, GOOGLE_API_KEY, GOOGLE_CX (web_search)
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=phi3:mini
LLM_TIMEOUT=60
DEEPSEEK_STRICT_MODE=false
MAX_CONTEXT_TOKENS=128000
# Security (auto-generated in dev, REQUIRED in production via MORPHIX_ENV=production)
ENCRYPTION_KEY=
PASSWORD_HASH=
# Workspace / agents
ACTIVE_WORKSPACE=main
DEFAULT_AGENT=developer
FALLBACK_AGENT=conversacional
DEFAULT_WORKFLOW=development
# Feature flags
DARK_MODE=true
OFFLINE_MODE=false
UNDERCOVER_MODE=true
DAEMON_MODE=true
SELF_HEAL_INTERVAL=120
CONTEXT_COMPRESSION=true
MAX_SUBTASKS=8
MAX_AGENT_ITERATIONS=8
TOOLS_ENABLED=true
ALLOW_CODE_EXECUTION=true
# Tool settings
TOOL_MAX_TOKENS_PER_WORKFLOW=8000
TOOL_ENABLE_TOKEN_BUDGET=true
TOOL_MAX_RETRIES=3
TOOL_BACKOFF_BASE=1.5
# Database pool
DB_POOL_SIZE=5
DB_MAX_OVERFLOW=10
DB_POOL_PRE_PING=true
DB_POOL_RECYCLE=3600
# Redis (optional)
REDIS_URL=redis://localhost:6379/0
ENCRYPTION_KEYauto-generates in dev but raisesValueErrorin production (MORPHIX_ENV=production). CI setsUNDERCOVER_MODE=false,DAEMON_MODE=false,OFFLINE_MODE=trueto disable features that need auth or external services.
| Task | Command |
|---|---|
| Run GUI | poetry run python run.py |
| Run MCP server | poetry run morphix-mcp |
| All tests (async + coverage) | poetry run pytest |
| Single test | poetry run pytest tests/test_workflow_orchestrator.py::test_direct_tool_route |
| Lint | poetry run ruff check . |
| Format | poetry run black . |
| Typecheck | poetry run mypy core/ llm/ agents/ tools/ orchestration/ desktop/ |
| Pre-commit (all hooks) | poetry run pre-commit run --all-files |
| DB migrations | poetry run alembic upgrade head |
| Health check | poetry run python -c "import asyncio; from core.health import run_health_check; r = asyncio.run(run_health_check()); print(r.format())" |
| Documentation (local) | poetry run mkdocs serve |
Local check order: ruff check . → black --check . → mypy → pytest.
Full documentation is built with MkDocs Material and available at the Morphix docs site. To browse locally:
poetry install --with docs
poetry run mkdocs serveThe documentation covers:
- Getting Started — installation, configuration, first workflow
- User Guide — GUI overview, cockpit, workflows, agents, tools, workspaces
- Architecture — design decisions, data flow, workspace system, security model, memory system, MCP integration, per-layer deep-dives
- Developer Guide — adding tools, agents, workflows, hooks; contributing; testing guide
- API Reference — auto-generated from docstrings via mkdocstrings
- Changelog — release notes and version history
codemorphix/
├── core/ # Business logic (no UI deps)
│ ├── mcp/ # MCP protocol (client + server)
│ ├── memory/ # FAISS + MemoryManager + autoDream
│ ├── security/ # undercover, anti-distillation, frustration detector
│ ├── sandbox/ # RestrictedPython executor
│ ├── hooks/ # global hook implementations
│ └── repositories/ # DB repositories (ConversationRepository, ...)
├── llm/ # controller, provider, parser, prompts, offline
├── agents/ # registry, loader, profiles, base, service, audit
├── tools/ # 12 tools + specs, registry, orchestrator, wrapper, loader, kits, skills
├── orchestration/ # analyzer, decomposer, router, supervisor, aggregator, finalizer, loop, runner
│ ├── executor/ # subtask, plan, verify, post
│ └── workflows/ # orchestrator, collaborative, coordinated, tdd, blackboard
├── desktop/ # PySide6 GUI
│ ├── services/ # config, dashboard, analytics, history
│ └── widgets/ # reusable widgets
├── templates/ # agent + workflow YAML templates
├── workspaces/ # per-workspace configs + runtime data
├── docs/ # MkDocs documentation source
├── alembic/ # DB migrations
├── tests/ # 78 test modules (~698 test functions)
└── logs/ # runtime logs (morphix.log)
- See the documentation site for architecture, workflows, agents, tools, and development guides.
- See docs/ for the full documentation source.
- See CONTRIBUTING.md for developer setup and conventions.
Test conventions: pytest-asyncio with asyncio_mode = "auto"; mark async tests with
@pytest.mark.asyncio. No shared fixtures in conftest.py — mocks are defined inline per module.
CI provides PostgreSQL as a service container.
MIT — see LICENSE for the full text.