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 input
  • Optional(name, type, default): optional input with default value
  • Const(name, type, value): constant — a fixed value baked into the step definition
  • Meta(name, metaKey): metadata — injects a named metadata field (e.g. flow_id, webhook_url) at execution time
  • Output(name, type): output attribute
  • WithForEach(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 URL
  • WithCompensateHandler(handler): register a compensation handler (auto-generates the URL when used with Start)

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 only
  • Update(): mark for update on next Start
  • Start(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())