Skill: aronchick/expanso-json-to-csv (version 1.0.0)

# json-to-csv "Convert JSON array of objects to CSV format" ## Requirements - Expanso Edge installed (`expanso-edge` binary in PATH) - Install via: `clawhub install expanso-edge` ## Usage ### CLI Pipeline ```bash # Run standalone echo '<input>' | expanso-edge run pipeline-cli.yaml ``` ### MCP Pipeline ```bash # Start as MCP server expanso-edge run pipeline-mcp.yaml ``` ### Deploy to Expanso Cloud ```bash expanso-cli job deploy https://skills.expanso.io/json-to-csv/pipeline-cli.yaml ``` ## Files | File | Purpose | |------|---------| | `skill.yaml` | Skill metadata (inputs, outputs, credentials) | | `pipeline-cli.yaml` | Standalone CLI pipeline | | `pipeline-mcp.yaml` | MCP server pipeline |

path: README.md
content: # json-to-csv

Convert JSON array of objects to CSV format.

## Overview

This skill converts a JSON array to CSV with automatic header detection. Runs entirely locally.

## Usage

### CLI Mode

```bash
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' | \
  expanso-edge run pipeline-cli.yaml
```

### MCP Mode

```bash
PORT=8080 expanso-edge run pipeline-mcp.yaml &
curl -X POST http://localhost:8080/convert \
  -H "Content-Type: application/json" \
  -d '{"data": [{"name":"Alice","age":30},{"name":"Bob","age":25}]}'
```

## Output

```json
{
  "csv": "name,age\nAlice,30\nBob,25",
  "row_count": 2,
  "columns": ["name", "age"],
  "metadata": {...}
}
```

## Use Cases

- Data export
- Spreadsheet generation
- Report creation
- API response formatting


path: pipeline-cli.yaml
content: # Expanso Pipeline: json-to-csv (CLI mode)
# =========================================
#
# Usage:
#   echo '[{"name":"Alice","age":30}]' | expanso-edge run pipeline-cli.yaml
#
# No API key needed - runs entirely locally.

name: "json-to-csv-cli"
type: pipeline

config:
  input:
    stdin:
      codec: all
      max_buffer: 10485760

  pipeline:
    processors:
      - mapping: |
          meta trace_id = uuid_v4()
          let delimiter = env("DELIMITER").or(",")

          # Parse JSON input
          let data = content().parse_json().catch([])
          let data = if $data.type() == "array" { $data } else { [$data] }

          # Get all unique keys from all objects
          let columns = $data.fold([], pair -> pair.value.keys().or([]).fold(pair.tally, kp -> if kp.tally.contains(kp.value) { kp.tally } else { kp.tally.append(kp.value) }))

          # Build CSV rows
          let header = $columns.join($delimiter)
          let rows = $data.map_each(obj -> $columns.map_each(col -> if obj.get(col).or("").string().contains($delimiter) || obj.get(col).or("").string().contains("\"") {
            "\"" + obj.get(col).or("").string().re_replace_all("\"", "\"\"") + "\""
          } else { obj.get(col).or("").string() }).join($delimiter))

          root.csv = $header + "\n" + $rows.join("\n")
          root.row_count = $data.length()
          root.columns = $columns
          root.metadata = {
            "skill": "json-to-csv",
            "mode": "cli",
            "delimiter": $delimiter,
            "trace_id": meta("trace_id"),
            "timestamp": now()
          }

      - log:
          level: INFO
          message: |
            [json-to-csv] Converted ${! root.row_count } rows (trace: ${! meta("trace_id").slice(0, 8) })

  output:
    stdout:
      codec: json_object


path: pipeline-mcp.yaml
content: # Expanso Pipeline: json-to-csv (MCP mode)
# =========================================
#
# Usage:
#   PORT=8080 expanso-edge run pipeline-mcp.yaml &
#   curl -X POST http://localhost:8080/convert \
#     -d '{"data": [{"name":"Alice","age":30}]}'

name: "json-to-csv-mcp"
type: pipeline

config:
  http:
    enabled: true
    address: "0.0.0.0:${PORT:-8080}"

  input:
    http_server:
      path: /convert
      allowed_verbs: [POST]
      timeout: 60s

  pipeline:
    processors:
      - mapping: |
          meta trace_id = uuid_v4()
          let delimiter = this.delimiter.or(",")
          let data = this.data.or([])
          let data = if $data.type() == "array" { $data } else { [$data] }

          let columns = $data.fold([], pair -> pair.value.keys().or([]).fold(pair.tally, kp -> if kp.tally.contains(kp.value) { kp.tally } else { kp.tally.append(kp.value) }))

          let header = $columns.join($delimiter)
          let rows = $data.map_each(obj -> $columns.map_each(col -> if obj.get(col).or("").string().contains($delimiter) || obj.get(col).or("").string().contains("\"") {
            "\"" + obj.get(col).or("").string().re_replace_all("\"", "\"\"") + "\""
          } else { obj.get(col).or("").string() }).join($delimiter))

          root.csv = $header + "\n" + $rows.join("\n")
          root.row_count = $data.length()
          root.columns = $columns
          root.metadata = {
            "skill": "json-to-csv",
            "mode": "mcp",
            "delimiter": $delimiter,
            "trace_id": meta("trace_id"),
            "timestamp": now()
          }

      - log:
          level: INFO
          message: |
            [json-to-csv] Converted ${! root.row_count } rows (trace: ${! meta("trace_id").slice(0, 8) })

  output:
    sync_response: {}


path: skill.yaml
content: # Skill: json-to-csv
# Version: 1.0.0
#
# Convert JSON array to CSV.
# Runs locally without API calls.

name: "json-to-csv"
version: "1.0.0"
description: "Convert JSON array of objects to CSV format"

author:
  name: "Expanso Team"
  url: "https://expanso.io"
  avatar: "EX"

credentials: []

inputs:
  - name: data
    type: array
    required: true
    description: JSON array of objects
  - name: delimiter
    type: string
    default: ","
    description: Field delimiter

outputs:
  - name: csv
    type: string
    description: CSV formatted string
  - name: row_count
    type: integer
    description: Number of data rows
  - name: columns
    type: array
    description: Column names

backends:
  - name: local
    type: local
    requires: []
    description: Pure local conversion

components:
  inputs:
    - stdin
    - http_server
  processors:
    - mapping
  outputs:
    - stdout
    - sync_response


path: test/fixtures/input.txt
content: name: Alice
email: [REDACTED_SECRET]

name: Bob
email: [REDACTED_SECRET]

path: test/test.yaml
content: # Test cases for json-to-csv skill

tests:
  - name: "Convert JSON array"
    input: '[{"name":"Alice","age":30}]'
    expected:
      has_field: csv
      has_field: row_count
      has_field: columns
      metadata_has: [skill, trace_id, timestamp]


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)