> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kapso.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Build locally

> Pull workflows into a local repo, edit them as JSON or code, and push them back to Kapso.

Use the Kapso CLI to keep workflows and functions in a local repository. You can edit the generated `definition.json` directly, or use `@kapso/workflows` to author the workflow in JavaScript or TypeScript.

The Platform API stores workflow definitions as JSON with `snake_case` config keys. The JavaScript library uses idiomatic `camelCase` inputs and compiles them to the same JSON shape before `kapso push`.

## Start a local repo

```bash theme={null}
# 1. Create a local workspace
mkdir kapso-workflows
cd kapso-workflows

# 2. Install the Kapso CLI and workflow library
npm init -y
npm install -g @kapso/cli
npm install --save-dev @kapso/workflows

# 3. Link this directory to your Kapso project
kapso login
kapso link --project <project-id>
kapso pull

# 4. Install Kapso agent skills
npx skills add gokapso/agent-skills
```

`kapso link` binds the current directory to one Kapso project. `kapso pull` downloads source files for workflows and functions.

## Repository layout

After pulling, the repo includes project binding metadata and one directory per source object.

```text theme={null}
kapso.yaml
.kapso/project.json
.kapso/remote-map.json

functions/
  send-slack-message/
    function.yaml
    index.js

workflows/
  support-router/
    workflow.yaml
    definition.json
    workflow.js
```

Commit the files you want to version. Keep `.kapso/remote-map.json` in shared repos because it stores the last pulled remote state for dirty-file and stale-update checks.

## Choose JSON or code

Both paths are supported:

* Edit `definition.json` when you want the exact Platform API graph payload.
* Edit `workflow.js` or `workflow.ts` when you want a boring code API for constructing the graph.
* Keep or ignore generated `definition.json` as a team decision. The CLI works either way.

`kapso pull` creates `workflow.js` next to `definition.json` when no workflow source file exists. After you edit that source file, future pulls preserve it and update only the remote-owned JSON/YAML files.

## Build with code

```javascript theme={null}
import { START, Workflow } from "@kapso/workflows";

const workflow = new Workflow("support-router", {
  name: "Support Router",
  status: "draft"
});

workflow.addTrigger({
  type: "inbound_message",
  phoneNumberId: "<phone-number-id>"
});

workflow.addNode(START, {
  position: { x: 100, y: 100 }
});

workflow.addNode("intro", {
  type: "send_text",
  message: "Hi {{vars.customer_name}}, how can we help?"
}, {
  position: { x: 360, y: 100 }
});

workflow.addNode("wait_reply", {
  type: "wait_for_response",
  saveResponseTo: "latest_reply",
  timeoutSeconds: 300
}, {
  position: { x: 620, y: 100 }
});

workflow.addNode("classify", {
  type: "decide",
  decisionType: "ai",
  providerModel: "gpt-5-mini",
  conditions: [
    { label: "billing", description: "Billing, invoices, or payments" },
    { label: "technical", description: "Product or technical support" }
  ]
}, {
  position: { x: 880, y: 100 }
});

workflow.addEdge(START, "intro");
workflow.addEdge("intro", "wait_reply");
workflow.addEdge("wait_reply", "classify");

export default workflow;
```

Build the workflow JSON before pushing:

```bash theme={null}
kapso build
```

If a pulled `workflow.js` file is unchanged, `kapso push` uses `workflow.yaml` and `definition.json`. Once you edit `workflow.js` or add `workflow.ts`, `kapso push` compiles that source before uploading.

## Push changes

Preview changes before writing to Kapso:

```bash theme={null}
kapso push --dry-run
```

Push one workflow:

```bash theme={null}
kapso push workflow support-router
```

Push one function:

```bash theme={null}
kapso push function send-slack-message
```

Push everything in the local repo:

```bash theme={null}
kapso push
```

Workflows and functions are matched by slug. If a remote object with the same slug exists but your repo does not have a pull baseline, run `kapso pull` first.

## Node reference

Each node has a stable `id`, a `type`, and optional display/position options. Edges reference node IDs.

```javascript theme={null}
workflow.addNode("node_id", { type: "send_text", message: "Hello" });
workflow.addEdge("node_id", "next_node");
```

The table below shows the library shape and the Platform API `node_type`.

