Quickstart

From zero to a governed operational workflow in 15 minutes.

Who This Is For

Operations lead — "My team spends hours investigating exceptions manually. I need AI that works within our approval process." → Skip to Your First Governed Workflow

Platform engineer — "We need to embed governed agent execution into our product." → Start at The Graduated Pipeline

Developer — "Just show me the API." → Skip to API Fast Path

What You'll Build

A working governed workflow that demonstrates the core pattern: deterministic rules handle clear cases, a bounded AI agent investigates exceptions, a human reviewer makes the final call on edge cases, and every decision is logged.

We'll use invoice-to-payment reconciliation as the example — but the same architecture applies to incident response, contract review, employee onboarding, claims processing, or any operational process where you need autonomous AI within boundaries.


The Graduated Pipeline

Every Hyphen deployment follows this architecture:

flowchart TD A["Operational Event"] --> B["Deterministic Rules"] B -->|"~80% auto-resolved"| F["✅ Done"] B -->|"Exceptions"| C["ReAct Agent — Bounded AI"] C -->|"~15% AI-resolved"| F C -->|"Low confidence"| D["PbotApproval — Human Review"] D -->|"~5% human-resolved"| F F --> E["Audit Trail"]

Rules handle the clear cases. AI handles the ambiguous middle. Humans handle the edge cases. Every layer feeds the next. Nothing falls through.

This pattern works because it matches how real operations teams already work — experienced staff handle the obvious cases, specialists investigate the tricky ones, managers approve the exceptions. Hyphen encodes that same graduated judgment into infrastructure.


Your First Governed Workflow

Step 1: Prepare Your Data

Two datasets — invoices and payments — with real-world messiness:

Invoices:

json
[
  { "invoice_id": "INV-001", "vendor": "Acme Corp", "amount": 10000.00, "date": "2026-01-15" },
  { "invoice_id": "INV-002", "vendor": "Globex Inc", "amount": 4500.00, "date": "2026-01-18" },
  { "invoice_id": "INV-003", "vendor": "Initech", "amount": 7250.00, "date": "2026-01-20" },
  { "invoice_id": "INV-004", "vendor": "Umbrella Ltd", "amount": 15000.00, "date": "2026-01-22" },
  { "invoice_id": "INV-005", "vendor": "Stark Industries", "amount": 3200.00, "date": "2026-01-25" }
]

Payments:

json
[
  { "invoice_id": "INV-001", "vendor": "Acme Corp", "amount": 10000.00, "date": "2026-01-16" },
  { "invoice_id": "INV-002", "vendor": "Globex Inc", "amount": 4480.00, "date": "2026-01-19" },
  { "invoice_id": "INV-004", "vendor": "Umbrela Ltd", "amount": 15000.00, "date": "2026-01-23" },
  { "invoice_id": "INV-006", "vendor": "Wayne Enterprises", "amount": 8800.00, "date": "2026-01-27" }
]

Notice: INV-002 has a $20 discrepancy, INV-004 has a vendor typo ("Umbrela"), INV-003 and INV-005 have no payments, and INV-006 is a payment without an invoice.

Step 2: Create the Workflow

POST/workflows

Create a workflow with matching, AI investigation, human approval, and audit logging.

bash
curl -X POST http://localhost:3009/workflows \
  -H "X-Org-Id: your-org" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "invoice_payment_reconciliation",
    "definition": {
      "actions": [
        {
          "type": "matcher",
          "properties": {
            "left": "@input.invoices",
            "right": "@input.payments",
            "matchOn": ["invoice_id"],
            "tolerance": 0.02,
            "dateWindowDays": 3,
            "fuzzyThreshold": 85,
            "descriptionKey": "vendor",
            "outputMatched": "matched",
            "outputUnmatchedLeft": "unmatched_invoices",
            "outputUnmatchedRight": "unmatched_payments"
          }
        },
        {
          "type": "loop",
          "filter": {
            "condition": {
              "greaterThan": [{ "length": "@unmatched_invoices" }, 0]
            }
          },
          "properties": {
            "mode": "react",
            "objective": "Investigate these unmatched invoices. For each, determine the most likely reason (timing delay, data entry error, duplicate, or missing payment). Recommend: wait, follow up with vendor, or escalate.",
            "tools": [
              { "type": "action", "name": "lookup_vendor_history" }
            ],
            "max_iterations": 10,
            "on_stuck": { "iterations": 3, "action": "escalate" },
            "result_key": "investigation"
          }
        },
        {
          "type": "PbotApproval",
          "filter": {
            "condition": {
              "greaterThan": [{ "length": "@unmatched_invoices" }, 0]
            }
          },
          "properties": {
            "comment": "AI investigated unmatched invoices. Review findings and approve recommended actions.",
            "request_payload": {
              "matched_count": "@matched.length",
              "unmatched_invoices": "@unmatched_invoices",
              "ai_investigation": "@investigation"
            }
          }
        },
        {
          "type": "custom-table",
          "properties": {
            "table": "reconciliation_log",
            "operation": "write",
            "keys": ["run_id", "timestamp"],
            "values": ["@__run_id", "@now"],
            "fields": {
              "matched_count": "@matched.length",
              "exception_count": "@unmatched_invoices.length",
              "status": "completed"
            }
          }
        }
      ]
    }
  }'

