Getting Started
Arc is for fixed ESP32-S3 firmware where hidden allocation, cache incoherency, or task migration would be a product bug.
Environment
Use the repo environment wrapper so CMake target selection stays portable:
source ./env.shThe wrapper defaults to esp32s3 unless ARC_TARGET is set. Keep target changes in the Arc target selection path; do not bypass it with ad hoc ESP-IDF target commands.
First Build
Build the root firmware project:
idf.py buildBuild a focused ESP32-S3 example:
idf.py -C examples/esp32s3/udp buildList buildable projects with the command that builds each one:
./tools/arc-projects.py --buildable --format reportFast Local Checks
For source changes that do not require flashing hardware, start with:
./tools/host-tests.sh
./tools/format.sh --check
./tools/check-repo.shFor public headers or component dependency changes, validate the clangd compile database:
./tools/clangd-compile-commands.py --validate-arc-headersProject Shape
- Public headers live in
components/arc/include/arc/. components/arc/include/arc.hppis the umbrella include.- Root firmware entry code lives in
main/app_main.cpp. - ESP32-S3 examples live in
examples/esp32s3/. - Host tests and compile contracts live in
tests/host/. - Repo automation lives in
tools/.
First Mental Model
When Arc is new to you, start with ownership instead of feature count:
- put slow services on Core 0 and deterministic work on Core 1;
- name shared state once as static storage, then pass it through
arc::StaticRefor a lane such asarc::Spsc; - use
read<Core>()when code only observes state, andwrite<Core>()only at the owner boundary; - keep hardware topology, buffer storage, and failure policy close together in one owner type.
This path gives beginner code a small shape first, then lets you open specific modules only when the app needs that hardware or protocol.
First Safety Pattern
Before sharing state between tasks or cores, write down the owner in the type:
constinit ControlState control_state{};
using ControlCell = arc::StaticRef<&control_state, arc::Core::core1>;
using ControlRead = ControlCell::Read;
using ControlWrite = ControlCell::Write;
static_assert(ControlCell::can_write<arc::Core::core1>());
static_assert(!ControlCell::can_write<arc::Core::core0>());
static_assert(arc::StaticWritable<ControlCell, arc::Core::core1>);
static_assert(arc::loans_ok<ControlRead, ControlRead>());
static_assert(!arc::loans_ok<ControlRead, ControlWrite>());Open Safety Patterns for the complete copyable version, including core handoff, StaticReads, StaticEdit, proof::Pack, and validation commands.
Reading Path
Read in this order when Arc is new to you:
- Architecture explains why Core 0 and Core 1 have different jobs.
- Safety Patterns gives the first ownership, lifetime, and proof-pack code shapes.
- Production Integration explains the CMake, target, topology, validation, and release-evidence path for product work.
- Troubleshooting maps common setup, CMake, editor, docs, benchmark, and evidence failures to fixes.
- Glossary defines Arc-specific words used throughout the docs.
- Module Guide maps every public header to the problem it solves.
- Module Page Index gives one page per public header, including zero-start steps and proof paths.
- Examples shows which firmware project to build for each hardware lane.
- API Reference gives the exact public methods, failure behavior, and ownership notes.
- Licensing explains the AGPL public path and paid commercial path.
- Benchmarking explains what evidence is required before publishing performance claims.
The shortest practical path is still: read architecture, copy the safety pattern, build the closest example, then open the matching module and API section.