| Node              | API `node_type`     | Library config                                                                                                                        |
| ----------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| Start             | `start`             | `workflow.addNode(START, { position })`                                                                                               |
| Send text         | `send_text`         | `{ type: "send_text", message, phoneNumberId?, toPhoneNumber?, delaySeconds?, providerModel?, aiFields? }`                            |
| Send template     | `send_template`     | `{ type: "send_template", templateId, parameters?, phoneNumberId?, toPhoneNumber?, providerModel?, aiFields? }`                       |
| Send interactive  | `send_interactive`  | `{ type: "send_interactive", interactiveType, bodyText?, buttons?, listSections?, ctaUrl?, flowId?, phoneNumberId?, toPhoneNumber? }` |
| Wait for response | `wait_for_response` | `{ type: "wait_for_response", saveResponseTo?, timeoutSeconds? }`                                                                     |
| Decide            | `decide`            | `{ type: "decide", decisionType: "ai" / "function", conditions, providerModel? }` or `{ functionSlug }` for function decisions        |
| Function          | `function`          | `{ type: "function", functionSlug, saveResponseTo? }`                                                                                 |
| Webhook           | `webhook`           | `{ type: "webhook", url, method?, headers?, bodyTemplate?, saveResponseTo?, providerModel?, aiFields? }`                              |
| Agent             | `agent`             | `{ type: "agent", systemPrompt, providerModel?, functionTools?, webhooks?, mcpServers?, resources? }`                                 |
| Call workflow     | `call`              | `{ type: "call", workflowSlug, saveErrorTo? }`                                                                                        |
| Handoff           | `handoff`           | `{ type: "handoff", reason?, contextData? }`                                                                                          |
| Set variable      | `set_variable`      | `{ type: "set_variable", variableName, variableValue, valueType? }`                                                                   |
| Raw               | any                 | `{ type: "raw", nodeType, config }` for fields not yet modeled by the library                                                         |

Use `rawConfig` on typed nodes when you need an extra Platform API field that the library has not modeled yet:

```javascript theme={null}
workflow.addNode("send", {
  type: "send_text",
  message: "Hello",
  rawConfig: {
    experimental_field: true
  }
});
```

## References by slug

Local source should use stable slugs where possible:

* Function nodes use `functionSlug`.
* Function decision nodes use `functionSlug`.
* Agent function tools use `functionSlug`.
* Call workflow nodes use `workflowSlug`.

During `kapso push`, the CLI resolves those slugs to remote IDs before calling the Platform API. Direct Platform API requests should use `function_id` and `workflow_id`.

## API definition shape

A workflow definition is a graph:

```json theme={null}
{
  "nodes": [
    {
      "id": "start",
      "type": "flow-node",
      "position": { "x": 100, "y": 100 },
      "data": {
        "node_type": "start",
        "config": {},
        "display_name": "Start"
      }
    }
  ],
  "edges": []
}
```

When using the Platform API directly:

* Use `snake_case` config keys.
* Use `GET /workflows/{workflow_id}/definition` to read the expanded graph.
* Use `PATCH /workflows/{workflow_id}` to update metadata and graph collections.
* Include the latest `lock_version` to avoid overwriting remote changes.
* The update response returns workflow metadata, not the expanded definition. Refetch the definition when you need the saved graph.

Example update:

```bash theme={null}
curl -X PATCH "https://api.kapso.ai/platform/v1/workflows/<workflow-id>" \
  -H "X-API-Key: <api-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "workflow": {
      "lock_version": 3,
      "definition": {
        "nodes": [
          {
            "id": "start",
            "type": "flow-node",
            "position": { "x": 100, "y": 100 },
            "data": { "node_type": "start", "config": {} }
          },
          {
            "id": "intro",
            "type": "flow-node",
            "position": { "x": 360, "y": 100 },
            "data": {
              "node_type": "send_text",
              "config": {
                "message": "Hi {{vars.customer_name}}",
                "phone_number_id": "<phone-number-id>"
              }
            }
          }
        ],
        "edges": [
          { "source": "start", "target": "intro", "label": "next" }
        ]
      }
    }
  }'
```

Inside `definition`, `nodes` and `edges` are replacement sets when present. If you send only one node in `definition.nodes`, every other node is removed. Omit `definition.nodes` or `definition.edges` when you want that collection to remain unchanged.

## Sync behavior

The CLI protects local and remote work during sync:

* `kapso pull` refuses to overwrite dirty local remote-owned files.
* `kapso pull --diff` shows blocked incoming diffs without writing files.
* `kapso pull --overwrite` replaces local edits in remote-owned files with the remote version.
* `kapso pull` preserves authored `workflow.js` and `workflow.ts` files.
* `kapso push` checks the last pulled remote version before updating existing objects.
* Remote-only workflows and functions are reported, not deleted.
* Local-only workflows and functions are created on push.

## Build with AI

The setup block above installs the Kapso agent skills. For AI-assisted edits, point your coding assistant at the workflow directory and ask it to edit `workflow.js` or `workflow.ts`.

Kapso docs are available to AI tools through the MCP endpoint:

```text theme={null}
https://docs.kapso.ai/mcp
```
