AgentSkillsCN

map-json-converter

将人类可读的自动化计划转换为Sequence JSON格式。在以下场景中使用此功能:(1) 将序列地图生成器中的计划转化为可导入的JSON;(2) 根据Sequence模式验证JSON结构;(3) 为地图生成节点ID与位置;(4) 在人类可读的规则描述与JSON规则对象之间进行转换。

SKILL.md
--- frontmatter
name: map-json-converter
description: Convert human-readable automation plans to Sequence JSON format. Use when: (1) Transforming a plan from sequence-map-generator into importable JSON, (2) Validating JSON structure against the Sequence schema, (3) Generating node IDs and positions for a map, (4) Converting between human-readable rule descriptions and JSON rule objects.

Map JSON Converter

Transform human-readable automation plans into the Sequence JSON map format.

Overview

This skill converts plans generated by sequence-map-generator into the exact JSON structure that Sequence can import. It handles node creation, rule generation, and proper positioning.

JSON Schema

Top-Level Structure

json
{
  "nodes": [...],
  "rules": [...],
  "viewport": {
    "x": 321.5,
    "y": -198.4,
    "zoom": 0.9
  }
}

Node Schema

json
{
  "id": "uuid-string",
  "type": "POD | PORT | DEPOSITORY_ACCOUNT | LIABILITY_ACCOUNT",
  "subtype": "CHECKING | SAVINGS | CREDIT_CARD | LOAN | null",
  "name": "Human readable name",
  "balance": 0,
  "icon": "emoji",
  "position": {
    "x": 500,
    "y": 300
  }
}

Rule Schema

json
{
  "id": "uuid-string",
  "sourceId": "node-uuid",
  "trigger": {
    "type": "INCOMING_FUNDS | SCHEDULED | BALANCE_THRESHOLD",
    "sourceId": "node-uuid",
    "cron": "0 0 1 * *"  // for SCHEDULED only
  },
  "steps": [
    {
      "actions": [...]
    }
  ]
}

Action Schema

json
{
  "type": "PERCENTAGE | FIXED | REMAINDER | TOP_UP | AVALANCHE | SNOWBALL | NEXT_PAYMENT_MINIMUM | TOTAL_AMOUNT_DUE | ROUND_DOWN",
  "sourceId": "node-uuid",
  "destinationId": "node-uuid",
  "amountInCents": 10000,
  "amountInPercentage": 0,
  "groupIndex": 0,
  "limit": null,
  "upToEnabled": null
}

Conversion Process

Step 1: Parse Human-Readable Plan

Extract from the plan:

  • Node names and types
  • Rule triggers and actions
  • Relationships between nodes

Step 2: Generate Nodes

python
import uuid

def create_node(name, node_type, subtype=None, balance=0):
    icons = {
        'POD': '💰',
        'PORT': '📥',
        'DEPOSITORY_ACCOUNT': '🏦',
        'LIABILITY_ACCOUNT': '💳'
    }

    return {
        'id': str(uuid.uuid4()),
        'type': node_type,
        'subtype': subtype,
        'name': name,
        'balance': balance,
        'icon': icons.get(node_type, '💰'),
        'position': {'x': 0, 'y': 0}  # Calculate later
    }

Step 3: Calculate Positions

Arrange nodes in a logical flow:

python
def calculate_positions(nodes, rules):
    """
    Layout strategy:
    - Income sources (PORT) on left
    - Router/allocation pods in middle
    - Destination pods/accounts on right
    - Liabilities at bottom
    """

    positions = {}
    x_start, y_start = 200, 200
    spacing_x, spacing_y = 250, 150

    # Group by type
    ports = [n for n in nodes if n['type'] == 'PORT']
    pods = [n for n in nodes if n['type'] == 'POD']
    accounts = [n for n in nodes if n['type'] == 'DEPOSITORY_ACCOUNT']
    liabilities = [n for n in nodes if n['type'] == 'LIABILITY_ACCOUNT']

    # Position ports on left
    for i, node in enumerate(ports):
        positions[node['id']] = {'x': x_start, 'y': y_start + i * spacing_y}

    # Position pods in middle columns
    for i, node in enumerate(pods):
        col = i // 4
        row = i % 4
        positions[node['id']] = {
            'x': x_start + spacing_x + col * spacing_x,
            'y': y_start + row * spacing_y
        }

    # Position accounts on right
    for i, node in enumerate(accounts):
        positions[node['id']] = {
            'x': x_start + spacing_x * 3,
            'y': y_start + i * spacing_y
        }

    # Position liabilities at bottom
    for i, node in enumerate(liabilities):
        positions[node['id']] = {
            'x': x_start + i * spacing_x,
            'y': y_start + spacing_y * 4
        }

    return positions

Step 4: Generate Rules

python
def create_rule(source_id, trigger_type, actions, cron=None):
    trigger = {
        'type': trigger_type,
        'sourceId': source_id,
        'cron': cron
    }

    return {
        'id': str(uuid.uuid4()),
        'sourceId': source_id,
        'trigger': trigger,
        'steps': [{'actions': actions}]
    }

def create_action(action_type, source_id, dest_id, amount=None, percentage=None, group_index=0):
    action = {
        'type': action_type,
        'sourceId': source_id,
        'destinationId': dest_id,
        'amountInCents': int(amount * 100) if amount else 0,
        'amountInPercentage': percentage or 0,
        'groupIndex': group_index,
        'limit': None,
        'upToEnabled': None
    }
    return action

