Go SDK
Use the Go builder to register endpoints, serve Step handlers, and start or inspect Flows.
Installation
go get github.com/kode4food/argyll/sdk/go
Client
The package name is argyll:
import (
"time"
"github.com/kode4food/argyll/sdk/go"
)
client := argyll.NewClient("http://localhost:8080", 30*time.Second)
The examples below use this client.
Register a Script Step
import (
"context"
"github.com/kode4food/argyll/engine/pkg/api"
argyll "github.com/kode4food/argyll/sdk/go"
)
err := client.NewStep().
WithID("price-calculator").
WithName("Price Calculator").
Required("quantity", api.TypeNumber).
Required("unit_price", api.TypeNumber).
Output("total", api.TypeNumber).
WithScript(api.ScriptConfig{
Language: api.ScriptLangLua,
Script: `return {total = quantity * unit_price}`,
}).
Register(context.Background())
Executable Script Steps use Lua. The jpath language identifier is available for JSONPath predicates and attribute mappings, not executable Script Steps.
Register an HTTP Step
err := client.NewStep().
WithID("lookup-customer").
WithName("Lookup Customer").
WithSyncInvoke().
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 *argyll.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 *argyll.StepContext, args api.Args) (api.Args, error) {
asyncCtx, err := argyll.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").
WithAsyncInvoke().
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 generates the compensation URL:
handler := func(ctx *argyll.StepContext, args api.Args) (api.Args, error) {
chargeID := chargeCard(args["amount"])
return api.Args{"charge_id": chargeID}, nil
}
compensateHandler := func(
ctx *argyll.StepContext, args api.Args,
) error {
chargeID := args["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).
WithCompensated("charge_id").
WithCompensateHandler(compensateHandler).
Start(handler)
The compensation handler receives a flat argument map containing the selected Attributes under their invocation names. Return nil for success, api.ErrWorkNotCompleted to request another attempt, or another error to report permanent failure.
Code Generation
The Go Step Generator derives a Step contract and handler from an ordinary Go function.
Builder Methods
Identity
WithID(id),WithName(name),WithDescription(text), andWithTags(tags...), which merges into the Step’s tag set, sorted and deduped
Attributes
Required(name, type): required inputOptional(name, type, default): optional input with default valueConst(name, type, value): a fixed value baked into the Step definitionMeta(name, metaKey): a named metadata field (e.g.flow_id,webhook_url) injected at execution timeOutput(name, type): output attributeWithCollect(collect, names...): set the collect policy (first,last,some,all,none) for inputsWithForEach(names...): mark inputs for parallel expansion over their collected values, requiringcollect: allorcollect: someWithCompensated(names...): include Attributes in compensation requests
Execution Type
WithScript(...)selects Script execution
Action Mode
WithInvokeMode(api.ActionMode),WithCompensateMode(api.ActionMode): set how an action reports its result,api.ActionModeSync(default) orapi.ActionModeAsyncWithSyncInvoke(),WithAsyncInvoke(): shorthand for the invoke action’s mode
HTTP
WithEndpoint(url),WithMethod(method),WithTimeout(ms),WithHealthCheck(url)WithCompensate(url): set the endpoint URL and compensated handlingWithCompensateMethod(method): compensate HTTP method, defaults toPOSTWithCompensateTimeout(ms): compensate timeout, defaults to the Step timeoutWithCompensateHandler(handler): register a compensation handler (auto-generates the URL when used withStart)
Script
WithScript(api.ScriptConfig{...})- executable Script Steps use Lua
Predicate / Match
WithPredicate(api.ScriptConfig{...})- predicates may use Lua or JSONPath ("jpath")WithMatch(name, api.ScriptConfig{...}): match predicate on a required or optional input
Behavior
WithHandling(api.Handling): choose standard, memoized, or compensated handlingWithFlowGoals(api.Goals{...}): configure a Flow-type Step with a chain of fallback Goal setsWithFlowSpace(spaceID): restrict its child flow to a Space
Lifecycle
Register(ctx): register or update the Step definition, retrying transient failuresStart(handler): register or update with retries, then serve
The builder applies the engine’s validation rules before registration and returns the same validation error locally.
Registering a Prepared Step
RegisterStep accepts an existing *api.Step. It validates the definition, retries transient failures, and updates an existing registration after a conflict.
err := client.RegisterStep(context.Background(), step)
List Steps
steps, err := client.ListSteps(context.Background())
Start a Flow
Use WithGoals(api.Goals{...}) to set the chain of fallback Goal sets at once, or WithGoal(goal) to add a Goal to the last set in the chain. Flows carry tags too, set with WithTags(tags...), where they drive flow queries rather than Space membership.
err := client.NewFlow("order-123").
WithGoals(api.Goals{
Steps: []api.StepID{"send-confirmation"},
Else: &api.Goals{Steps: []api.StepID{"queue-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. Each key declares the resolved values for that Attribute, so an empty slice declares zero values and an omitted key leaves the Attribute to providers. See Initial Values Are Authoritative.
Query Flow State
flow := client.Flow("order-123")
state, err := flow.GetState(context.Background())
status, err := flow.GetStatus(context.Background())