Note on tools: Built-in agent tools (__complete__, __pause_for_human__, __store_memory__, __retrieve_memory__, __log_progress__) are automatically injected into every ReAct agent — you don't need to declare them. Only declare your custom action tools and workflow tools.

**What this defines:**
Step Primitive What Happens
1 matcher Compares invoices to payments: exact invoice_id, 2% amount tolerance, ±3 day date window, 85% fuzzy vendor match
2 loop (react) AI agent investigates unmatched invoices — bounded to 10 iterations with stuck detection
3 PbotApproval Human reviewer sees results + AI reasoning — makes final call
4 custom-table Logs the run to an audit table

Step 3: Execute

POST/workflows/:id/execute

Run the workflow with your invoice and payment data.

bash
curl -X POST http://localhost:3009/workflows/{workflow_id}/execute \
  -H "X-Org-Id: your-org" \
  -H "Content-Type: application/json" \
  -d '{
    "invoices": [
      { "invoice_id": "INV-001", "vendor": "Acme Corp", "amount": 10000.00, "date": "2026-01-15" },
      { "invoice_id": "INV-002", "vendor": "Globex Inc", "amount": 4500.00, "date": "2026-01-18" },
      { "invoice_id": "INV-003", "vendor": "Initech", "amount": 7250.00, "date": "2026-01-20" },
      { "invoice_id": "INV-004", "vendor": "Umbrella Ltd", "amount": 15000.00, "date": "2026-01-22" },
      { "invoice_id": "INV-005", "vendor": "Stark Industries", "amount": 3200.00, "date": "2026-01-25" }
    ],
    "payments": [
      { "invoice_id": "INV-001", "vendor": "Acme Corp", "amount": 10000.00, "date": "2026-01-16" },
      { "invoice_id": "INV-002", "vendor": "Globex Inc", "amount": 4480.00, "date": "2026-01-19" },
      { "invoice_id": "INV-004", "vendor": "Umbrela Ltd", "amount": 15000.00, "date": "2026-01-23" },
      { "invoice_id": "INV-006", "vendor": "Wayne Enterprises", "amount": 8800.00, "date": "2026-01-27" }
    ]
  }'

Response:

json
{ "id": "run_abc123", "status": "running" }

Step 4: Check Results

GET/runs/:runId/status

Poll for status. The run will pause at PbotApproval waiting for human review.

bash
curl http://localhost:3009/runs/run_abc123/status \
  -H "X-Org-Id: your-org"

Expected matcher output:

Record Result Why
INV-001 ✅ Matched Exact match, 1-day date offset
INV-002 ✅ Matched $4,500 vs $4,480 — within 2% tolerance
INV-004 ✅ Matched "Umbrella" vs "Umbrela" — 87% fuzzy match
INV-003 ❌ Unmatched No payment found
INV-005 ❌ Unmatched No payment found
INV-006 ❌ Unmatched payment No invoice found

The matcher handled 3 of 5 invoices automatically — including the amount discrepancy and vendor typo. No AI cost. Near-instant.

The 2 unmatched invoices flow to the ReAct agent. Sample reasoning trace:

text
Iteration 1:
  Thought: "INV-003 from Initech — no payment match. Dated Jan 20,
            only 16 days ago. Standard terms are net-30."
  Action: __log_progress__
  Input: { "message": "INV-003 likely within payment terms" }

Iteration 3:
  Thought: "Both INV-003 and INV-005 are recent. Recommend: monitor
            for 30 days, then follow up if still unmatched."
  Action: __complete__
  Input: {
    "answer": "2 unmatched invoices — both within payment terms. Recommend: wait 30 days.",
    "confidence": 0.85
  }

Step 5: Approve

The workflow pauses at PbotApproval. The reviewer sees matched records, exceptions, and the AI investigation.

POST/approvals/:runId/:stepIndex

Submit the human decision. It becomes part of the permanent audit trail.

bash
curl -X POST http://localhost:3009/approvals/run_abc123/2 \
  -H "X-Org-Id: your-org" \
  -H "Content-Type: application/json" \
  -d '{
    "approved": true,
    "comments": "Agree with AI recommendation. Monitor and follow up in 30 days.",
    "data": { "reviewer": "[email protected]" }
  }'

The workflow resumes, logs to the audit table, and completes.

What just happened. One API call matched 60% of records automatically, got AI investigation of exceptions, routed edge cases to a human with full context, and logged everything. Manual process: 4+ hours. Hyphen: ~30 seconds of compute.

---

API Fast Path

For developers who want the five-minute tour.

Setup

bash
BASE_URL=http://localhost:3009
ORG_ID=your-org

1. Health Check

:::api GET /health :::

bash
curl $BASE_URL/health
# → { "status": "ok" }

2. Register an Action

POST/actions

