Project Management
Six tools handle project setup, scaffolding, chip selection, settings
checking, and IDF version pinning. Together they’re enough to take an
empty folder to “ready to build” without you ever opening menuconfig.
| Tool | What it does |
|---|---|
project.init | Create .espctl.toml and the build folder for a new project. |
project.create | Create a new ESP-IDF project from a template (hello_world, blink, empty). |
project.create_component | Add a new component to an existing project. |
set_target | Change the chip target for an existing project. |
validate_config | Check that a .espctl.toml file is valid. |
idf_select_version (alias idf.select_version) | Figure out which IDF version a build will use. |
project.init
Sets up an espctl project in a folder by creating .espctl.toml and
the standard build subfolders.
Input:
{
"target": "esp32s3",
"idf_version": "v5.3.1",
"name": "my-project"
}
| Field | Required | Notes |
|---|---|---|
target | Yes | Chip — esp32, esp32s2, esp32s3, esp32c2, esp32c3, esp32c6, esp32h2, esp32p4. |
idf_version | No | Pin a specific IDF version. Defaults to the build server’s latest stable. |
name | No | Friendly project name (saved into .espctl.toml). |
Returns:
{
"project_root": "/path/to/project",
"config_path": "/path/to/project/.espctl.toml",
"target": "esp32s3",
"idf_version_resolved": "v5.3.1"
}
What it does to your project folder:
- Creates
.espctl.tomlif it doesn’t exist (won’t overwrite). - Creates
build/if it doesn’t exist. - Writes a default
.idf-versionfile pinning the IDF version (if you asked for one).
project.init is safe to run twice — the second run does nothing.
project.create
Creates a brand-new ESP-IDF project from a template. Generates
CMakeLists.txt, main/main.c, and optionally sdkconfig.defaults
and .idf-version.
Input:
{
"name": "my-sensor",
"target": "esp32s3",
"template": "hello_world"
}
| Field | Required | Notes |
|---|---|---|
name | Yes | Project name (used as directory name). Alphanumeric, underscore, hyphen, 1-64 chars. |
target | No | Chip target. Written to sdkconfig.defaults. |
version | No | IDF version to pin in .idf-version. |
template | No | "hello_world" (default), "blink", or "empty". |
Returns:
{
"project_dir": "/path/to/my-sensor",
"files_created": ["CMakeLists.txt", "main/main.c", "main/CMakeLists.txt"],
"target": "esp32s3",
"idf_version": "v5.3.1"
}
The project is created at <project_root>/<name>.
project.create_component
Adds a new component to an existing ESP-IDF project. Creates
components/<name>/ with CMakeLists.txt, a header, and a source
file.
Input:
{
"name": "my_driver",
"project_path": "/path/to/project"
}
| Field | Required | Notes |
|---|---|---|
name | Yes | Component name. Alphanumeric and underscore, 1-64 chars. |
project_path | No | Project directory. Defaults to the server’s project root. |
Returns:
{
"component_dir": "components/my_driver",
"files_created": ["CMakeLists.txt", "include/my_driver.h", "my_driver.c"]
}
set_target
Changes the chip target for a project that’s already been set up.
Updates .espctl.toml, regenerates sdkconfig.defaults, and clears
the build cache.
Input:
{ "target": "esp32c6" }
Returns:
{
"previous_target": "esp32s3",
"new_target": "esp32c6",
"rebuild_required": true
}
Heads up: Switching chips always clears the build cache. Your next
build will be a full rebuild from scratch. There’s no shortcut.
CLI: espctl set-target
A local helper that creates build/<target>/ and validates the chip
name. It does not call the build server or update .espctl.toml
— for the server-side equivalent, use the MCP
set_target.run tool.
espctl set-target <target>
Inputs
| Argument | Notes |
|---|---|
<target> (positional) | One of esp32, esp32s2, esp32s3, esp32c2, esp32c3, esp32c6, esp32h2, esp32p4. Anything else exits with code 2 (invalid target). |
Output
Human mode:
Target set to esp32s3 (build dir: /path/to/build/esp32s3)
JSON (--json):
{
"target": "esp32s3",
"build_dir": "/path/to/build/esp32s3"
}
What it actually does
- Validates
<target>against the supported chip list. - Creates
build/<target>/if it doesn’t exist (idempotent). - Writes nothing to
.espctl.toml. The nextespctl buildreads the directory layout to decide where to put output.
Examples
# Switch project to ESP32-C3 (creates build/esp32c3/)
espctl set-target esp32c3
# JSON output for scripting
espctl --json set-target esp32s3
validate_config
Checks a .espctl.toml file and returns either “valid” or a structured
error.
Input:
{
"content": "[project]\nname = \"my-app\"\ntarget = \"esp32s3\"\n..."
}
You can also pass a path:
{ "path": "/path/to/.espctl.toml" }
Returns:
{
"valid": true,
"warnings": [],
"normalized": { ... }
}
…or, on failure:
{
"valid": false,
"errors": [
{
"line": 7,
"column": 14,
"message": "unknown field `targe` (did you mean `target`?)"
}
]
}
This tool is read-only and safe to call as often as you like — many
assistants run it after every edit to .espctl.toml for live checking.
idf_select_version / idf.select_version
Tells you which IDF version a build will use, given the project settings, what the build server has, and any explicit pin.
Input:
{ "version": "v5.3.1" }
version is optional. When you leave it out, the tool figures it out
based on the project’s preferences:
- Explicit
versionargument - Project’s
.idf-versionfile [idf]section in.espctl.toml- Build server’s default
Returns:
{
"resolved": "v5.3.1",
"source": "explicit-argument",
"store_path": "/var/lib/aegis/espctl-store/idf/v5.3.1",
"alternatives": ["v5.2.2", "v5.4.0"]
}
source tells you why this version was picked, which is handy when a
build picks an unexpected version. alternatives lists every other IDF
version the build server has, so your assistant can suggest upgrades or
downgrades.
See also
store_versions— list every IDF version the build server has.doctor— health check.- Quick Start — uses
project.initto set up a fresh project.