Kucatoo-Code · Wiki

Configuration

All runtime configuration is via environment variables, conventionally stored in a .env file at the project root. .env.example documents the main vars; copy it to .env and fill in values. .env is gitignored — it holds secrets.

.env loading

model_harness/web/app.py:59 loads .env at import time:

load_dotenv(BASE_DIR / ".env", override=True)

Ports

Three HTTP/WS services, three ports:

Port Service Configured by Notes
5000 Flask web app (UI + /api/*) HOST, PORT Started by run_webapp.py:57-75 (threaded=True for SSE)
5001 Server manager (Start/Stop/Restart) MANAGER_PORT server_manager.py:60; binds 127.0.0.1 only; stdlib-only, no .env
5002 Voice Chat (STS) WebSocket proxy VOICE_WS_HOST, VOICE_WS_PORT voice_ws_server.py:118-127; daemon thread started from run_webapp.py:66-69

The voice WS proxy exists because Werkzeug's WS layer intermittently emits frames Chrome rejects; the standalone server uses the websockets library (voice_ws_server.py:1-14). It relays to wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime, adding the DASHSCOPE_API_KEY bearer header browsers cannot set. A legacy in-Flask proxy also exists at /ws/voice (app.py:172-302).

Environment variables

Provider API keys

At least one provider key is required. Key resolution per model: direct key → primary env var → fallback env var (model_harness/core/config.py:173-183). See Provider Mesh for which models use which key.

Variable Used by Default / fallback
KIMI_API_KEY All four Kimi chat models Fallback: MOONSHOT_API_KEY
MOONSHOT_API_KEY Fallback for Kimi models Optional
BAILIAN_CODING_PLAN_API_KEY deepseek-v4-pro, glm-5.2, qwen3.7-max, qwen3.8-max (Bailian token-plan endpoint) No fallback; not listed in .env.example
DEEPSEEK_API_KEY deepseek-v4-flash (direct api.deepseek.com)
MINIMAX_API_KEY MiniMax-M3 chat; MiniMax-H3 video
MINIMAX_GROUP_ID MiniMax-M3 GroupId header, resolved at call time Header dropped if unset (config.py:220-240)
DASHSCOPE_API_KEY Voice WS proxies (app.py:188, voice_ws_server.py:49), Qwen TTS / voiceclone / imagegen Not used by chat presets
GLM_API_KEY, ZAI_API_KEY Listed in .env.example, but no live chat preset reads themglm-5.2 is served via the Bailian endpoint with no Zhipu fallback (config.py:415-419)

Tool API keys (optional)

Variable Used by Default
TAVILY_API_KEY Builtin web_search tool Tool reports a clear error when unset
OPENAI_API_KEY Remote embedding engine for the memory subsystem (embedding_api_key_env, config.py:622) Local embedding engine needs no key

SkillDAG sidecar (optional, off by default)

Variable Default Purpose
SKILLDAG_ENABLED false Connect the query pipeline to an external SkillDAG server
SKILLS_AGENT_ENABLED true Register the use_skill tool and list committed skills in agent system prompts
DOMAIN_CONTEXT_ENABLED true Inject domain RAG context into agent system prompts on confident detection
USER_PROFILE_CONTEXT_ENABLED true Inject known-user preference context into agent system prompts
SESSION_LOG_ENABLED true Persist session stores (direct-chat turns, agent resume history) to <DATA_DIR>/sessions/*.jsonl so they survive restarts
SKILLDAG_URL http://localhost:8000 SkillDAG server address
SKILLDAG_READ_GRAPH default Graph for skill enrichment (read path)
SKILLDAG_WRITE_GRAPH default Graph for skill mining (write path, fire-and-forget)
SKILLDAG_TIMEOUT 5 Sidecar timeout (seconds)
SKILLDAG_ENRICH_ENABLED true Prompt enrichment with relevant skills
SKILLDAG_MINE_ENABLED true Mine finished query/response pairs for skills

MCP satellite servers (optional)

Variable Default Purpose
HARNESS_MCP_SERVERS unset JSON array of MCP stdio server configs; alternative to the YAML mcp_servers: list (config.py:608-610). Missing/crashed servers only log warnings

Language servers (LSP tools, optional)

Variable Default Purpose
HARNESS_LSP_PYTHON_CMD / _ARGS pylsp / empty Python language server binary
HARNESS_LSP_TS_CMD / _ARGS typescript-language-server / --stdio TS/JS language server
HARNESS_LSP_GO_CMD / _ARGS gopls / serve Go language server
HARNESS_LSP_IDLE_TIMEOUT 1800 Seconds an idle language server stays alive

Missing binaries produce an Error: ... not installed tool result; nothing is auto-installed.

File locations

Resolution rules (app.py:62-79): ~ expands to the user home; relative paths resolve against the project root (not the cwd); absolute paths are honored as-is; / and \ both work on Windows. All directories are created at startup (app.py:101-103).

Variable Default Holds
DATA_DIR <project>/data Root for all generated files: harness subsystem storage (memory DBs, schedules, skills, knowledge bases, user profiles, guests DB) plus the subfolders below
HARNESS_DATA_DIR set from DATA_DIR Legacy alias; the app sets it via os.environ.setdefault so the harness factory roots subsystem storage at DATA_DIR (app.py:133-137)
PROMPTS_DIR <DATA_DIR>/prompts Saved user prompts
RESPONSES_DIR <DATA_DIR>/responses Saved model responses
LOG_DIR <DATA_DIR>/logs App log files
TRACES_DIR <DATA_DIR>/traces Trace files (app.py:97-99; not listed in .env.example)
WORKSPACE_DIR sibling of DATA_DIR named workspace Agent tool workspace (files written by write_file/create_file); also the Workspaces-panel root. Active workspace persisted to <DATA_DIR>/active_workspace.json, stats to <DATA_DIR>/workspace_stats/

Web server and auth

Variable Default Purpose
HOST 127.0.0.1 Bind interface. 0.0.0.0 exposes the app to the network — set API_TOKEN if you do; startup logs a loud warning when binding beyond localhost without a token (run_webapp.py:60-64, app.py:154-160)
PORT 5000 Flask listen port (run_webapp.py:58)
API_TOKEN unset = no auth When set, ALL /api/* routes require Authorization: Bearer <token> or ?token=<token> (auth.py:108-118; constant-time compare). The UI shows a token field persisted to localStorage. Recommended when HOST is not 127.0.0.1
MANAGER_TOKEN unset = open Bearer token for server_manager.py (:5001). Use the same value as API_TOKEN so the UI's server-control buttons work. Not read from .env — export in shell
MANAGER_PORT 5001 Server manager port (server_manager.py:60)
FLASK_SECRET random per restart Flask session-cookie signing key (app.py:124). Unset means sessions reset on restart
KUCATOO_REMOTE unset =1 marks a platform-managed deployment: POST /api/server/stop returns 400 disabled (routes_server.py:24-30) and pages get a remote_mode flag (routes_pages.py:91)
VOICE_WS_HOST falls back to HOST Bind host for the :5002 voice WS proxy (voice_ws_server.py:124-125)
VOICE_WS_PORT 5002 Voice WS proxy port (voice_ws_server.py:126)

Logging

Variable Default Purpose
LOG_LEVEL INFO Python logging level: DEBUG, INFO, WARNING, ERROR (run_webapp.py:45-47)

Data directory layout

With defaults (DATA_DIR = <project>/data):

<project>/
├── data/                      # DATA_DIR — all internal state
│   ├── prompts/               # PROMPTS_DIR
│   ├── responses/             # RESPONSES_DIR
│   ├── logs/                  # LOG_DIR
│   ├── traces/                # TRACES_DIR
│   ├── active_workspace.json  # selected workspace
│   ├── workspace_stats/       # per-workspace usage stats
│   └── ...                    # memory DBs, schedules, skills, KBs,
│                              # user profiles, guests DB
└── workspace/                 # WORKSPACE_DIR — agent-written files,
                               # one subdir per selectable workspace

The workspace is deliberately a sibling of DATA_DIR, not a child, so user-generated files stay separate from internal app state (.env.example lines 152-162).

Auth model summary

model_harness/web/auth.py implements a role hierarchy: owner (Google OAuth, when configured) > token (the API_TOKEN convenience path) > guest (sandboxed trial tokens). With no auth configured, everything is open — the intended local single-user default on 127.0.0.1 (auth.py:11-16). Webhook-triggered schedules without a webhook_secret accept unauthenticated triggers (backward-compatible default, independent of API_TOKEN).

verified against code: 2026-08-15