Public C++ API¶
TopoExec is pre-1.0, but embedders should still know which headers are intended product surface and which ones are low-level runtime machinery. Prefer topoexec::runtime for embedded C++ applications and add topoexec::yaml only when YAML loading or JSON/Mermaid plan helpers are needed.
CMake Targets¶
| Target | Intended use | Dependency boundary |
|---|---|---|
topoexec::core |
Header-only value types shared by runtime users. | No YAML, CLI, adapter, or tool dependency. |
topoexec::runtime |
Components, C++ graph construction, validation, runtime execution, payload helpers, metrics, and traces. | No YAML parser or CLI dependency for pure C++ embedding. |
topoexec::yaml |
YAML schema_version: 1 loading and optional JSON/Mermaid plan helpers. |
Depends on topoexec::runtime and parser/JSON libraries. |
topoexec::adapter_sdk |
Header-only adapter SDK v0 boundary for future adapter packages. | Depends on topoexec::runtime; no YAML, CLI, ROS, OpenTelemetry, Prometheus, Python, Perfetto, or plugin-loader dependency. |
topoexec::c_api |
Optional unstable C API/FFI preview target. | Depends on topoexec::runtime; no YAML, CLI, adapters, Python, dynamic plugin, or ABI-stability promise. Default OFF. |
topoexec::plugin_loader |
Optional trusted-native dynamic component loader preview target. | Depends on topoexec::runtime; no YAML, CLI, adapters, Python, sandbox, graph discovery, or stable ABI promise. Default OFF. |
topoexec_adapters::otel |
Optional OTel exporter preview target. | Depends on topoexec::adapter_sdk; no core/runtime reverse dependency and no external telemetry SDK. Default OFF. |
topoexec_adapters::prometheus |
Optional Prometheus text exporter preview target. | Depends on topoexec::adapter_sdk; no core/runtime reverse dependency, no HTTP server, and no external Prometheus library. Default OFF. |
topoexec_adapters::ros2 |
Optional ROS 2 fake-boundary preview target. | Depends on topoexec::adapter_sdk; no core/runtime reverse dependency, no ROS client library, no executor, and no schema fields. Default OFF. |
Installed package config metadata exposes TOPOEXEC_VERSION,
TOPOEXEC_SCHEMA_VERSION, TOPOEXEC_SEMANTIC_CONTRACT_VERSION,
TOPOEXEC_HAS_RUNTIME, TOPOEXEC_HAS_ADAPTER_SDK, TOPOEXEC_HAS_C_API,
TOPOEXEC_HAS_PYTHON_PREVIEW, TOPOEXEC_HAS_PLUGIN_LOADER,
TOPOEXEC_HAS_YAML, TOPOEXEC_HAS_OTEL_ADAPTER, TOPOEXEC_HAS_PROMETHEUS_ADAPTER,
TOPOEXEC_HAS_ROS2_ADAPTER, TOPOEXEC_HAS_CLI, and
TOPOEXEC_HAS_EXAMPLES so downstream projects can assert package capabilities
at configure time. The Python automation preview is not a C++ target or native
extension; when enabled, it installs topoexec_preview for CLI-backed
automation only. The plugin loader preview is a C++ target and header, but it is
trusted-native-code only and does not promise sandboxing or ABI stability.
Stability markers¶
Generated Doxygen output is an optional lookup view over these same installed
headers; it does not change the stability class of any API. See
doxygen.md for the local build target and the Pages /api/
publication boundary.
Each installed public header now starts with one of these markers:
API stability: stable-v0.2— intended embedder API for the nextv0.2.0-alpha.0line. Source compatibility is best-effort through0.x; breaking changes need a changelog and versioning note.API stability: mixed— the header contains a stable subset used by stable APIs plus experimental low-level types.API stability: experimental— public because tests, advanced examples, or future extension points need it, but normal embedders should avoid depending on details before beta.internal-use-only— must not be installed underinclude/. Internal headers belong insrc/,tools/, or private build trees.
Header stability matrix¶
Stable-v0.2 headers¶
These headers are safe for ordinary runtime users to include directly.
| Header | Main surface | Notes |
|---|---|---|
topoexec/runtime/status.hpp |
Status, Result<T> |
Status-returning hooks use this instead of exceptions when failures are expected. |
topoexec/runtime/clock.hpp |
TimestampDomain, EventTimestamp |
Stable timestamp value types for event-time payloads and policies. |
topoexec/runtime/payload.hpp |
Built-in payload variants, schema constants, typed access helpers, payload schema summaries | Custom OpaquePayload/make_custom_payload are stable enough for in-process embedding; external shared-memory zero-copy remains out of scope. |
topoexec/runtime/cancellation.hpp |
CancellationToken, CancellationSource |
Stable cooperative cancellation value types; they report requests and observations without hard preemption. |
topoexec/runtime/component.hpp |
Component, ComponentDescriptor, PortDescriptor, PortMultiplicity, GraphContext, Invocation, InvocationMetadata, InputView, ConfigView, LoopIterationContext, LoopConvergenceReport, publication result |
GraphContext::publish() stages through the runtime publisher and never calls downstream components directly; descriptor port metadata is optional and semantic-validation only. Solver-style CompositeLoops can report convergence through GraphContext::report_loop_convergence(). |
topoexec/runtime/component_registry.hpp |
ComponentRegistry, ComponentRegistration, ComponentFactory |
Stable registry entry point for embedders and examples. |
topoexec/runtime/diagnostics.hpp |
GraphDiagnosticDescriptor, kGraphDiagnosticSchemaVersion, graph_diagnostic_registry() |
Stable diagnostic code/category/severity descriptors for editor/tooling integrations. |
topoexec/runtime/graph.hpp |
GraphSpec, GraphHierarchyEntry, edge/channel/trigger policy specs, validation and compile result structs, runtime metric samples, GraphInputLimits |
The C++ graph model is stable; YAML loader declarations in this header require linking topoexec::yaml when called. |
topoexec/runtime/graph_builder.hpp |
GraphBuilder and helper constructors |
Convenience only; it does not create a second graph model. |
topoexec/runtime/runtime_runner.hpp |
RuntimeRunner, RuntimeRunnerOptions, RuntimeRunnerResult, RuntimeTraceEvent, RuntimeError, health event result fields |
Primary execution API for embedded applications. |
Mixed stability headers¶
| Header | Stable subset | Experimental subset |
|---|---|---|
topoexec/runtime/buffer.hpp |
SharedBuffer, FrameView, BinaryBlobPayload support types |
BufferPool, BufferPoolConfig, LoanedFrame, and pool metrics are in-process helpers; external allocator/SHM ownership remains out of scope. |
topoexec/runtime/scheduler.hpp |
SchedulerStopToken and SchedulerStopReason as used by RuntimeRunnerOptions/RuntimeRunnerResult |
Direct scheduler classes, lane metric structs, worker-loop details, and lane implementation hooks may change before beta. |
Experimental headers¶
| Header | Reason |
|---|---|
topoexec/runtime/channel.hpp |
Low-level bounded channel bus, publication router, channel read APIs, and channel metrics. Prefer RuntimeRunner/GraphContext for ordinary embedding. |
topoexec/runtime/event_runtime.hpp |
Lower-level event runtime surface used by tests and advanced embedders. |
topoexec/runtime/health.hpp |
HealthEvent and bounded HealthEventSink helpers used by the runtime observer surface. |
topoexec/runtime/live_event.hpp |
Low-level fixed-size live observe event records and numeric event identifiers. CLI/live observe JSON schema remains the user-facing contract. |
topoexec/runtime/live_observe.hpp |
Low-level bounded live observe transport/session helpers. RuntimeRunnerOptions::live_observe and topoexec graph observe are the supported integration path. |
topoexec/runtime/metric_schema.hpp |
Runtime metric descriptor registry, schema version, and sample validation helpers for exporter-safe cardinality. |
topoexec/runtime/state.hpp |
Namespaced blackboard and graph/component config snapshot stores with epoch-boundary commits and experimental config transaction metadata. |
topoexec/runtime/task_executor.hpp |
ITaskExecutor, DeterministicTaskExecutor, and opt-in ThreadedTaskExecutor preview. |
topoexec/runtime/trigger_policy.hpp |
Trigger engine internals and readiness helpers. |
topoexec/c_api/topoexec.h |
C API/FFI preview: opaque handles, create/run/destroy, borrowed error strings, and metric iteration for downstream C smoke tests. |
topoexec/plugins/loader.hpp |
Dynamic plugin loader preview: manifest/version/schema views, load options/result errors, and trusted native loader entry point. |
topoexec/adapters/sdk.hpp |
Adapter SDK v0 preview: observer aliases, BoundaryBridge, and ComponentFactoryProvider for dependency-free future adapter packages. |
topoexec/adapters/otel.hpp |
OTel exporter preview: dependency-free in-memory mapping records over runtime metrics, trace, health, and errors. |
topoexec/adapters/prometheus.hpp |
Prometheus exporter preview: dependency-free text exposition mapping over runtime metric descriptors and histogram summaries. |
topoexec/adapters/ros2.hpp |
ROS 2 adapter preview: dependency-free topic/service/action endpoint mapping and fake boundary bridges over Adapter SDK types. |
topoexec/common/metrics.hpp |
Small metrics registry/value helpers; runtime metric schema descriptors live in topoexec/runtime/metric_schema.hpp. |
topoexec/common/logging.hpp |
Structured logging helper; adapter/exporter boundary is not stable yet. |
topoexec/common/trace.hpp |
Trace collection helper used by the runtime; public timeline fields are exposed through RuntimeTraceEvent. |
No installed header is intentionally internal-use-only. If future work needs internal-only declarations, place them outside include/ or stop installing them.
Function and class stability¶
| Surface | Stability | Compatibility expectation |
|---|---|---|
Component::configure/activate/execute/deactivate plus status variants |
stable-v0.2 | Existing hook meanings should not silently change. Reset/pause/resume/snapshot/restore hooks and validate/apply config hooks are additive and experimental until lifecycle/config policy is stable. |
GraphContext::publish() and publish_shared() |
stable-v0.2 | Publication remains staged/routed by runtime; no direct downstream calls. |
GraphContext::loop_iteration and report_loop_convergence() |
experimental | In-process solver-style CompositeLoop hook. Components can report converged, optional residual, and a bounded reason string; dynamic solver plugins remain out of scope. |
Invocation, InvocationMetadata, InputView, typed payload helpers |
stable-v0.2 | Existing payload lookup and typed access behavior should remain source-compatible; metadata fields are additive trace/debug context and Invocation::cancel_requested() is cooperative. |
CancellationToken / CancellationSource |
stable-v0.2 | Cancellation requests are observable by components, tasks, and loops; observation is metric/trace evidence, not forced termination. |
ComponentRegistry::register_component/create/metadata/types |
stable-v0.2 | Registration metadata can gain additive fields. |
GraphSpec, LaneSpec, EdgeSpec, TriggerPolicySpec, CompositeLoopSpec, GraphHierarchyEntry |
stable-v0.2 for current fields | Additive fields are allowed only when schema/runtime meaning stays compatible. LoopPolicySpec::solver_iteration, residual threshold, and partial-success fields are experimental additions. GraphHierarchyEntry records compile-time subgraphs[] expansion metadata only; it does not imply runtime nesting. Trigger v2 watermark, condition, debounce, and rate_limit policy fields are additive preview fields and may be refined before beta. |
ActionDescriptor, EventKind::kActionGoal, EventKind::kActionCancel |
experimental preview | Descriptor/API preview concepts only. Schema-v1 graph event_sources do not create action-triggered runtime invocations yet. |
GraphInputLimits, default_graph_input_limits(), load_graph_text(..., limits), load_graph_file(..., limits) |
stable-v0.2 | Parser-limit fields can be tightened by embedders and CLI tooling; defaults should remain conservative and source-compatible. |
YAML templates[] / template_instances[] |
stable-v0.2 schema-loader surface | Template definitions are not retained in GraphSpec; they expand through strict parameter substitution before validation/runtime execution. |
validate_graph, compile_graph, GraphDiagnostic |
stable-v0.2 | New diagnostics may be added; existing codes should keep meanings. |
RuntimeRunner::run(), RuntimeRunnerOptions, and RuntimeRunnerResult |
stable-v0.2 | New result fields may be added; existing counters, observer registration, trace vectors, metric vectors, health event vectors, and structured runtime error fields should keep meanings. channel_drop_count is real drops only; use channel_overwrite_count, channel_reject_count, channel_stale_drop_count, and channel_deadline_miss_count when explaining channel degradation. |
RuntimeObserver, ResultSink, MetricSink, TraceSink, NoopRuntimeObserver, InMemoryRuntimeObserver |
stable-v0.2 | Observer callbacks are best-effort result/metric/trace/health/error delivery for adapters. InMemoryRuntimeObserver is bounded and returns vector snapshots; its internal storage is not part of the API. Callback failures are reported as observer diagnostics, not runtime semantic failures. |
RuntimeMetricDescriptor, runtime_metric_descriptors(), validate_runtime_metric_samples() |
stable-v0.2 | Metric names, kind/unit metadata, allowed labels, and descriptor schema version are the exporter-safe contract. Add names rather than changing meanings. |
RuntimeTraceEvent and kRuntimeTraceSchemaVersion |
stable-v0.2 | Trace schema version 1 events expose ordered timeline fields plus phase/component/channel/lane/worker/epoch/transaction/correlation/causation identifiers. A compatibility constructor preserves the prior name/trace-id/timing/attributes shape; add fields or event names rather than changing existing meanings. |
SchedulerStopSource/SchedulerStopToken |
stable-v0.2 through runner options | Direct scheduler registry/metrics internals remain experimental. |
ComponentStateSnapshot, reset/snapshot/restore runner options/results |
experimental | Stateful lifecycle support is start/end-boundary only; pause/resume policy and hot live control may change before beta. |
RuntimeStateStore, ConfigSnapshotStore |
experimental | State snapshots and config transactions are epoch-boundary, observable APIs; transaction metadata and immediate-update escape hatches may be reshaped before beta. |
ITaskExecutor, DeterministicTaskExecutor, ThreadedTaskExecutor |
experimental | Deterministic and threaded executor shutdown/admission details may change before beta. Current threaded admission counts pending, active, and undrained completed records toward its bound. Direct sink registration is non-owning and must outlive concurrent executor operations. |
RuntimeChannelBus, RuntimePublicationRouter, TriggerPolicyEngine, EventRuntime |
experimental | Advanced runtime internals may change as scheduler/channel/trigger v2 goals land. Direct RuntimeChannelBus health sink registration is non-owning and must outlive concurrent channel operations. |
topoexec/c_api/topoexec.h opaque handles and functions |
experimental | C API/FFI preview, ABI version 0. Names, ownership details, and exported functions may change before any stable ABI promise. |
topoexec::plugins::load_plugin, LoadedPlugin, and manifest view structs |
experimental | Plugin loader preview, plugin API version 0. The loader requires explicit paths and trusted native code, validates manifest/schema/component descriptors, defaults to no dlclose, and may change before any stable plugin ABI. |
topoexec::adapters::BoundaryBridge, BoundaryMessage, BoundaryPollResult, BoundaryBridgeStatus, ComponentFactoryProvider |
experimental | Adapter SDK v0 is a header-only boundary. Bridges are bounded/best-effort and providers register components explicitly; concrete adapter packages and dynamic discovery remain future work. |
topoexec::adapters::otel::ExporterPreview and preview record structs |
experimental | Dependency-free OTel-shaped mapping over the observer API. Record names and options may change before production exporter work. |
topoexec::adapters::prometheus::TextExporterPreview |
experimental | Dependency-free Prometheus text exposition mapping over metric descriptors and custom histogram summaries. Text names/options may change before production exporter work. |
topoexec::adapters::ros2::* preview endpoint and fake bridge types |
experimental | Dependency-free ROS 2 boundary mapping preview. Names/options may change before any real ROS package or client-library integration. |
Compatibility Expectations¶
- Source compatibility in
0.xis best-effort forstable-v0.2headers. - Binary compatibility is not promised before
1.0.0; rebuild downstream applications when upgrading. - Stable enum names, field names, and result field meanings should not change inside a patch release.
- Additive fields and metrics may appear in minor releases.
- Experimental headers may change in minor releases, but changes should still be documented.
Deprecation policy¶
Before 1.0.0, TopoExec still optimizes for semantic clarity over permanent
compatibility. The beta-readiness bar is therefore a visible deprecation path,
not an ABI-freeze claim:
stable-v0.2headers and documented CLI JSON/schema fields should receive at least one prerelease/minor-line deprecation note before removal or rename when practical. Immediate removal is reserved for security, data-corruption, unsound semantic, or build-breaking defects.- Deprecated stable APIs should name the replacement in
CHANGELOG.mdand this API map or the relevant reference page. Keep source compatibility through the next prerelease line when the compatibility shim is small and behaviorally honest. - Mixed headers follow the stable policy for their stable subset; explicitly experimental classes, fields, low-level scheduler/channel hooks, lifecycle extensions, and adapter-preview helpers may change with a changelog note and no long deprecation window.
- CLI JSON and schema-compatible surfaces should prefer additive fields. Removing or renaming stable fields requires a changelog and versioning note; schema semantic changes require the schema/semantic-contract rules below.
- Human-readable CLI output, examples, and docs may evolve more freely, but changes that alter a documented behavior claim still need a release note.
Schema and semantic compatibility¶
Schema v1 is strict and compatibility-preserving:
- Additive fields are allowed only when they do not change v1 meaning.
- Unknown fields remain invalid.
- Breaking semantic changes require a schema version bump.
- New adapter-specific fields should not be added to core schema v1 unless they are useful without that adapter.
A schema version bump is required when a graph that was valid under the old schema would be rejected or would mean something different because of:
- a removed or renamed root field;
- a removed or renamed enum value;
- a new required field without a backward-compatible default;
- changed edge visibility, trigger readiness, channel overflow, or loop ownership semantics;
- incompatible validation behavior for existing graph files.
Additive optional fields with documented defaults can remain in schema v1. Schema v2 notes are the review gate for candidates such as runtime-nested subgraphs, YAML-authored typed ports, graph-declared adapter or plugin/package discovery, arbitrary trigger expressions, and schema-selected runtime behavior.
CLI JSON Compatibility¶
CLI JSON fields are part of the user-facing tooling contract even though the CLI implementation is not an embedder API.
- Stable commands:
plan,metrics,trace,schema dump,schema check,doctor, anddiff-planshould keep existing field names and JSON value types within a minor release.metricsandtraceJSON include explicit schema-version fields for exporter compatibility. benchJSON is machine-readable but still experimental; add fields instead of changing existing field meanings where practical.- New fields are allowed. Removing or renaming fields requires a changelog note and, when schema-related, a versioning note.
- Human-readable text output is allowed to evolve more freely than JSON.
- Golden drift coverage lives in
tests/golden/for plan, metrics, trace, Chrome trace, render, schema dump, and doctor JSON. Benchmark JSON has separate output-contract coverage intests/bench/check_bench_contract.pybecause timings are intentionally volatile.
Adapter-preview stability¶
Adapter SDK v0 is a preview/dependency-free boundary:
- Core/runtime headers must not include ROS 2 client-library, OpenTelemetry, Prometheus, Python, Perfetto, dynamic-loader APIs, plugin-loader headers, or
topoexec/adapters/*. ResultSink,RuntimeObserver,MetricSink,TraceSink, andInMemoryRuntimeObserverremain the stable-v0.2 in-process observer surface;topoexec/adapters/sdk.hppre-exports them undertopoexec::adaptersfor adapter authors.topoexec::adapter_sdkis a header-only interface target that depends ontopoexec::runtime;topoexec::runtimedoes not depend on it.topoexec_adapters::otelis a default-off preview target that depends ontopoexec::adapter_sdkand maps observer/result records without linking an external telemetry SDK.topoexec_adapters::prometheusis a default-off preview target that depends ontopoexec::adapter_sdkand renders metric records as text exposition without starting an HTTP server or linking an external Prometheus library.topoexec_adapters::ros2is default-off and only validates adapter-side endpoint/QoS mapping plus fake boundary bridges; it does not create ROS nodes or link ROS packages.topoexec::plugin_loaderis default-off and only loads trusted native plugins from explicit paths after manifest, plugin API version, schema version, and descriptor checks; it does not add schema fields, sandboxing, package discovery, or stable ABI promises.BoundaryBridgeis bounded/best-effort and must not directly affect runtime scheduling. Bridge failures are adapter health/diagnostic evidence unless represented as ordinary graph boundary input/output.ComponentFactoryProviderregisters explicit in-process factories intoComponentRegistry. Dynamic loading is a preview alternative for trusted native components only; production package discovery, sandboxing, stable ABI, telemetry exporters, and network transports remain future work.
Pure runtime embedding smoke¶
The pure C++ path links only topoexec::runtime:
find_package(topoexec CONFIG REQUIRED)
target_link_libraries(my_app PRIVATE topoexec::runtime)
Use GraphBuilder or direct GraphSpec construction, register components in a ComponentRegistry, then call RuntimeRunner::run(). The package smoke under tests/cmake/runtime_smoke compiles this path against only topoexec::runtime after install and now verifies:
- minimal app graph construction;
- component registry registration/creation;
- GraphBuilder helpers;
- typed payload publication and consumption;
- RuntimeRunner execution;
RuntimeRunnerResultmetrics and trace consumption.
Example header boundary¶
Ordinary embedding examples should include only stable headers:
examples/apps/minimal_pipelineexamples/apps/control_feedback_delayexamples/apps/composite_loop_fixed_pointexamples/apps/async_workerexamples/apps/cpp_builder_minimal
examples/apps/overload_latest_vs_queue is intentionally marked as an advanced low-level channel-policy tutorial because it uses topoexec/runtime/channel.hpp directly.
examples/apps/robot_cell_pilot is an advanced pilot case study: it still links
only topoexec::runtime, but it intentionally composes stable, mixed, and
experimental runtime surfaces such as BufferPool and config/state snapshots.
Component failure model¶
Existing components can keep overriding the original void hooks:
void configure(topoexec::GraphContext&, const topoexec::ConfigView&) override;
void execute(const topoexec::Invocation&, topoexec::GraphContext&) override;
For non-exception error reporting, override the status hooks:
topoexec::Status execute_status(const topoexec::Invocation& invocation,
topoexec::GraphContext& ctx) override {
if (bad_input) {
return topoexec::Status::error("bad input");
}
return topoexec::Status::success();
}
RuntimeRunnerResult::runtime_errors records runtime failure entries with phase, component id, lane when known, message, code, trace id when known, and fatality. The runner deactivates already-started components after stop-token shutdown and component errors.
Graph diagnostics¶
GraphValidationResult and GraphCompileResult preserve legacy errors strings and also expose diagnostics[] with code, severity, category, message, optional graph path/involved ids, and suggested_fix. New tooling should prefer diagnostics while keeping errors for human-readable compatibility. Stable code descriptors and diagnostic schema version 1 live in topoexec/runtime/diagnostics.hpp and are documented in diagnostics.md.
API change checklist¶
Use api-change-checklist.md before modifying installed headers, CLI JSON, schema fields, or adapter-preview boundaries; schema-field proposals must also classify v1 vs v2 impact in schema-v2-notes.md.