{
  "schemaVersion": "1.0",
  "item": {
    "slug": "csv-handler",
    "name": "Csv Handler",
    "source": "tencent",
    "type": "skill",
    "category": "数据分析",
    "sourceUrl": "https://clawhub.ai/datadrivenconstruction/csv-handler",
    "canonicalUrl": "https://clawhub.ai/datadrivenconstruction/csv-handler",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/csv-handler",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=csv-handler",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "claw.json",
      "instructions.md",
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-23T16:43:11.935Z",
      "expiresAt": "2026-04-30T16:43:11.935Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
        "contentDisposition": "attachment; filename=\"4claw-imageboard-1.0.1.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/csv-handler"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/csv-handler",
    "agentPageUrl": "https://openagent3.xyz/skills/csv-handler/agent",
    "manifestUrl": "https://openagent3.xyz/skills/csv-handler/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/csv-handler/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Overview",
        "body": "CSV is the universal exchange format in construction - from scheduling exports to cost databases. This skill handles encoding issues, delimiter detection, and data cleaning."
      },
      {
        "title": "Python Implementation",
        "body": "import pandas as pd\nimport csv\nfrom typing import Dict, Any, List, Optional, Tuple\nfrom pathlib import Path\nfrom dataclasses import dataclass\nimport chardet\n\n\n@dataclass\nclass CSVProfile:\n    \"\"\"Profile of CSV file.\"\"\"\n    encoding: str\n    delimiter: str\n    has_header: bool\n    row_count: int\n    column_count: int\n    columns: List[str]\n\n\nclass ConstructionCSVHandler:\n    \"\"\"Handle CSV files from construction software.\"\"\"\n\n    COMMON_DELIMITERS = [',', ';', '\\t', '|']\n    COMMON_ENCODINGS = ['utf-8', 'utf-8-sig', 'latin-1', 'cp1252', 'iso-8859-1']\n\n    def __init__(self):\n        self.last_profile: Optional[CSVProfile] = None\n\n    def detect_encoding(self, file_path: str) -> str:\n        \"\"\"Detect file encoding.\"\"\"\n        with open(file_path, 'rb') as f:\n            raw = f.read(10000)\n        result = chardet.detect(raw)\n        return result.get('encoding', 'utf-8') or 'utf-8'\n\n    def detect_delimiter(self, file_path: str, encoding: str) -> str:\n        \"\"\"Detect CSV delimiter.\"\"\"\n        with open(file_path, 'r', encoding=encoding, errors='replace') as f:\n            sample = f.read(5000)\n\n        # Count occurrences\n        counts = {d: sample.count(d) for d in self.COMMON_DELIMITERS}\n\n        # Return most common that appears consistently\n        if counts:\n            return max(counts, key=counts.get)\n        return ','\n\n    def profile_csv(self, file_path: str) -> CSVProfile:\n        \"\"\"Profile CSV file.\"\"\"\n        encoding = self.detect_encoding(file_path)\n        delimiter = self.detect_delimiter(file_path, encoding)\n\n        # Read sample\n        df = pd.read_csv(file_path, encoding=encoding, delimiter=delimiter,\n                         nrows=10, on_bad_lines='skip')\n\n        has_header = not df.columns[0].replace('.', '').replace('-', '').isdigit()\n\n        # Full row count\n        with open(file_path, 'r', encoding=encoding, errors='replace') as f:\n            row_count = sum(1 for _ in f) - (1 if has_header else 0)\n\n        profile = CSVProfile(\n            encoding=encoding,\n            delimiter=delimiter,\n            has_header=has_header,\n            row_count=row_count,\n            column_count=len(df.columns),\n            columns=list(df.columns)\n        )\n        self.last_profile = profile\n        return profile\n\n    def read_csv(self, file_path: str,\n                 encoding: Optional[str] = None,\n                 delimiter: Optional[str] = None,\n                 clean: bool = True) -> pd.DataFrame:\n        \"\"\"Read CSV with auto-detection.\"\"\"\n\n        # Auto-detect if not provided\n        if encoding is None:\n            encoding = self.detect_encoding(file_path)\n        if delimiter is None:\n            delimiter = self.detect_delimiter(file_path, encoding)\n\n        # Read with error handling\n        df = pd.read_csv(\n            file_path,\n            encoding=encoding,\n            delimiter=delimiter,\n            on_bad_lines='skip',\n            low_memory=False\n        )\n\n        if clean:\n            df = self.clean_dataframe(df)\n\n        return df\n\n    def clean_dataframe(self, df: pd.DataFrame) -> pd.DataFrame:\n        \"\"\"Clean construction CSV data.\"\"\"\n        # Clean column names\n        df.columns = [self._clean_column_name(c) for c in df.columns]\n\n        # Remove empty rows and columns\n        df = df.dropna(how='all')\n        df = df.dropna(axis=1, how='all')\n\n        # Strip whitespace from strings\n        for col in df.select_dtypes(include=['object']):\n            df[col] = df[col].str.strip() if df[col].dtype == 'object' else df[col]\n\n        return df\n\n    def _clean_column_name(self, name: str) -> str:\n        \"\"\"Clean column name.\"\"\"\n        if not isinstance(name, str):\n            return str(name)\n\n        # Remove special characters, replace spaces\n        clean = name.strip().lower()\n        clean = clean.replace(' ', '_').replace('-', '_')\n        clean = ''.join(c for c in clean if c.isalnum() or c == '_')\n        return clean\n\n    def merge_csvs(self, file_paths: List[str],\n                   on_column: Optional[str] = None) -> pd.DataFrame:\n        \"\"\"Merge multiple CSV files.\"\"\"\n        dfs = []\n        for path in file_paths:\n            df = self.read_csv(path)\n            df['_source_file'] = Path(path).name\n            dfs.append(df)\n\n        if not dfs:\n            return pd.DataFrame()\n\n        if on_column and on_column in dfs[0].columns:\n            result = dfs[0]\n            for df in dfs[1:]:\n                result = pd.merge(result, df, on=on_column, how='outer')\n            return result\n\n        return pd.concat(dfs, ignore_index=True)\n\n    def split_csv(self, df: pd.DataFrame,\n                  group_column: str,\n                  output_dir: str) -> List[str]:\n        \"\"\"Split CSV by column values.\"\"\"\n        output_path = Path(output_dir)\n        output_path.mkdir(parents=True, exist_ok=True)\n\n        files = []\n        for value in df[group_column].unique():\n            subset = df[df[group_column] == value]\n            filename = f\"{group_column}_{value}.csv\"\n            filepath = output_path / filename\n            subset.to_csv(filepath, index=False)\n            files.append(str(filepath))\n\n        return files\n\n    def convert_types(self, df: pd.DataFrame,\n                      type_map: Dict[str, str] = None) -> pd.DataFrame:\n        \"\"\"Convert column types intelligently.\"\"\"\n        df = df.copy()\n\n        if type_map:\n            for col, dtype in type_map.items():\n                if col in df.columns:\n                    try:\n                        df[col] = df[col].astype(dtype)\n                    except:\n                        pass\n        else:\n            # Auto-convert\n            for col in df.columns:\n                # Try numeric\n                try:\n                    df[col] = pd.to_numeric(df[col])\n                    continue\n                except:\n                    pass\n\n                # Try datetime\n                try:\n                    df[col] = pd.to_datetime(df[col])\n                except:\n                    pass\n\n        return df\n\n    def export_csv(self, df: pd.DataFrame,\n                   file_path: str,\n                   encoding: str = 'utf-8-sig',\n                   delimiter: str = ',') -> str:\n        \"\"\"Export DataFrame to CSV.\"\"\"\n        df.to_csv(file_path, encoding=encoding, sep=delimiter, index=False)\n        return file_path\n\n\n# Specialized handlers\nclass ScheduleCSVHandler(ConstructionCSVHandler):\n    \"\"\"Handler for project schedule CSVs.\"\"\"\n\n    SCHEDULE_COLUMNS = ['task_id', 'task_name', 'start_date', 'end_date',\n                        'duration', 'predecessors', 'resources']\n\n    def parse_schedule(self, file_path: str) -> pd.DataFrame:\n        \"\"\"Parse schedule CSV.\"\"\"\n        df = self.read_csv(file_path)\n\n        # Convert date columns\n        for col in df.columns:\n            if 'date' in col.lower() or 'start' in col.lower() or 'end' in col.lower():\n                try:\n                    df[col] = pd.to_datetime(df[col])\n                except:\n                    pass\n\n        return df\n\n\nclass CostCSVHandler(ConstructionCSVHandler):\n    \"\"\"Handler for cost/estimate CSVs.\"\"\"\n\n    def parse_costs(self, file_path: str) -> pd.DataFrame:\n        \"\"\"Parse cost CSV.\"\"\"\n        df = self.read_csv(file_path)\n\n        # Find and convert numeric columns\n        for col in df.columns:\n            if any(word in col.lower() for word in ['cost', 'price', 'amount', 'total', 'qty', 'quantity']):\n                df[col] = pd.to_numeric(df[col].replace(r'[\\$,]', '', regex=True), errors='coerce')\n\n        return df"
      },
      {
        "title": "Quick Start",
        "body": "handler = ConstructionCSVHandler()\n\n# Profile CSV first\nprofile = handler.profile_csv(\"export.csv\")\nprint(f\"Encoding: {profile.encoding}, Delimiter: '{profile.delimiter}'\")\n\n# Read with auto-detection\ndf = handler.read_csv(\"export.csv\")\nprint(f\"Loaded {len(df)} rows, {len(df.columns)} columns\")"
      },
      {
        "title": "1. Merge Multiple Exports",
        "body": "files = [\"jan_export.csv\", \"feb_export.csv\", \"mar_export.csv\"]\nmerged = handler.merge_csvs(files)"
      },
      {
        "title": "2. Split by Category",
        "body": "handler.split_csv(df, group_column='category', output_dir='./split_files')"
      },
      {
        "title": "3. Schedule Import",
        "body": "schedule_handler = ScheduleCSVHandler()\nschedule = schedule_handler.parse_schedule(\"p6_export.csv\")"
      },
      {
        "title": "Resources",
        "body": "DDC Book: Chapter 2.1 - Structured Data"
      }
    ],
    "body": "CSV Handler for Construction Data\nOverview\n\nCSV is the universal exchange format in construction - from scheduling exports to cost databases. This skill handles encoding issues, delimiter detection, and data cleaning.\n\nPython Implementation\nimport pandas as pd\nimport csv\nfrom typing import Dict, Any, List, Optional, Tuple\nfrom pathlib import Path\nfrom dataclasses import dataclass\nimport chardet\n\n\n@dataclass\nclass CSVProfile:\n    \"\"\"Profile of CSV file.\"\"\"\n    encoding: str\n    delimiter: str\n    has_header: bool\n    row_count: int\n    column_count: int\n    columns: List[str]\n\n\nclass ConstructionCSVHandler:\n    \"\"\"Handle CSV files from construction software.\"\"\"\n\n    COMMON_DELIMITERS = [',', ';', '\\t', '|']\n    COMMON_ENCODINGS = ['utf-8', 'utf-8-sig', 'latin-1', 'cp1252', 'iso-8859-1']\n\n    def __init__(self):\n        self.last_profile: Optional[CSVProfile] = None\n\n    def detect_encoding(self, file_path: str) -> str:\n        \"\"\"Detect file encoding.\"\"\"\n        with open(file_path, 'rb') as f:\n            raw = f.read(10000)\n        result = chardet.detect(raw)\n        return result.get('encoding', 'utf-8') or 'utf-8'\n\n    def detect_delimiter(self, file_path: str, encoding: str) -> str:\n        \"\"\"Detect CSV delimiter.\"\"\"\n        with open(file_path, 'r', encoding=encoding, errors='replace') as f:\n            sample = f.read(5000)\n\n        # Count occurrences\n        counts = {d: sample.count(d) for d in self.COMMON_DELIMITERS}\n\n        # Return most common that appears consistently\n        if counts:\n            return max(counts, key=counts.get)\n        return ','\n\n    def profile_csv(self, file_path: str) -> CSVProfile:\n        \"\"\"Profile CSV file.\"\"\"\n        encoding = self.detect_encoding(file_path)\n        delimiter = self.detect_delimiter(file_path, encoding)\n\n        # Read sample\n        df = pd.read_csv(file_path, encoding=encoding, delimiter=delimiter,\n                         nrows=10, on_bad_lines='skip')\n\n        has_header = not df.columns[0].replace('.', '').replace('-', '').isdigit()\n\n        # Full row count\n        with open(file_path, 'r', encoding=encoding, errors='replace') as f:\n            row_count = sum(1 for _ in f) - (1 if has_header else 0)\n\n        profile = CSVProfile(\n            encoding=encoding,\n            delimiter=delimiter,\n            has_header=has_header,\n            row_count=row_count,\n            column_count=len(df.columns),\n            columns=list(df.columns)\n        )\n        self.last_profile = profile\n        return profile\n\n    def read_csv(self, file_path: str,\n                 encoding: Optional[str] = None,\n                 delimiter: Optional[str] = None,\n                 clean: bool = True) -> pd.DataFrame:\n        \"\"\"Read CSV with auto-detection.\"\"\"\n\n        # Auto-detect if not provided\n        if encoding is None:\n            encoding = self.detect_encoding(file_path)\n        if delimiter is None:\n            delimiter = self.detect_delimiter(file_path, encoding)\n\n        # Read with error handling\n        df = pd.read_csv(\n            file_path,\n            encoding=encoding,\n            delimiter=delimiter,\n            on_bad_lines='skip',\n            low_memory=False\n        )\n\n        if clean:\n            df = self.clean_dataframe(df)\n\n        return df\n\n    def clean_dataframe(self, df: pd.DataFrame) -> pd.DataFrame:\n        \"\"\"Clean construction CSV data.\"\"\"\n        # Clean column names\n        df.columns = [self._clean_column_name(c) for c in df.columns]\n\n        # Remove empty rows and columns\n        df = df.dropna(how='all')\n        df = df.dropna(axis=1, how='all')\n\n        # Strip whitespace from strings\n        for col in df.select_dtypes(include=['object']):\n            df[col] = df[col].str.strip() if df[col].dtype == 'object' else df[col]\n\n        return df\n\n    def _clean_column_name(self, name: str) -> str:\n        \"\"\"Clean column name.\"\"\"\n        if not isinstance(name, str):\n            return str(name)\n\n        # Remove special characters, replace spaces\n        clean = name.strip().lower()\n        clean = clean.replace(' ', '_').replace('-', '_')\n        clean = ''.join(c for c in clean if c.isalnum() or c == '_')\n        return clean\n\n    def merge_csvs(self, file_paths: List[str],\n                   on_column: Optional[str] = None) -> pd.DataFrame:\n        \"\"\"Merge multiple CSV files.\"\"\"\n        dfs = []\n        for path in file_paths:\n            df = self.read_csv(path)\n            df['_source_file'] = Path(path).name\n            dfs.append(df)\n\n        if not dfs:\n            return pd.DataFrame()\n\n        if on_column and on_column in dfs[0].columns:\n            result = dfs[0]\n            for df in dfs[1:]:\n                result = pd.merge(result, df, on=on_column, how='outer')\n            return result\n\n        return pd.concat(dfs, ignore_index=True)\n\n    def split_csv(self, df: pd.DataFrame,\n                  group_column: str,\n                  output_dir: str) -> List[str]:\n        \"\"\"Split CSV by column values.\"\"\"\n        output_path = Path(output_dir)\n        output_path.mkdir(parents=True, exist_ok=True)\n\n        files = []\n        for value in df[group_column].unique():\n            subset = df[df[group_column] == value]\n            filename = f\"{group_column}_{value}.csv\"\n            filepath = output_path / filename\n            subset.to_csv(filepath, index=False)\n            files.append(str(filepath))\n\n        return files\n\n    def convert_types(self, df: pd.DataFrame,\n                      type_map: Dict[str, str] = None) -> pd.DataFrame:\n        \"\"\"Convert column types intelligently.\"\"\"\n        df = df.copy()\n\n        if type_map:\n            for col, dtype in type_map.items():\n                if col in df.columns:\n                    try:\n                        df[col] = df[col].astype(dtype)\n                    except:\n                        pass\n        else:\n            # Auto-convert\n            for col in df.columns:\n                # Try numeric\n                try:\n                    df[col] = pd.to_numeric(df[col])\n                    continue\n                except:\n                    pass\n\n                # Try datetime\n                try:\n                    df[col] = pd.to_datetime(df[col])\n                except:\n                    pass\n\n        return df\n\n    def export_csv(self, df: pd.DataFrame,\n                   file_path: str,\n                   encoding: str = 'utf-8-sig',\n                   delimiter: str = ',') -> str:\n        \"\"\"Export DataFrame to CSV.\"\"\"\n        df.to_csv(file_path, encoding=encoding, sep=delimiter, index=False)\n        return file_path\n\n\n# Specialized handlers\nclass ScheduleCSVHandler(ConstructionCSVHandler):\n    \"\"\"Handler for project schedule CSVs.\"\"\"\n\n    SCHEDULE_COLUMNS = ['task_id', 'task_name', 'start_date', 'end_date',\n                        'duration', 'predecessors', 'resources']\n\n    def parse_schedule(self, file_path: str) -> pd.DataFrame:\n        \"\"\"Parse schedule CSV.\"\"\"\n        df = self.read_csv(file_path)\n\n        # Convert date columns\n        for col in df.columns:\n            if 'date' in col.lower() or 'start' in col.lower() or 'end' in col.lower():\n                try:\n                    df[col] = pd.to_datetime(df[col])\n                except:\n                    pass\n\n        return df\n\n\nclass CostCSVHandler(ConstructionCSVHandler):\n    \"\"\"Handler for cost/estimate CSVs.\"\"\"\n\n    def parse_costs(self, file_path: str) -> pd.DataFrame:\n        \"\"\"Parse cost CSV.\"\"\"\n        df = self.read_csv(file_path)\n\n        # Find and convert numeric columns\n        for col in df.columns:\n            if any(word in col.lower() for word in ['cost', 'price', 'amount', 'total', 'qty', 'quantity']):\n                df[col] = pd.to_numeric(df[col].replace(r'[\\$,]', '', regex=True), errors='coerce')\n\n        return df\n\nQuick Start\nhandler = ConstructionCSVHandler()\n\n# Profile CSV first\nprofile = handler.profile_csv(\"export.csv\")\nprint(f\"Encoding: {profile.encoding}, Delimiter: '{profile.delimiter}'\")\n\n# Read with auto-detection\ndf = handler.read_csv(\"export.csv\")\nprint(f\"Loaded {len(df)} rows, {len(df.columns)} columns\")\n\nCommon Use Cases\n1. Merge Multiple Exports\nfiles = [\"jan_export.csv\", \"feb_export.csv\", \"mar_export.csv\"]\nmerged = handler.merge_csvs(files)\n\n2. Split by Category\nhandler.split_csv(df, group_column='category', output_dir='./split_files')\n\n3. Schedule Import\nschedule_handler = ScheduleCSVHandler()\nschedule = schedule_handler.parse_schedule(\"p6_export.csv\")\n\nResources\nDDC Book: Chapter 2.1 - Structured Data"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/datadrivenconstruction/csv-handler",
    "publisherUrl": "https://clawhub.ai/datadrivenconstruction/csv-handler",
    "owner": "datadrivenconstruction",
    "version": "2.1.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/csv-handler",
    "downloadUrl": "https://openagent3.xyz/downloads/csv-handler",
    "agentUrl": "https://openagent3.xyz/skills/csv-handler/agent",
    "manifestUrl": "https://openagent3.xyz/skills/csv-handler/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/csv-handler/agent.md"
  }
}