Go SDK
Register Steps, serve sync or async handlers, and start Flows from Go. The fluent builder mirrors the engine API, with helpers for predicates, match scripts, for_each expansion, and memoization.
Installation
go get github.com/kode4food/argyll/sdks/go-builder
Client
import "github.com/kode4food/argyll/sdks/go-builder"
client := builder.NewClient("http://localhost:8080", 30*time.Second)
Register a Script Step
import (
"context"
"github.com/kode4food/argyll/engine/pkg/api"
"github.com/kode4food/argyll/sdks/go-builder"
)
err := client.NewStep().
WithID("price-calculator").
WithName("Price Calculator").
Required("quantity", api.TypeNumber).
Required("unit_price", api.TypeNumber).
Output("total", api.TypeNumber).
WithScript(`{:total (* quantity unit_price)}`).
Register(context.Background())
WithScript defaults to Ale. Use WithScriptLanguage("lua", ...) for Lua or WithScriptLanguage("jpath", ...) for JPath.
Register an HTTP Step
err := client.NewStep().
WithID("lookup-customer").
WithName("Lookup Customer").
WithSyncExecution().
WithEndpoint("https://api.example.com/customers/{customer_id}").
WithMethod("GET").
WithTimeout(5000).
Required("customer_id", api.TypeString).
Output("customer", api.TypeObject).
Register(context.Background())
Serve a Sync Step
Start registers the step and starts an HTTP server that handles invocations:
handler := func(ctx *builder.StepContext, args api.Args) (api.Args, error) {
name := args["name"].(string)
return api.Args{"greeting": "Hello, " + name}, nil
}
err := client.NewStep().
WithID("greet").
WithName("Greet").
Required("name", api.TypeString).
Output("greeting", api.TypeString).
Start(handler)
Serve an Async Step
handler := func(ctx *builder.StepContext, args api.Args) (api.Args, error) {
asyncCtx, err := builder.NewAsyncContext(ctx)
if err != nil {
return nil, err
}
go func() {
result := doLongRunningWork(args)
asyncCtx.Success(api.Args{"result": result})
}()
return api.Args{}, nil // return immediately
}
err := client.NewStep().
WithID("process").
WithName("Process").
WithAsyncExecution().
Required("input", api.TypeObject).
Output("result", api.TypeObject).
Start(handler)
Serve a Step with Compensation
Use WithCompensateHandler to register a handler that undoes a completed work item. Start auto-generates the compensate URL:
handler := func(ctx *builder.StepContext, args api.Args) (api.Args, error) {
chargeID := args["charge_id"].(string)
return api.Args{"charge_id": chargeID}, nil
}
compensateHandler := func(
ctx *builder.StepContext, inputs api.Args, outputs api.Args,
) error {
chargeID := outputs["charge_id"].(string)
return refundCharge(ctx, chargeID)
}
err := client.NewStep().
WithID("charge-card").
WithName("Charge Card").
Required("amount", api.TypeNumber).
Output("charge_id", api.TypeString).
WithCompensateHandler(compensateHandler).
Start(handler)
The compensate handler receives the original inputs and outputs for the work item being undone. Return nil for success, api.ErrWorkNotCompleted for a transient failure (triggers retry), or any other error for a permanent failure.
Builder Methods
Identity
WithID(id),WithName(name),WithLabel(k, v),WithLabels(labels)
Attributes
Required(name, type): required inputOptional(name, type, default): optional input with default valueConst(name, type, value): constant — a fixed value baked into the step definitionMeta(name, metaKey): metadata — injects a named metadata field (e.g.flow_id,webhook_url) at execution timeOutput(name, type): output attributeWithForEach(name): mark an array input for parallel expansion
Execution Type
WithSyncExecution(),WithAsyncExecution(),WithScriptExecution()
HTTP
WithEndpoint(url),WithMethod(method),WithTimeout(ms),WithHealthCheck(url)WithCompensate(url): set the compensate endpoint URLWithCompensateHandler(handler): register a compensation handler (auto-generates the URL when used withStart)
Script
WithScript(ale),WithScriptLanguage(lang, script)— lang:"ale","lua","jpath"
Predicate / Match
WithPredicate(lang, script),WithAlePredicate(script),WithLuaPredicate(script)WithRequiredMatch(name, lang, script): match predicate on a required input
Behavior
WithMemoizable(),WithFlowGoals(goals...)(for flow-type steps)
Lifecycle
Register(ctx): register the step definition onlyUpdate(): mark for update on nextStartStart(handler): register and serve
List Steps
steps, err := client.ListSteps(context.Background())
Start a Flow
Use WithGoals(goals...) to set all goals at once, or WithGoal(goal) to add one at a time. Both WithLabel and WithLabels are also available on flows.
err := client.NewFlow("order-123").
WithGoals("send-confirmation").
WithInitialState(api.InitArgs{
"customer_id": []any{"cust-456"},
"order_amount": []any{99.99},
}).
Start(context.Background())
Initial values are arrays. Wrap each value in a slice.
Query Flow State
flow := client.Flow("order-123")
state, err := flow.GetState(context.Background())
status, err := flow.GetStatus(context.Background())