# Workflow Vibe-Coding Guide

Build, upload, and run BPMN workflows with **Cursor**, **VS Code + Copilot**, or **Antigravity** agents — no platform source required.

## Prerequisites

Same env as entity vibe-coding:

```bash
export GIA_ENDPOINT=https://gia.hub8.ai/api   # cloud; NOT https://gia.hub8.ai
# export GIA_ENDPOINT=http://127.0.0.1:4000   # local
export GIA_API_KEY=pk_...                      # Settings → API Support
```

## Flow

```
1. Connect      → GET /v1/seeds/health
2. Discover     → GET /v1/tools/configs?view=minimal     (list tool configs)
                   GET /v1/workflows/configs?page=1       (list existing workflows)
                   GET /v1/entities/metadata              (entity names for Spaces calls)
3. Build        → Generate valid BPMN 2.0 XML (see rules below)
4. Upload       → POST /v1/workflows/configs              (create workflow config + upload .bpmn)
5. Start        → POST /v1/workflows/{id}/start           (run an instance)
6. Monitor      → GET /v1/workflows/{id}/instances        (check status)
                   GET /v1/workflows/{id}/instances/{iid}  (instance detail)
```

## Step 1: Connect

```bash
curl -sS -H "Authorization: Bearer $GIA_API_KEY" \
  "$GIA_ENDPOINT/v1/seeds/health"
```

## Step 2: Discover

### Available Tool Configs

```bash
curl -sS -H "Authorization: Bearer $GIA_API_KEY" \
  "$GIA_ENDPOINT/v1/tools/configs?view=minimal"
```

Returns a compact list of tool config names. Your BPMN Service Tasks can only call these names in `<moduleName>`.

### Existing Workflows

```bash
curl -sS -H "Authorization: Bearer $GIA_API_KEY" \
  "$GIA_ENDPOINT/v1/workflows/configs?page=1&page_size=50"
```

### Entity Names (for Spaces calls)

```bash
curl -sS -H "Authorization: Bearer $GIA_API_KEY" \
  "$GIA_ENDPOINT/v1/entities/metadata"
```

Use the `displayName` values as `entity_name` in Spaces toolkit methods.

## Step 3: Build the BPMN

Generate a `.bpmn` file following these hard rules:

### Hard Rules

- **Pure BPMN 2.0** — no Camunda/Activiti/Flowable extensions
- **IDs:** `[a-zA-Z0-9_]` only. Multi-word: `enter_data`, not `enter-data`
- **File matching:** `id="validate"` → `scripts/validate.py` (case-sensitive)
- **XML escaping (critical):** `<` → `&lt;`, `>` → `&gt;`, `&` → `&amp;`, `"` → `&quot;`, `'` → `&apos;`
- **Conditions:** Python operators only (`and`, `or`, `not`). No `&&`, `||`, `!`
- **Variables:** Direct access in scripts: `result = email`. No `workflow.email`, no `context['email']`
- **User Tasks:** `<entityData>` required on every `<userTask>`
- **No overlapping nodes:** min 150px X, 120px Y spacing

### Service Task = Tool Config

A Service Task calls a **Tool Configuration** by name. It does not HTTP to `/v1/`. The worker handles auth.

```xml
<serviceTask id="update_status" name="Update Status">
  <extensionElements xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL">
    <serviceConfiguration xmlns="http://example.org/service">
      <function>
        <moduleName>Spaces</moduleName>
        <functionName>update_entity_record</functionName>
        <parameters>
          <parameter name="entity_name" value="Leave Requests"/>
          <parameter name="record_id" value="${recordId}"/>
          <parameter name="data_json" value="{&quot;Status&quot;:&quot;Approved&quot;}"/>
        </parameters>
      </function>
    </serviceConfiguration>
    <resultVariable name="update_result"/>
  </extensionElements>
</serviceTask>
```

### Pick the right toolkit

| Need | Toolkit (`moduleName`) | Method |
|---|---|---|
| List/get/create/update entity records | `Spaces` | `query_entity_data`, `create_entity_record`, `update_entity_record` |
| Create/publish entity schemas | `Entities` | `save_entity`, `publish_entity` |
| Run an AI agent | `AI Agent` | `execute_agent`, `execute_agent_advanced` |
| Send email | `SMTP` (or your config name) | `send_email` |
| Generate PDF | `PDF Toolkit` | `create_pdf`, `html_to_pdf` |
| Query external SQL DB | `SQL` (or your config name) | `execute_sql`, `execute_safe_query` |
| Direct MongoDB ops | `Mongo` (or your config name) | `find`, `aggregate`, `insert_one` |
| Math, flags, gateway inputs | **Script Task** (not Service Task) | Python script |