Action Type Mapping

Human DescriptionAction TypeKey Fields
"X% of funds"PERCENTAGEamountInPercentage
"$X moves"FIXEDamountInCents
"Remaining funds"REMAINDER-
"Fill up to $X"TOP_UPlimit (cents)
"Pay highest interest first"AVALANCHEgroupIndex (same for all)
"Pay smallest balance first"SNOWBALLgroupIndex (same for all)
"Pay minimum due"NEXT_PAYMENT_MINIMUMupToEnabled
"Pay full balance"TOTAL_AMOUNT_DUE-
"Round down to nearest $X"ROUND_DOWN-

Trigger Type Mapping

Human DescriptionTrigger TypeAdditional Fields
"When funds are received"INCOMING_FUNDS-
"On the Xth of month"SCHEDULEDcron: "0 0 X * *"
"Every week on DAY"SCHEDULEDcron: "0 0 * * DAY"
"When balance reaches $X"BALANCE_THRESHOLDcondition in trigger

Cron Patterns

code
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, SUN-SAT)
│ │ │ │ │
* * * * *

Common patterns:

  • 0 0 1 * * - 1st of every month
  • 0 0 15 * * - 15th of every month
  • 0 0 * * MON - Every Monday
  • 0 0 * * FRI - Every Friday
  • 0 0 1,15 * * - 1st and 15th of month

Complete Conversion Example

Input Plan:

code
Goal: Pay off credit cards

Nodes:
- Paycheck (PORT)
- Budget Router (POD)
- Bills Pod (POD)
- Debt Payment Pod (POD)
- Chase Card (LIABILITY_ACCOUNT, CREDIT_CARD)
- Amex Card (LIABILITY_ACCOUNT, CREDIT_CARD)

Rules:
1. When Paycheck receives funds: 100% to Budget Router
2. When Budget Router receives funds:
   - 60% to Bills Pod
   - 40% to Debt Payment Pod
3. When Debt Payment Pod receives funds:
   - AVALANCHE to Chase Card, Amex Card

Output JSON:

json
{
  "nodes": [
    {
      "id": "node-paycheck",
      "type": "PORT",
      "name": "Paycheck",
      "icon": "📥",
      "position": {"x": 200, "y": 200}
    },
    {
      "id": "node-router",
      "type": "POD",
      "name": "Budget Router",
      "icon": "💰",
      "position": {"x": 450, "y": 200}
    },
    {
      "id": "node-bills",
      "type": "POD",
      "name": "Bills Pod",
      "icon": "💰",
      "position": {"x": 700, "y": 150}
    },
    {
      "id": "node-debt",
      "type": "POD",
      "name": "Debt Payment Pod",
      "icon": "💰",
      "position": {"x": 700, "y": 300}
    },
    {
      "id": "node-chase",
      "type": "LIABILITY_ACCOUNT",
      "subtype": "CREDIT_CARD",
      "name": "Chase Card",
      "icon": "💳",
      "position": {"x": 400, "y": 500}
    },
    {
      "id": "node-amex",
      "type": "LIABILITY_ACCOUNT",
      "subtype": "CREDIT_CARD",
      "name": "Amex Card",
      "icon": "💳",
      "position": {"x": 650, "y": 500}
    }
  ],
  "rules": [
    {
      "id": "rule-1",
      "sourceId": "node-paycheck",
      "trigger": {
        "type": "INCOMING_FUNDS",
        "sourceId": "node-paycheck"
      },
      "steps": [{
        "actions": [{
          "type": "PERCENTAGE",
          "sourceId": "node-paycheck",
          "destinationId": "node-router",
          "amountInPercentage": 100,
          "amountInCents": 0,
          "groupIndex": 0
        }]
      }]
    },
    {
      "id": "rule-2",
      "sourceId": "node-router",
      "trigger": {
        "type": "INCOMING_FUNDS",
        "sourceId": "node-router"
      },
      "steps": [{
        "actions": [
          {
            "type": "PERCENTAGE",
            "sourceId": "node-router",
            "destinationId": "node-bills",
            "amountInPercentage": 60,
            "groupIndex": 0
          },
          {
            "type": "PERCENTAGE",
            "sourceId": "node-router",
            "destinationId": "node-debt",
            "amountInPercentage": 40,
            "groupIndex": 1
          }
        ]
      }]
    },
    {
      "id": "rule-3",
      "sourceId": "node-debt",
      "trigger": {
        "type": "INCOMING_FUNDS",
        "sourceId": "node-debt"
      },
      "steps": [{
        "actions": [
          {
            "type": "AVALANCHE",
            "sourceId": "node-debt",
            "destinationId": "node-chase",
            "amountInPercentage": 100,
            "groupIndex": 0
          },
          {
            "type": "AVALANCHE",
            "sourceId": "node-debt",
            "destinationId": "node-amex",
            "amountInPercentage": 100,
            "groupIndex": 0
          }
        ]
      }]
    }
  ],
  "viewport": {
    "x": 300,
    "y": 100,
    "zoom": 0.9
  }
}

References

  • schema.md - Complete JSON schema specification