The Engine is Skyflo’s backend orchestration layer for DevOps and SRE teams. It connects the Command Center and the MCP server, turning natural language into typed, auditable Kubernetes and CI/CD operations with an approval gate for every mutating tool call.
See docs/architecture.md for full system context.
The Engine follows a layered structure under src/api:
endpoints/: FastAPI routers for agent chat/approvals/stop, conversations, auth, team, integrations, and healthservices/: Business logic (MCP client, tool execution, approvals, rate limiting, titles, persistence)agent/: LangGraph workflowconfig/: Settings, database, and rate-limit configurationmodels/: Tortoise ORM modelsmiddleware/: CORS and request loggingutils/: Helpers, sanitization, time utilitiesThe workflow is a compact graph compiled with an optional Postgres checkpointer:
entry → model → gate → final with conditional routingmodel runs an LLM turn (via LiteLLM) and may produce tool callsgate executes MCP tools (with approval policy) and feeds results back to the modelCheckpointer:
langgraph-checkpoint-postgres when ENABLE_POSTGRES_CHECKPOINTER=trueAll workflow events stream over SSE from /api/v1/agent/chat and /api/v1/agent/approvals/{call_id}. Internally, the Engine uses Redis pub/sub channels keyed by a unique run id. Event types include (non-exhaustive):
ready, heartbeatthinking, thinking.completetoken, generation.start, generation.completetools.pending, tool.executing, tool.awaiting_approval, tool.result, tool.error, tool.approved, tool.deniedtoken.usage, ttftcompleted, workflow_complete, workflow_error, workflow.errorreadOnlyHint, destructiveHint)1) Create .env from the example and set required variables.
# From engine/
cp .env.example .env
Minimum to set for local dev:
APP_NAME, APP_VERSION, APP_DESCRIPTIONPOSTGRES_DATABASE_URL (e.g. postgres://postgres:postgres@localhost:5432/skyflo)REDIS_URL (e.g. redis://localhost:6379/0)JWT_SECRETMOONSHOT_API_KEY when LLM_MODEL=moonshot/kimi-k2.52) Install dependencies and the package in editable mode.
python -m venv .venv
source .venv/bin/activate
uv pip install -e "."
3) Apply database migrations (Tortoise + Aerich).
aerich upgrade
To create new migrations during development:
aerich migrate
aerich upgrade
# From project root
docker compose -f deployment/local.docker-compose.yaml up -d
# Using uv (recommended, respects uv.lock for reproducible builds)
uv run uvicorn src.api.asgi:app --host 0.0.0.0 --port 8080 --reload
Service will be available at http://localhost:8080.
Note: Development commands require Hatch. Install via pip install hatch or pipx install hatch.
| Command | Description |
|---|---|
uv run uvicorn src.api.asgi:app --host 0.0.0.0 --port 8080 --reload |
Start development server with hot reload |
hatch run lint |
Run Ruff linter to check for code issues |
hatch run type-check |
Run mypy for type checking |
hatch run format |
Format code with Ruff |
hatch run test |
Run tests with pytest |
hatch run test-cov |
Run tests with coverage report |
Base path: /api/v1
GET /health and GET /health/databasePOST /agent/chat (SSE): stream tokens/eventsPOST /agent/approvals/{call_id} (SSE): approve/deny pending toolPOST /agent/stop: stop a specific runGET /agent/tools: list available MCP tools with metadata (name, title, tags, annotations)POST /conversations, GET /conversations, GET/PATCH/DELETE /conversations/{id}/auth/jwt/*, /auth/register/*, /auth/verify/*, /auth/reset-password/*, /auth/users/*), plus:
GET /auth/is_admin_userGET /auth/me, PATCH /auth/mePATCH /auth/users/me/passwordPOST /auth/refresh/issue, POST /auth/refresh (refresh token rotation)POST /auth/logout (revoke refresh token, clear cookies)/team/*): members list/add/update/remove (requires admin)/integrations/*): list (authenticated), create/update/delete (admin only)curl -N -H "Content-Type: application/json" \
-X POST \
-d '{"messages":[{"role":"user","content":"List pods in default"}]}' \
http://localhost:8080/api/v1/agent/chat
curl -N -H "Content-Type: application/json" \
-X POST \
-d '{"approve":true, "reason":"safe", "conversation_id":"<conversation-uuid>"}' \
http://localhost:8080/api/v1/agent/approvals/<call_id>
Defined in src/api/config/settings.py (Pydantic Settings, .env loaded). Key variables:
APP_NAME, APP_VERSION, APP_DESCRIPTION, DEBUG, LOG_LEVEL, API_V1_STRPOSTGRES_DATABASE_URLENABLE_POSTGRES_CHECKPOINTER (default true), CHECKPOINTER_DATABASE_URLREDIS_URL, RATE_LIMITING_ENABLED, RATE_LIMIT_PER_MINUTEJWT_SECRET, JWT_ALGORITHM, JWT_ACCESS_TOKEN_EXPIRE_MINUTES, JWT_REFRESH_TOKEN_EXPIRE_DAYSMCP_SERVER_URLINTEGRATIONS_SECRET_NAMESPACE (default default)MAX_AUTO_CONTINUE_TURNS, LLM_MAX_ITERATIONSLLM_MODEL (e.g. moonshot/kimi-k2.5), LLM_HOST (optional), provider API key envs like MOONSHOT_API_KEYLLM_REASONING_EFFORT (low, medium, high), LLM_THINKING_BUDGET_TOKENS (Anthropic-specific), LLM_MAX_TOKENS (optional override when thinking is enabled)engine/
├── src/
│ └── api/
│ ├── agent/ # LangGraph workflow (graph, model node, state, prompts, stop)
│ ├── config/ # Settings, DB, rate limiting
│ ├── endpoints/ # FastAPI routers (agent, auth, conversations, team, integrations, health)
│ ├── integrations/ # Provider-specific helpers (Jenkins)
│ ├── middleware/ # CORS, logging
│ ├── models/ # Tortoise ORM models (User, Conversation, Message, Integration, RefreshToken)
│ ├── schemas/ # Pydantic schemas (team)
│ ├── services/ # MCP client, tool executor, approvals, limiter, persistence, titles, checkpointer, stop, tools cache
│ └── utils/ # Helpers, sanitization, time
├── migrations/ # Aerich migrations
└── pyproject.toml # Project dependencies and tooling
| Component | Technology |
|---|---|
| Web Framework | FastAPI + Uvicorn |
| ORM | Tortoise ORM |
| Migrations | Aerich |
| Authentication | fastapi-users (+ tortoise) |
| Streaming | SSE + Redis (pub/sub) |
| Rate Limiting | fastapi-limiter + Redis |
| AI Agent | LangGraph |
| LLM Integration | LiteLLM |
| MCP Communication | FastMCP |
| Database | PostgreSQL |