Full method reference: [Toolkit Catalog](https://gia.hub8.ai/docs/workflows/toolkit-catalog)

### Script Tasks

Script Tasks run Python. They are for math, flags, and gateway inputs only. They must **not** HTTP to `/v1/` endpoints.

```xml
<scriptTask id="calculate" name="Calculate Total" scriptFormat="python">
  <script>scripts/calculate.py</script>
</scriptTask>
```

`scripts/calculate.py`:
```python
"""Calculate total | Inputs: quantity, unit_price | Outputs: total, auto_approve"""
total = float(quantity) * float(unit_price)
auto_approve = total < 5000
```

### User Tasks

User Tasks collect data from humans. `<entityData>` is required.

```xml
<userTask id="enter_data" name="Enter Data">
  <extensionElements>
    <entityData xmlns="http://example.org/entity">
      <entityField id="email" label="Email" type="String" required="true"/>
      <entityField id="amount" label="Amount" type="Number" required="true"/>
    </entityData>
  </extensionElements>
</userTask>
```

Field types: `String`, `Number`, `Boolean`, `DateTime`, `Files`, `Audio`, `Media`.

## Step 4: Upload

Create the workflow config with a BPMN file upload:

```bash
curl -sS -X POST \
  -H "Authorization: Bearer $GIA_API_KEY" \
  -F "name=Leave Approval" \
  -F "category=HR" \
  -F "description=Automated leave approval workflow" \
  -F "bpmn_file=@workflow.bpmn" \
  "$GIA_ENDPOINT/v1/workflows/configs"
```

If you have Python scripts or React components, upload them as `workflow_files`:

```bash
curl -sS -X POST \
  -H "Authorization: Bearer $GIA_API_KEY" \
  -F "name=Leave Approval" \
  -F "category=HR" \
  -F "bpmn_file=@workflow.bpmn" \
  -F "workflow_files=@scripts/calculate.py" \
  -F "workflow_files=@scripts/validate.py" \
  "$GIA_ENDPOINT/v1/workflows/configs"
```

Save the returned `id` — you need it to start instances.

## Step 5: Start

```bash
curl -sS -X POST \
  -H "Authorization: Bearer $GIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"initial_data": {"entityName": "Leave Requests", "recordId": "abc123"}}' \
  "$GIA_ENDPOINT/v1/workflows/{workflow_id}/start"
```

Or start by name:

```bash
curl -sS -X POST \
  -H "Authorization: Bearer $GIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"entityName": "Leave Requests", "recordId": "abc123"}' \
  "$GIA_ENDPOINT/v1/workflows/by-name/Leave%20Approval/start"
```

## Step 6: Monitor

### List instances

```bash
curl -sS -H "Authorization: Bearer $GIA_API_KEY" \
  "$GIA_ENDPOINT/v1/workflows/{workflow_id}/instances?status=all"
```

### Get instance detail

```bash
curl -sS -H "Authorization: Bearer $GIA_API_KEY" \
  "$GIA_ENDPOINT/v1/workflows/{workflow_id}/instances/{instance_id}"
```

### Submit a user task

```bash
curl -sS -X POST \
  -H "Authorization: Bearer $GIA_API_KEY" \
  -F "task_id=enter_data" \
  -F 'data={"email":"user@example.com","amount":500}' \
  "$GIA_ENDPOINT/v1/workflows/{workflow_id}/instances/{instance_id}/submit-task"
```

## Agent Hard Rules

1. `moduleName` in BPMN **must** match an existing Tool Config name (check via `GET /v1/tools/configs?view=minimal`)
2. Use `${variable}` for parameter binding — not string interpolation or f-strings
3. XML-escape everything in BPMN XML — this is the #1 cause of parse failures
4. Scripts do not HTTP to `/v1/` — they access workflow variables directly
5. The worker remints the owner JWT — do not put `api_token` or `pk_` keys in BPMN or scripts
6. Entity names in Spaces calls are **display names** (`Leave Requests`, not `leave_requests`)
7. Discover tool configs and entity names before building BPMN — do not guess
