Recipes
These recipes show example prompts and the expected agent workflow. They work with any AI coding tool.
Create a Logic Block from a Description
Prompt:
Create a logic block called
RoomControllerthat has a temperature measuring point (double, °C), a setpoint property (double, °C, configurable, default 21), and a heating output (boolean). Every 5 seconds, compare temperature to setpoint and enable heating if temperature is below setpoint minus 0.5°C hysteresis.
Expected agent workflow:
dale add logicblock RoomController- Add properties, measuring points, and a service provider contract for the output
- Implement the control logic with
[Timer(5)] dale buildto verify compilation- Write tests for the hysteresis logic
dale testto verify
Add a Modbus Device Integration
Prompt:
Add a logic block that reads 3 voltage registers (float, starting at address 0) and 1 power register (float, at address 52) from a Modbus RTU device every 2 seconds. Expose voltage L1/L2/L3 and total power as service properties with units.
Expected agent workflow:
- Create the logic block with
[ServiceProviderContractBinding]forIModbusRtu - Add service properties with
[ServiceMeasuringPoint]and unit annotations - Implement
[Timer(2)]method with batch read for voltages and individual read for power - Add error handling with error count property
dale buildanddale test
Write Tests for an Existing Block
Prompt:
Write comprehensive tests for the RoomController logic block. Test that heating turns on below setpoint, turns off above setpoint, and respects the hysteresis band.
Expected agent workflow:
dale list --output jsonto understand the block's structure- Create an xUnit test class using the TestKit
- Use
InitializeForTest()andCreateTestContext() - Test boundary conditions around the hysteresis
dale testto run the tests
Build, Test, and Publish
Prompt:
Build the project, run tests and scenarios, fix any failures, then upload to VION Cloud with release notes "Added room controller with hysteresis logic".
Expected agent workflow:
dale build— fix any compilation errorsdale test— fix any xUnit test failuresdale scenario validate— resolve every scenario's name paths and topology offline- Boot
dale dev --headless --stepped, thendale scenario run <id>for each scenario as the gate before upload dale upload --release-notes "Added room controller with hysteresis logic"- Report success or failure
Refactor Properties for Dashboard Display
Prompt:
Update the BatterySimulation logic block: mark StateOfCharge as primary on the dashboard tile, group the charging and discharging properties under Status, and add a status indicator enum for battery state (Charging, Discharging, Idle, Fault).
Expected agent workflow:
dale list --output jsonto see current structure- Add
[Presentation(Group = PropertyGroup.Status, Importance = Importance.Primary)]toStateOfCharge - Add
[Presentation(Group = PropertyGroup.Status, Importance = Importance.Secondary)]to the charging / discharging power properties - Create a
BatteryStateenum with[EnumLabel("...")]and[Severity(StatusSeverity.X)]on each member - Add a status enum property with
[Presentation(Group = PropertyGroup.Alarm, StatusIndicator = true)] dale buildto verify (the Dale analyzers catch most authoring mistakes)
Run a Scenario as the Feedback Loop
Prompt:
Verify the RoomController behaves correctly: with a setpoint of 21 and the temperature driven to 20, heating should be on. Run it headless and report the result.
Expected agent workflow:
- Boot the DevHost headless and deterministic with
dale dev --headless --stepped, then parse the JSON readiness line to learn the port dale scenario run room-controllerto drive the committed scenario against the wired network- Read the structured report — the same one the Player's copy button produces
- If a step failed, fix the logic block and re-run; iterate until the report is green
The DevHost runs the real wired messaging path, so this catches wiring bugs that a stubbed-collaborator unit test would miss. For the scenario file grammar, see Scenarios.
Use the Deterministic Clock for Reproducible Runs
Prompt:
The RoomController scenario passes sometimes and fails other times depending on timing. Make the run reproducible.
Expected agent workflow:
- Boot with
dale dev --steppedso the host uses a virtual clock instead of the wall clock - Ensure the scenario advances time explicitly with
advancesteps rather than relying on wall-clock delays — under the stepped clock, timers fire when the scenario advances the clock and emission happens immediately dale scenario run room-controller— the run now produces the same report every time- Pin any remaining non-deterministic input (live data, RNG) so the result is fully reproducible
Graduate a Scenario to an xUnit Test
Prompt:
The room-controller scenario needs assertions the file format can't express. Turn it into a typed xUnit test.
Expected agent workflow:
dale scenario scaffold room-controllerto generate a typed test that runs the scenario's setup and steps viaScenarioRunner.ApplyAsync, with TODO assertions for the human judgments- Or hand-write a
[Theory]over the committed scenario files using the wired DevHost fixture - Fill in the typed assertions and run
dale test
The scaffold is the fast path. To run every committed scenario as its own test row, hand-write a theory that loads the wired host on the scenario's topology with the deterministic clock and runs it:
using System.Threading.Tasks;
using Vion.Dale.DevHost.Xunit;
using Xunit;
namespace RoomController.Test
{
public sealed class ScenarioTests
{
private sealed class Fixture : DevHostScenarioFixture
{
protected override DevHostBuilder ConfigureDi(DevHostBuilder builder) =>
builder.WithDi<DependencyInjection>();
}
private readonly Fixture _fixture = new();
[Theory]
[ScenarioFiles]
public async Task EveryScenarioSucceeds(string id, string topology)
{
await using var host = await _fixture.LoadAsync(topology, stepped: true);
(await host.RunScenarioAsync(id)).AssertSucceeded();
}
}
}[ScenarioFiles] yields one test row per committed *.scenario.json file, named by the scenario title. LoadAsync(topology, stepped: true) builds a fresh wired host on the scenario's declared topology under the deterministic clock, and RunScenarioAsync(id).AssertSucceeded() runs the scenario and throws with the first failed step's detail if it does not succeed. Replace DependencyInjection with the block catalog type your project generates.