Skip to content

Examples

Worked cases you can run against examples/basic_counter/. Each assumes a build with the management API:

Terminal window
cmake -S . -B build -DSIG_NET=ON -DSIG_HTTP_SERVER=ON -DSIG_MGMT=ON
cmake --build build

The example project has these capsule configurations and services:

Configuration Capsule Properties
Sim simulator 0..9 step 1 every 250 ms
SimToo simulator 0..9 step 1 every 550 ms
Count counter reports every 1000 ms
Logger logger level warn
Service Shape
test Sim and SimToo both feed Count, which feeds Logger
Foo, Dave small scratch services created from the web UI; they reuse the configurations above

A second project, examples/weather/, logs the current temperature in London through the weather capsule. It needs a host built with -DSIG_HTTP_CLIENT=ON -DSIG_CAPSULES="counter;simulator;logger;weather" (and libcurl) and network access:

Terminal window
build/host/posix/sighost -p examples/weather
Terminal window
build/host/posix/sighost -p examples/basic_counter -m 8080

test has "auto_start": true, so it is already running; Foo and Dave have no auto_start and stay stopped until you POST /services/{name}/start.

The service looks like this (arrows are receivers; every link uses the default terminal __default_terminal_value):

flowchart LR
    Sim[Sim<br/>simulator] --> Count
    SimToo[SimToo<br/>simulator] --> Count[Count<br/>counter]
    Count --> Logger[Logger<br/>logger]

Both simulators emit integers; Count tallies signals from either, and once per interval logs counter Count: processed N signals in the past 1000ms and emits N to Logger. Logger is set to warn, so under the default -l trace you see its lines, and under -l error you do not. Fan-in (two sources to one input) needs nothing special: both routes enqueue onto the same destination.

Stop and restart it, or read what it is made of:

Terminal window
curl -s localhost:8080/services/test # instances, terminals, links
curl -s localhost:8080/services/test/instances/Sim # configured properties
curl -s -X POST localhost:8080/services/test/restart

A receiver list may name several destinations. Signals are delivered to each, and one failing destination does not stop the others.

{
"execution": [
{ "name": "Sim", "receivers": { "__default_terminal_value": [
{ "name": "Count", "input": "__default_terminal_value" },
{ "name": "Logger", "input": "__default_terminal_value" } ] } },
{ "name": "Count" },
{ "name": "Logger" }
]
}

Logger here prints every integer Sim emits (raw), while Count summarises them. Create it without touching the disk by hand:

Terminal window
curl -s -X PUT -H 'Content-Type: application/json' -d @fanout.json localhost:8080/services/fanout
curl -s -X POST localhost:8080/services/fanout/start

Sim is in test and could be in fanout as well: a configuration is project-wide and each service that lists it gets its own instance, with its own storage and its own position in the simulator’s sequence. Editing Sim’s end marks every service that uses it as "dirty": true:

Terminal window
curl -s -X PATCH -H 'Content-Type: application/json' \
-d '{"attr_value":{"end":99}}' localhost:8080/configurations/Sim
curl -s localhost:8080/services # test (and fanout, if it uses Sim): "dirty": true
curl -s -X POST localhost:8080/services/test/restart

A running service is not disturbed by an edit; the change applies on its next start. DELETE /configurations/Sim is refused (409 configuration_in_use) while any service still lists it.

Property tables are enforced on write, so a bad configuration never reaches disk:

Terminal window
curl -s -X PUT -H 'Content-Type: application/json' -d '{"type":"simulator"}' \
localhost:8080/configurations/Bad
# {"error":"invalid_config","message":"end: required"}
curl -s -X PUT -H 'Content-Type: application/json' \
-d '{"type":"simulator","attr_value":{"end":9,"interval_ms":0}}' \
localhost:8080/configurations/Bad
# {"error":"invalid_config","message":"interval_ms: must be >= 1"}

A hand-edited .cfg that violates its capsule’s table loads fine but the service refuses to start (422 invalid_config from POST .../start, with the property named in the host log).

Terminal window
build/host/posix/sighost -p examples/basic_counter -m 8080 -o http://localhost:5173
cd ui && pnpm install && pnpm dev

Open http://localhost:5173, connect to 127.0.0.1:8080, then:

  1. Pick test in the service list; the graph appears.
  2. Click Count to inspect its properties.
  3. Drag Logger from the palette onto the canvas. That creates a configuration (named like Logger2) and an instance of it in this service.
  4. Drag from Count’s output terminal to Logger2’s input to link them.
  5. Select Logger2 and set level to info in the form.
  6. Save. The toolbar then shows Needs restart; press Restart and the new link is live.

If another client edited the same service meanwhile, Save asks whether to overwrite or reload instead of silently clobbering it. See ui/README.md for the details of the draft model.

writing-capsules.md walks through declaring terminals and a property table. Once your capsule is registered, it appears in GET /capsules and in the UI palette with a form generated from its properties; no UI code is needed.

See the README for creating a runtime and registering the management modules in your own main(). A host with no management modules is just the project runner: services start from auto_start and run until you request shutdown.