Guidance for AI coding agents working in this repository.
AgentLauncher is a Qt6/QML + C++ desktop app that launches the web UI of AI
coding agents from a card grid. It is config-driven: agent definitions
(commands, web URLs, config directories, colors) live in agents.json, not
in C++.
cmake -B build -DCMAKE_PREFIX_PATH="C:/Qt/6.7.3/msvc2019_64"
cmake --build build- Qt 6.5+ required (modules: Core, Gui, Qml, Quick, Network, LinguistTools).
- CMake 3.16+, C++17.
- Generator: Ninja (preferred) or MSBuild. On Windows with MSVC, run from a
developer command prompt or call
vcvars64.batfirst.
src/ C++ backend: AgentConfig, AgentModel, AgentLauncher, main.cpp
qml/ QML UI: main.qml, AgentCard.qml, ConfigPage.qml
config/ default_agents.json (bundled as a Qt resource)
icons/ SVG icons (bundled as Qt resources)
translations/ .ts translation sources (compiled to .qm at build time, embedded as :/i18n/)
docs/ MkDocs site (English + zh/)
The root object has an optional title field (string). When set, it
overrides the application window title; when empty or absent, the default
AgentLauncher title is used. All other root-level content is the agents
array described below.
Each agent object has: id, name, command, webUrl, configDir, icon,
color, cardColor, installCommand, updateCommand, versionCommand,
setupCommand. See config/default_agents.json. New agents are added by
editing this file (and the on-disk copy at AppConfigLocation/agents.json).
Do not hard-code agent entries in C++.
The icon field accepts: qrc:/icons/<name>.svg (built-in), a local file path
(env vars %VAR% and ~ expanded), an http(s):// URL, or empty (falls back
to qrc:/icons/default.svg). Built-in neutral icons: default, terminal,
cube, bot. AgentConfig::resolveIcon() handles the resolution at parse
time; AgentConfig::expandEnv() does the env-var expansion (also used by
configDir).
The cardColor field is optional — it sets the card's non-running background
color. Empty = default #313244.
The color field is optional — if empty, a color is auto-assigned from a
built-in Catppuccin Mocha palette by cycling through it based on the agent's
position in the list. The assigned color is persisted on first run.
The setupCommand field is optional — it holds a one-time command that runs
before the first launch of an agent (e.g. generating a bearer token for
qwen serve). If the command exits with code 0, the result is persisted to
AppConfigLocation/agent_state.json and the command is never re-run unless
the user picks "Re-initialize" from the card's context menu. An empty
setupCommand means no prerequisite — the agent launches directly.
On load, AgentConfig::load() merges the bundled default into the on-disk
config: any field that is empty on disk is filled from the default, and any
agent present in the default but missing on disk is appended. This migration
ensures older configs (created before installCommand/updateCommand/
versionCommand existed) get the new fields automatically. The updated config
is persisted back to disk if anything changed.
- All agent state (commands, URLs) comes from
AgentConfig. The launcher reads/writes via the model; the UI never holds its own copy of agent data. - Running state is detected by HTTP health check to
webUrl(any HTTP response = running; connection refused/timeout = stopped). Do not add process-sniffing logic — keep it HTTP-based for cross-tool consistency. - Python and Node.js versions are detected at startup via
AgentLauncher::detectRuntimeVersions()(runspython --version/node --versionthroughcmd /c). Results are exposed to QML viaQ_PROPERTY(pythonVersion,pythonInstalled,nodeVersion,nodeInstalled) and shown as badges in the top-right corner of the home page. If a runtime is not found on PATH, the badge shows a red × with a tooltip explaining that agents requiring it may not work. - Launch uses
QProcess::startDetachedso agents survive the launcher closing. - If
setupCommandis set and hasn't been run yet (tracked inagent_state.json),launch()runs it first viacmd /c(no visible window) and only proceeds to the actual launch command on exit code 0. Failures emitlaunchFailed(id, message)with the captured output. - Environment variables in
configDiruse%VAR%(Windows) form; the launcher expands them.~is also expanded to the home dir. - When changing QML, keep the dark theme colors (Catppuccin Mocha palette).
This is an international open-source project. All user-visible strings must be translatable.
- Source language is English. Never write Chinese (or any other non-English
language) inside
tr()orqsTr()— the source string must be English. Chinese and other translations belong in.tsfiles undertranslations/. - C++: wrap every user-visible string in
tr(). - QML: wrap every user-visible string in
qsTr(). - Translation files live in
translations/. The build runslupdate(syncs.tsfrom source) andlrelease(compiles.qm) viaqt6_create_translationin CMakeLists.txt. Compiled.qmfiles are embedded as Qt resources under:/i18n/. main.cppinstalls aQTranslatorthat auto-loads based on system locale.- To add a new language: create
translations/agentlauncher_<locale>.ts, add it to theTS_FILESlist in CMakeLists.txt, then build (lupdate will populate it). Fill in translations and rebuild. - Comments, identifiers, and log messages should also be in English.
- Localized documentation (
docs/zh/,README-zh.md) and language-name labels inmkdocs.ymlare not source code — they are legitimate localized content and are exempt from this rule.
- Don't hard-code agent definitions in C++.
- Don't write non-English source strings inside
tr()/qsTr(). - Don't run
git commit/git pushunless explicitly asked.
Cards show a subtle × in the top-right corner while an agent is running.
Clicking it terminates the process tree this launcher started this
session — launch() records the PID returned by startDetached, and
stop() runs taskkill /F /T /PID … (Windows) so the whole
cmd → .cmd → node tree dies. PIDs are in-memory only, so:
- An agent detected as running via the HTTP health check but not started
from this launcher has no PID;
stop()shows a message instead of killing anything. Stop those via their own command. - After the launcher restarts, PIDs are lost — running agents detected by health check can't be stopped from the card until re-launched here.
Force-kill is intentional for a dev-server launcher; agents that need graceful shutdown should still be stopped via their own command.
launch() resolves the bare program via QStandardPaths::findExecutable
(which applies PATHEXT), then runs .cmd/.bat shims through cmd /c —
CreateProcess alone won't find npm-style shims like qwen.cmd. Launch
failures emit launchFailed(id, message); the UI shows an at-place red flash
on the card plus a popup with the reason.