Using the SDK(s)


If you've gone through our technical overview, you can see how steps are built in any language. Even though the process is fairly straightforward, we felt it was important to provided a thin SDK to improve the speed and debugging ability of building new packages. Right now we have SDKs for:

  • Go

  • C#

Luckily, because our SDK layer is so thin, it's easy for us (or you) to build a new one for the language of your choice.

Advantages of using the SDK

There are a few important advantages to utilizing our SDKs.

  • You don't need to worry about how to parse inputs or return outputs

  • You can run your package in hosted mode. In this mode, your package will be run in a mini server allowing the engine to call it as part of a workflow. This let's you set breakpoints and debug your step while running in a real workflow.

  • You can interact with the AppTree Cache directly from your step. Allowing you to query and insert data from your step into our caching layer.

A simple SDK example

Here you can see a quick example of using the SDK in Go and C#. We attempt to keep the SDK as idiomatic as possible to the language you are using.

// (1)
type StringLengthInput struct {
Text string
type StringLengthOutput struct {
Count int
// (2)
type StringLengthCounter struct {
// Implements the Step interface
func (StringLengthCounter) Name() string {
return "string_length"
// Implements the Step interface
func (StringLengthCounter) Version() string {
return "1.0"
// Implements the Step interface
func (StringLengthCounter) Execute(ctx step.Context) (interface{}, error) {
input := StringLengthInput{}
err := ctx.BindInputs(&input) // 3
if err != nil {
return nil, err
// 4
output := StringLengthOutput{}
output.Count = len(input.Text)
return output, nil
func main() {
step.Register(StringLengthCounter{}) // 5
step.Run() // 6
  1. We first declare our input and output structs. Remember, the engine will send all input as JSON so you simply need to create a struct that contains the input fields you want to read in. In this case, we have one input which is Text.

  2. Next we declare our Step StringLengthCounter struct and have it implement the Step interface which has 3 methods:

    1. Name() string

    2. Version() string

    3. Execute(ctx step.Context) (interface{}, error)

  3. In the execute method, we we are passed in a step.Context which contains information about the environment it's running in. It also has some convenience methods like Bind that will read the inputs into the struct provided.

  4. Next we count the string and assign it to our StringLengthOutput struct. When this struct is returned from the Execute method it will be serialized as JSON and sent back to the engine for us by the SDK

  5. Using the SDK, we register the step.

  6. Lastly, the step.Run() method executes your step packages taking care of things for you like determining which step to run, parsing inputs, etc.


An example string_length step in C# using the C# SDK. The C# SDK makes use of Attributes to simplify the development and registration of the step.

[StepDescription("string_length")] // (1)
public class StringLength : Step{ // (2)
// (3)
[Input(Description = "The string you want to count the length of")]
public string Text { get; set; }
// (4)
[Output(Description = "The length of the string")]
public int Length { get; set; }
// (5)
public override void Execute() {
var length = this.text.length;
this.Length = length;
using System;
using System.Threading.Tasks;
using StepCore;
namespace Accruent.Famis.Steps {
// (6)
class Program {
static async Task Main(string[] args) {
await PackageManager.Run(args); //(7)

1. First, we register our step by using the StepDescription attribute. This makes the SDK aware of the new step we are creating.

2. Next we extend the Step class. There are two possible classes you can extend from, Step or StepAsync. The difference is in the execute method. If you use StepAsync you will be returning a Task rather than void

3. Use the Input attribute to define our Text input.

4. Use the Output attribute to define our Count output.

5. Implement the Execute method. This is an abstract method on the superclass Step that is required. This is where you perform the work of your step.

6. Jumping over to the Program.cs file, we define our Package using the PackageDefinition attribute on the Program class.

7. Lastly, we call PackageManager.Run(args) to begin running our step. The PackageManager takes care of reading in environment variables, binding your inputs using the Input attributes and setting our outputs based on the Output attribute.