SDK Pipeline Guide
Choose the driver from the shape of the work, not from the plugin name.
| Work shape | Current primitive | Advance method |
|---|---|---|
| Fixed, ordered sub-steps | TaskPipeline | tick() |
| Branching, looping, or recovery states | TypesafeCarouselStateMachine<E> | pulse(clientTick) |
| Standard bank, combat, production, enchanting, pouch, or spellbook flow | The matching workflow builder and plan | Carousel pulse(clientTick) |
| A single observed action | The relevant Api.actions method | Re-observe on the next tick |
Pipeline Selection Decision Flow
Fixed sequences
Build a TaskPipeline with named TaskStep callbacks. A step advances only
when it returns StepResult.success(). Retry and waiting results retain the
current index. Use StepResult.waitForEvent(...) when an issued action must wait
for a RuneLite event rather than polling the same interaction each tick.
boolean[] depositRequested = {false};
TaskPipeline pipeline = TaskPipeline.create()
.step("open", () -> StepResult.fromInteraction(BankActions.openNearestAccessible()))
.step("deposit", () -> {
if (Inventory.getEmptySlots() == 28) {
return StepResult.success("Inventory deposited");
}
if (depositRequested[0]) {
return StepResult.waitTicks(1, "Waiting for inventory to empty");
}
InteractionResult dispatch = BankActions.depositAll();
if (dispatch.accepted()) {
depositRequested[0] = true;
return StepResult.waitTicks(1, "Waiting for inventory to empty");
}
return StepResult.fromInteraction(dispatch);
});
StepResult result = pipeline.tick();
The actual overloads and status handling are defined by TaskPipeline,
StepResult, and StepStatus; check those sources before selecting an adapter.
The deposit step records its dispatch separately, then advances only after the
inventory-empty postcondition is observed, so it does not click the control on
every retry tick.
Branching workflows
Use an enum and define every handler. The Carousel builder requires a stable ID,
an owner, an initial state, and exhaustive state coverage. Each handler returns
stay, transitionTo, complete, or fail, all with a stable reason code.
Duplicate-tick pulses do not execute a handler twice.
See Typesafe Carousel State Machine and
Observable Workflow Runtime for construction, terminal
telemetry, cancellation, reset, and AutomationLoop.fromStateMachine(...).
Domain builders
BankWorkflowBuilder, CombatWorkflowBuilder, ProductionWorkflowBuilder,
EnchantingWorkflowBuilder, PouchWorkflowBuilder, and
SpellbookWorkflowBuilder accept their corresponding immutable plan and return
a typed Carousel. Do not copy examples for retired workflow APIs. Use the builder's current create(plan) method
and the plan builder methods present in live source. Current examples are in
Workflow Builders & Plans.
For jewellery enchanting, build an EnchantingPlan with a typed Spell, the
unenchanted input item, the exact enchanted output, per-cast rune quantities,
and any ordered owned-staff candidates. EnchantingWorkflowBuilder validates
the Standard spellbook and boosted Magic level, prepares bank supplies, equips
the chosen staff, and closes the bank before casting. It counts inventory and
rune-pouch quantities and treats an equipped elemental staff as infinite
coverage only for the runes declared by its StaffOption.
The builder snapshots the input and output quantities before each jewellery cast. It reports progress only after the input decreases and the configured output increases. Callers must preserve that confirmation boundary; an accepted interaction does not confirm an enchantment.
Runtime rules
- Observe live state before choosing a transition.
- Perform at most one meaningful action per tick.
- Inspect
InteractionResult; paced or dispatched work is not confirmation. - Re-fetch entities and widgets after state-changing actions.
- Reset transient workflow state on logout, disable, or other invalidation.
- Keep suite-wide pacing and walker ticking in Packet Utils.