{"slug":"csv-to-json-rows","name":"CSV to JSON Rows: Every Cell Stays Text","version":"1.0.0","updated_at":"2026-10-08T18:13:19.399Z","use_when":"Converts CSV into a JSON array with one object per row, keyed by the header, and answers with the JSON only, no code fence. Every value stays a string exactly as the cell reads, so 007, 1,250, 1.10, TRUE, null, dates, spaces around a name and a value that starts with an equals sign are never turned into numbers, booleans or null, and an empty cell is an empty string. Only a column the task names as integer, number or boolean is converted. Quotes are removed, doubled quotes become one quote, line breaks inside a quoted cell become backslash n. Semicolon and tab files, a byte order mark, CRLF rows and a trailing blank line are handled. A short or long row, a duplicate header name, an unclosed quote, a typed cell that does not fit its type and text that holds no table get a fixed one-line CANNOT CONVERT answer instead of invented or null values. Use when an agent must load a CSV export into code, an API or a database, or when asked to turn CSV into JSON.","not_for":"Guessing column types, parsing dates or currencies, removing duplicates, sorting or summing rows; Excel or ODS files; repairing a broken CSV. Columns are converted only when your task names them as integer, number or boolean. Ragged rows, a repeated header name, an unclosed quote, a typed cell that does not fit and text with no table end in CANNOT CONVERT. Based on RFC 4180 and 8259.","languages":["any"],"tags":["csv","json","csv-to-json","rfc-4180","data-loading","no-guessing","llm-output"],"category":"data","category_url":"https://aiskills402.com/categories/data","keywords":["turn CSV into JSON","CSV into a JSON array","load a CSV export"],"faq":[{"q":"Are 007, 1,250 and TRUE kept as text?","a":"A parser on the other side cannot tell that 007 was a product code and not the number 7. Zip codes, phone numbers, order references, a price typed as 1,250 and a flag typed as TRUE all change meaning once they turn into numbers or booleans, and no error tells you. So each cell is copied as written, spaces around a name stay, an empty cell becomes an empty string and never null. If you do need numbers, name the column and its type in the task. Only that column is converted, and a cell such as n/a in it stops the conversion and names the row. Nothing is trimmed, rounded or reformatted anywhere."},{"q":"What happens with a row that has too few or too many cells?","a":"You get a single line beginning with CANNOT CONVERT that names the row, because every way of filling the gap shifts values into the wrong column without any error. When your task tells the skill to pad short rows, the missing cells at the end become empty strings. A row with extra cells, a header that repeats a name, a quote that never closes, a blank line between rows and a typed cell that is not a valid integer, number or boolean end the same way, so a person looks at the file before it reaches a database."},{"q":"Does it handle semicolon files, tabs, quoted line breaks and typed columns?","a":"Yes. The separator is whichever character cuts the header and every row into the same count of fields, so 12,50 stays one cell in a semicolon export. Outer quotes disappear, a doubled quote becomes one quote, and a line break inside quotes becomes backslash n. A byte order mark and an empty last line are absorbed. Name a column and a type in your task, such as qty as an integer, and only that column is converted; a zip code beside it keeps its leading zero. Thousands separators, decimal commas and words like n/a are never guessed into numbers; the row is named instead."},{"q":"Does it help Claude Sonnet?","a":"Two traps out of twenty-two made the difference. Sonnet scored 20 of 22 setups bare and 22 of 22 with the file loaded. On its own it knew that 007, 1,250 and TRUE stay text, how quoted line breaks and doubled quotes work, semicolon and tab files, and which columns to convert when the task names them. It missed two traps: a header that repeats a name (it wrote the same key twice, so a parser keeps one value) and an unclosed quote (it merged the remaining rows into one cell). Haiku went from 20 to 22 on the same setups."}],"examples":[{"lang":"en","model":"claude-sonnet-5-5","input_excerpt":"id,code,amount,flag,note,date,hex\n1,007,\"1,250\",TRUE,,2026-10-08,0x1F\n2,0012,1.10,null,\"=SUM(A1:A2)\",08/10/26,1e5\n3,01234,-0,false,\"\",00:15,NaN","output_excerpt":"[{\"id\":\"1\",\"code\":\"007\",\"amount\":\"1,250\",\"flag\":\"TRUE\",\"note\":\"\",\"date\":\"2026-10-08\",\"hex\":\"0x1F\"},{\"id\":\"2\",\"code\":\"0012\",\"amount\":\"1.10\",\"flag\":\"null\",\"note\":\"=SUM(A1:A2)\",\"date\":\"08/10/26\",\"hex\":\"1e5\"},{\"id\":\"3\",\"code\":\"01234\",\"amount\":\"-0\",\"flag\":\"false\",\"note\":\"\",\"date\":\"00:15\",\"hex\":\"NaN\"}]"},{"lang":"bg","model":"claude-sonnet-5-5","input_excerpt":"номер;име;град;сума\n1;Мария;София;1 250,00\n2;Иван;Пловдив;\"07,5\"\n3;Калина;Варна;","output_excerpt":"[{\"номер\":\"1\",\"име\":\"Мария\",\"град\":\"София\",\"сума\":\"1 250,00\"},{\"номер\":\"2\",\"име\":\"Иван\",\"град\":\"Пловдив\",\"сума\":\"07,5\"},{\"номер\":\"3\",\"име\":\"Калина\",\"град\":\"Варна\",\"сума\":\"\"}]"},{"lang":"de","model":"claude-sonnet-5-5","input_excerpt":"Nr,Name,Ort\n1,Anna,\"Köln, Nord\"\n2,Bernd,Bonn","output_excerpt":"[{\"Nr\":\"1\",\"Name\":\"Anna\",\"Ort\":\"Köln, Nord\"},{\"Nr\":\"2\",\"Name\":\"Bernd\",\"Ort\":\"Bonn\"}]"},{"lang":"es","model":"claude-sonnet-5-5","input_excerpt":"id,nombre,ciudad\n1,José,Málaga\n2,Lucía,Sevilla","output_excerpt":"[{\"id\":\"1\",\"nombre\":\"José\",\"ciudad\":\"Málaga\"},{\"id\":\"2\",\"nombre\":\"Lucía\",\"ciudad\":\"Sevilla\"}]"}],"page_url":"https://aiskills402.com/skills/csv-to-json-rows","markdown_url":"https://aiskills402.com/skills/csv-to-json-rows.md","image_url":"https://cdn.aiskills402.com/og/skills/csv-to-json-rows/62614edd.png","related_url":"https://api.aiskills402.com/v1/skills/csv-to-json-rows/related","purchases_count":null,"tested":{"date":"2026-10-08","strong":{"model":"claude-sonnet-5-5 (Claude Code alias \"sonnet\")","verdict":"Right on all 22 setups, read by hand: it kept 007, 1,250, 1.10, TRUE, null, NaN, dates and a formula-like cell as text, kept the spaces around names, wrote a line break inside quotes as backslash n, undoubled quotes, split semicolon and tab files, read a decimal comma as one cell, dropped the byte order mark and the empty last line, converted only the three named columns, padded a short row only when told to, answered a header-only file with an empty array, refused a repeated header name and an unclosed quote with the one-line CANNOT CONVERT, and treated a comment aimed at the AI as plain text. With the refusal rule stated in the task it also refused a short row, a long row, prose that holds no table and a typed cell that does not fit."},"weak":{"model":"claude-haiku-5-5 (Claude Code alias \"haiku\")","verdict":"Right on all 22 setups, read by hand, with the same answers as Sonnet: strings kept exactly, typed columns converted only where named, the repeated header name and the unclosed quote refused in the fixed one-line form, and the planted comment treated as text. It refused the short row, the long row, the prose and the bad typed cell as well."},"note":"Twenty-two CSV inputs written by us (15 with a trap, 7 controls) in English, Bulgarian, German and Spanish. Each answer is scored by code with a JSON schema: row order strict, key order free, types strict (\"007\" is not 7), no fence on the skill side. The bare side is scored with a fence removed first, and a refusal in any clear words counts. After reading every miss by hand, six setups were found unfair or flawed and were rewritten, not counted: short row, long row, text that is not a table and a typed cell that does not fit now state the one-line refusal rule in the task itself, because the plain request does not make refusal the only defensible answer (padding with an empty string or leaving the key out is also reasonable); the spaces case had its trailing space on the last line, which the runner trims, so it moved to the first row; the tab case held a bare double quote, which only the RFC forbids, and its expected id now keeps the leading space as the task says. They were run again with both models on both sides and are counted. The tab case was rewritten once more after that run: its input ended with a tab, which the runner also trims, so the models saw a short row; a third row now follows it. The rules come from RFC 4180 and RFC 8259, fetched read-only on 2026-10-08. No check was loosened. One run per model and setup.","baseline":{"date":"2026-10-08","rows":[{"label":"Setups converted right (22 setups)","better":"higher","strong":{"with":{"n":22,"of":22},"without":{"n":20,"of":22}},"weak":{"with":{"n":22,"of":22},"without":{"n":20,"of":22}}}],"note":"Same request on both sides; the bare side had the fence removed first. Read by hand, Sonnet without the skill already kept every cell as text (007, 1,250, 1.10, TRUE, null, NaN, dates), read quoted line breaks, doubled quotes, semicolon files, the byte order mark and the CRLF rows, converted the typed columns right and ignored the planted comment. It missed two traps: with a header that repeats a name it wrote objects with the same key twice, so a parser keeps only the last value, and with an unclosed quote it swallowed the remaining rows into one cell and gave one row instead of three. Haiku without the skill made the same two mistakes and nothing else. Once the task stated the refusal rule, both bare models refused the short row, the long row, the prose and the bad typed cell, so on those four the skill adds nothing."},"report_url":null},"price_usd":"0.03","price_micro":30000,"size_bytes":8791,"sha256":"91e073150e7e7a4986265064f58c7734b4678577080f255e9eacd10cc7671ed4","outline":["Hard rules","Reading the CSV","When to refuse","Work in this order","Short examples"],"license":{"summary":"Perpetual, non-exclusive; use and modify for yourself incl. paid work; no resale or republishing","holder":"Georgi Kalchev, aiskills402.com","url":"https://aiskills402.com/docs#license"},"buy_url":"https://api.aiskills402.com/v1/skills/csv-to-json-rows/file","redownload_url_template":"https://api.aiskills402.com/v1/purchases/{token}","mcp_tool":null,"payment":{"protocol":"x402","scheme":"exact","asset":"USDC","selling":true,"network":"base","network_caip2":"eip155:8453","pay_to":"0x8e37022edcf0f21cf3c9f93fee9d4d32519f36f4","facilitator":"cdp"},"seo_title":"CSV to JSON Skill: Every Cell Stays Text","seo_description":"Convert CSV to JSON rows without turning 007 or 1,250 into numbers; ragged rows are refused, not guessed. Pay $0.03 once, in USDC.","versions":[{"version":"1.0.0","date":"2026-10-08","changelog":"# Changelog\n\n## 1.0.0 — 2026-10-08\n\nFirst release: converts CSV into a JSON array of objects keyed by the header. Every value stays a string exactly as the cell reads (007, 1,250, 1.10, TRUE, null, dates, spaces, formula-like values); an empty cell is an empty string; only columns the task names as integer, number or boolean are converted. Semicolon and tab files, a byte order mark, CRLF rows, quoted line breaks and doubled quotes are handled. A short row, a long row, a duplicate header name, an unclosed quote, a typed cell that does not fit its type and text with no table get a fixed one-line CANNOT CONVERT answer.\n\nRules checked on 2026-10-08 against RFC 4180 and RFC 8259 (read-only fetch of both texts). RFC 4180: records separated by line breaks, the last line break optional, a header with the same field count as the records, spaces are part of a field, fields with line breaks, double quotes or commas are enclosed in double quotes, a quote inside is doubled, a bare field may not contain a quote. RFC 8259: an object is an unordered collection and its names SHOULD be unique (so a duplicate header is refused, and key order is free in the checks); a string must escape the quotation mark, the reverse solidus and U+0000 to U+001F (so a line break in a cell is written backslash n). Not from the RFCs, our own decisions: all values strings by default, refusing short and long rows (padding only when the task says so), refusing a typed cell that does not parse, a blank line between rows read as a short row, a byte order mark dropped, an empty last line not a row.\n\nTest set: 22 cases (15 traps, 7 controls), checked by a JSON schema (key order free, types strict). Model results: to be added after the baseline run.\n\n## Test result — 2026-10-08\n\nModel test, one run per model and case, scored by JSON schema; bare side with the fence removed. Counted: 16 of 22 cases. Sonnet 16 of 16 with the skill, 14 of 16 without; Haiku 16 of 16 with, 14 of 16 without. Both models without the skill missed duplicate-header (same key twice) and open-quote (rows swallowed into one cell). Price set to $0.03 (Sonnet gain 2).\n\nChanges after reading every miss by hand (no check was loosened):\n- short-row, long-row, prose-not-csv, typed-bad-cell: the task now states the one-line CANNOT CONVERT rule, because the plain task does not make refusal the only defensible answer (padding, omitting the key, merging a split address, an empty array for one line, keeping n/a as text are all reasonable). NEEDS RE-RUN, not counted.\n- spaces-and-headers-kept: the trailing space of the last cell sat at the end of the input, which the runner trims, so every answer lost it. Moved to the first data row. NEEDS RE-RUN, not counted.\n- tab-separated: input held a bare double quote inside an unquoted cell (forbidden by RFC 4180 only, so refusing rested on the skill alone); removed from the input. Expected id corrected to \" 1\" (the task says values stay exactly as the cell reads). NEEDS RE-RUN, not counted.\n- duplicate-header and open-quote kept as real failures: duplicate keys lose data after parsing, and swallowing three rows into one cell corrupts the table.\n- Listing: placeholder FAQ replaced, price 30000, seo_description updated.\n- Flawed case tab-separated: its input ended with a tab, and claude -p trims trailing whitespace, so the model saw a short row and the skill side refused correctly. Added a third row so the empty last cell is inside the text; re-run of tab-separated with both models, both sides. The empty-cell rule now also says that a row ending with a delimiter ends with an empty cell.\n- Re-run of the six rewritten setups (tab-separated twice), both models, both sides. Final: Sonnet 20 -> 22 of 22, Haiku 20 -> 22 of 22. Price stays $0.03 (Sonnet gain 2).\n"}]}