Register a reusable operation — HTTP, LLM, DB, matcher, or custom-table.

bash
curl -X POST $BASE_URL/actions \
  -H "X-Org-Id: $ORG_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "action_name": "fetch_customer",
    "kind": "http",
    "url": "https://api.example.com/customers/{{customer_id}}",
    "http_method": "GET",
    "passthrough": true
  }'
# → { "id": "act_abc123", "action_name": "fetch_customer" }

3. Create a Workflow

:::api POST /workflows :::

bash
curl -X POST $BASE_URL/workflows \
  -H "X-Org-Id: $ORG_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my_first_workflow",
    "definition": {
      "actions": [
        { "type": "fetch_customer", "properties": { "customer_id": "@input.id" } },
        { "type": "custom-table", "properties": {
            "table": "audit_log", "operation": "write",
            "keys": ["action"], "values": ["customer_lookup"]
        }}
      ]
    }
  }'
# → { "id": "wf_xyz789" }

4. Execute

:::api POST /workflows/:id/execute :::

bash
curl -X POST $BASE_URL/workflows/wf_xyz789/execute \
  -H "X-Org-Id: $ORG_ID" \
  -H "Content-Type: application/json" \
  -d '{ "id": "cust-12345" }'
# → { "id": "run_abc", "status": "running" }

5. Check Status

:::api GET /runs/:runId/status :::

bash
curl $BASE_URL/runs/run_abc/status -H "X-Org-Id: $ORG_ID"
# → { "status": "completed", "context": { ... } }

6. Run a Standalone Agent

POST/agents/execute

Execute an AI agent outside of a workflow — agent-as-trigger or agent-as-orchestrator pattern.

bash
curl -X POST $BASE_URL/agents/execute \
  -H "X-Org-Id: $ORG_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "objective": "Analyze this support ticket and draft a response",
    "tools": [
      { "type": "action", "name": "fetch_customer" },
      { "type": "action", "name": "gmail_send" }
    ],
    "config": {
      "model": "gpt-4",
      "max_iterations": 10,
      "on_stuck": { "iterations": 3, "action": "escalate" }
    }
  }'

7. Get the Reasoning Trace

GET/agents/:id/trace

Full audit trail — every thought, action, and observation.

bash
curl $BASE_URL/agents/{agent_run_id}/trace -H "X-Org-Id: $ORG_ID"

Next Steps: Connect Your Systems

Register actions to connect your systems, then reference them as agent tools using typed declarations.

HTTP action (any internal API):

bash
curl -X POST $BASE_URL/actions \
  -H "X-Org-Id: $ORG_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "action_name": "lookup_record",
    "kind": "http",
    "url": "https://your-system.com/api/records/{{record_id}}",
    "http_method": "GET",
    "headers": { "Authorization": "Bearer orgconfig:api:system_token" }
  }'

LLM action (AI analysis):

bash
curl -X POST $BASE_URL/actions \
  -H "X-Org-Id: $ORG_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "action_name": "analyze_exception",
    "kind": "llm",
    "template": "Analyze this operational exception and recommend a resolution:\n\n{{exception_data}}",
    "model": "gpt-4",
    "max_tokens": 300
  }'

Then use them as typed tool references in any agent:

json
{
  "mode": "react",
  "objective": "Investigate this exception and notify the responsible party",
  "tools": [
    { "type": "action", "name": "lookup_record" },
    { "type": "action", "name": "analyze_exception" },
    { "type": "action", "name": "gmail_send" },
    { "type": "workflow", "id": "wf_escalation_process" }
  ]
}

Note: Built-in tools (__complete__, __pause_for_human__, __store_memory__, __retrieve_memory__, __log_progress__) are automatically injected — you never need to list them.

---

Same Architecture, Different Domains

The reconciliation example above demonstrates the graduated pipeline. Here's how the same pattern applies across industries:

Domain What plays the "Matcher" role What the Agent investigates Who reviews
IT Security Correlate alerts against known-benign indicators Enrich with threat intel, assess severity, recommend containment SOC analyst
Legal Compare extracted contract terms against standard playbook Classify deviation risk, search precedent, draft redlines Legal counsel
People Ops N/A — agent orchestrates directly Coordinate IT provisioning, benefits, training, equipment HR coordinator
Healthcare Match claims to policies, detect duplicates Analyze denial codes, check medical necessity, draft appeals Clinical reviewer

See all templates →


Three Things to Remember

1. You don't need AI for everything. The matcher handles the majority of operational data work with zero AI cost. Start with deterministic rules. Add AI only for exceptions that require judgment.

2. Governance is structural, not policy. The agent can only use tools you've declared, can only iterate up to the cap you set, and escalates automatically when stuck. This is architecture, not a policy document.

3. Every decision is auditable. Matcher results, agent reasoning traces, human approval decisions — all captured, all queryable, all persistent.

Continue learning: Core Concepts explains the six building blocks. Your First Workflow walks through building a more complex pipeline step by step. Templates show production-ready patterns across finance, IT, legal, healthcare, and people operations.