Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Logs & Artifacts

Five tools deal with everything a build produces — log lines, output files, the firmware manifest, structured error messages, and the size report.

ToolWhat it does
logs.tailGet the last N log lines for a build.
list_artifacts (alias artifacts.list)List the files a build produced and group them by type.
artifacts.manifestRead the official manifest.json from a finished build.
parse_build_errorsTurn raw compiler errors into something readable.
parse_size_reportTurn idf.py size output into a flash/RAM breakdown.

logs.tail

Returns the most recent N lines from a build’s log.

Input:

{
  "task_id": "0abf...e2",
  "lines": 200
}
FieldRequiredNotes
task_idYesThe id returned by build.
linesNoHow many trailing lines to return. Default 100.
since_seqNoOnly return lines after this sequence number (from a previous call).

Returns:

{
  "task_id": "0abf...e2",
  "lines": [
    { "seq": 4198, "ts": 1712340060, "stream": "stdout", "text": "[1234/1500] CC main.o" },
    { "seq": 4199, "ts": 1712340061, "stream": "stderr", "text": "warning: ..." }
  ],
  "next_seq": 4200,
  "more": false
}

more: true means the build is still producing log lines and you should ask again.

Tip: For long-running builds, use the build://log/{task_id} resource instead — it pushes new lines as they happen, instead of you asking over and over.


list_artifacts / artifacts.list

Lists the files a build produced, grouped by type.

Input:

{
  "task_id": "0abf...e2",
  "target": "esp32s3"
}

You can pass a task_id (preferred — looks at the exact build that ran) or just a target (looks at the project’s current build/ folder).

Returns:

{
  "build_dir": "/work/build",
  "artifacts": {
    "firmware": [
      { "path": "build/my-app.bin", "size": 1048576, "sha256": "..." }
    ],
    "elf": [
      { "path": "build/my-app.elf", "size": 4823104 }
    ],
    "bootloader": [
      { "path": "build/bootloader/bootloader.bin", "size": 24576 }
    ],
    "partitions": [
      { "path": "build/partition_table/partition-table.bin", "size": 3072 }
    ],
    "maps": [
      { "path": "build/my-app.map", "size": 8421376 }
    ],
    "other": []
  }
}

The grouping knows about ESP-IDF’s standard output layout (firmware, bootloader, partition table, ELF, maps) and groups files accordingly. Anything it doesn’t recognize lands in other.


CLI: espctl artifacts

Local — scans build/<target>/ for files matching the artifact classifier (.bin, .elf, .map, bootloader, partition table, sdkconfig, etc.) and emits an ArtifactManifest. Does not consult the build server.

espctl artifacts [--target <chip>]

Inputs

FlagDefaultNotes
--targetdefault_target from .espctl.tomlChip — falls back to the project default.

Output

Human mode lists each classified file:

Artifacts in /path/to/build/esp32s3:
  Bin  bootloader/bootloader.bin  (24576 bytes)
  Bin  esp32s3.bin                (1048576 bytes)
  Elf  esp32s3.elf                (4823104 bytes)
  Map  esp32s3.map                (8421376 bytes)

JSON (--json): the full ArtifactManifest with artifacts[] (each entry has artifact_type, path, size_bytes).

Failure modes

  • build/<target>/ doesn’t exist → exit 1.
  • Target invalid → exit 2.

Examples

# Use default_target from .espctl.toml
espctl artifacts

# Explicit target
espctl artifacts --target esp32s3

# JSON shape ready for a script
espctl --json artifacts --target esp32s3

artifacts.manifest

Reads the official manifest.json from a finished build. The manifest is the official record of what the build produced and how to flash it.

Input:

{ "task_id": "0abf...e2" }

Returns: The contents of manifest.json. The exact shape depends on the recipe, but always includes:

{
  "task_id": "0abf...e2",
  "target": "esp32s3",
  "idf_version": "v5.3.1",
  "profile": "release",
  "git_commit": "abc123",
  "built_at": 1712340060,
  "artifacts": [
    { "name": "firmware", "path": "build/my-app.bin", "size": 1048576, "sha256": "..." },
    { "name": "bootloader", "path": "build/bootloader/bootloader.bin", "offset": "0x0" },
    { "name": "partition-table", "path": "build/partition_table/partition-table.bin", "offset": "0x8000" },
    { "name": "app", "path": "build/my-app.bin", "offset": "0x10000" }
  ],
  "flash_size": "4MB",
  "flash_freq": "80m",
  "flash_mode": "dio"
}

This is the right tool to call when your assistant needs to know “which file goes to which flash address”.

Security note: Your compiled firmware may contain embedded secrets (Wi-Fi credentials, API keys). Treat .bin files as sensitive and don’t share them publicly.


parse_build_errors

Takes a raw compiler/linker error log (or a task_id) and returns structured, de-duplicated error messages.

Input:

{ "task_id": "0abf...e2" }

…or:

{ "log_text": "main.c:42:5: error: ..." }

Returns:

{
  "errors": [
    {
      "file": "main/app_main.c",
      "line": 42,
      "column": 5,
      "severity": "error",
      "message": "implicit declaration of function 'foo'",
      "context": [
        "  40 | void app_main(void) {",
        "  41 |     printf(\"hello\\n\");",
        "  42 |     foo();",
        "                       ^"
      ]
    }
  ],
  "warnings": [...],
  "summary": "1 error, 0 warnings"
}

Knows about GCC, Clang, CMake, and ESP-IDF’s own error formats. Useful when your assistant wants to show you “here’s the line to fix” instead of dumping 500 lines of log.


parse_size_report

Parses the output of idf.py size and returns a flash/RAM breakdown by section.

Input:

{ "task_id": "0abf...e2" }

Returns:

{
  "target": "esp32s3",
  "total_flash": { "used": 1048576, "free": 3145728, "total": 4194304 },
  "total_ram":   { "used":  131072, "free":  393216, "total":  524288 },
  "sections": [
    { "name": ".text", "size": 524288, "memory": "flash" },
    { "name": ".rodata", "size": 262144, "memory": "flash" },
    { "name": ".data", "size":  16384, "memory": "ram" },
    { "name": ".bss",  "size": 114688, "memory": "ram" }
  ]
}

Combine with parse_build_errors for a complete post-build summary your assistant can present in one go.


CLI: espctl clean

Removes per-target build artifacts. With --full, removes the entire build/, sdkconfig, and managed_components/. Operates locally only — does not touch the build server.

espctl clean [--full] [target]

Modes

  • Incrementalespctl clean <target> deletes the files that espctl_core::clean_plan lists for build/<target>/....
  • Fullespctl clean --full deletes the whole build/, sdkconfig, and managed_components/ (fullclean_plan). The positional target is ignored when --full is set.

Flag matrix

ArgumentDefaultNotes
target (positional)Required unless --full. Chip name.
--fullfalseSwitch to full clean.

Output

Human mode:

Removed:
  /path/to/build/esp32s3/CMakeCache.txt
  /path/to/build/esp32s3/CMakeFiles
  ...

…or Nothing to clean. if nothing matched.

JSON (--json): { "removed": ["/path/...", ...] }.

Failure modes

ConditionExitMessage
neither target nor --full given2target required for clean (use --full for full clean)
invalid target2invalid target: <name>

Pre-flight

Before a destructive cleanup (especially in CI), get a preview with the MCP get_clean_plan tool — it tells you exactly what would be removed, without removing anything.

Examples

# Incremental — only build/esp32s3/...
espctl clean esp32s3

# Full wipe — build/, sdkconfig, managed_components/
espctl clean --full

# JSON for scripting
espctl --json clean esp32s3

See also

  • build — every artifact tool needs a task_id from a finished build.
  • Resourcesbuild://log/{task_id} and build://artifacts/{target} are streaming alternatives to these tools.