CSV/TSV Import to Infrahub Objects
Overview
Expert guidance for turning user-provided CSV or TSV
inputs — a single file, a folder of files, or any
combination — into Infrahub object YAML that
infrahubctl object load accepts. The skill is the
bridge between "I have a spreadsheet" and "the
objects exist on a reviewable branch."
The skill is strictly a consumer of the live
schema. If a CSV column has no schema home, it
stops, lists the offending columns, and routes the
user to infrahub-managing-schemas to make the
schema decision separately. It never proposes
attribute additions, dropdown choices, or any other
schema edit, and it never writes directly to the
default branch.
Project Context
Existing schema files:
!find . -name "*.yml" -path "*/schemas/*" -o -name "*schema*" -name "*.yml" 2>/dev/null | head -10
Existing object files:
!find . -name "*.yml" -path "*/objects/*" 2>/dev/null | head -10
.infrahub.yml if present:
!find . -maxdepth 2 -name ".infrahub.yml" 2>/dev/null | head -1
Candidate CSV/TSV inputs in the working tree:
!find . -maxdepth 3 \( -name "*.csv" -o -name "*.tsv" \) 2>/dev/null | head -10
If invoked with arguments (e.g.,
/infrahub:importing-data inventory.csv), treat the
first argument as the input file or folder; treat
remaining arguments as additional paths to include.
When to Use
- A user hands you one or more CSV or TSV files and
wants the data in Infrahub.
- The input is denormalized — a single sheet
conflating multiple kinds — and you need to split
it across the right schema nodes with correct
load order.
- The CSV has columns that look like dropdown
labels (e.g.,
Status: Active) and you need to
emit the choice name (e.g., active).
- A parent kind's rows are repeated per child in
the CSV, and the children belong inline as
component children of the parent.
- Interface-shaped names (
eth0..eth47) appear in
sequence and you want range-collapsed emission.
- The user wants every imported value stamped with
a lineage tag.
When NOT to Use
- The input is an LDJSON dump from
infrahubctl export dump. Use infrahubctl import load; it
reads a different format and is the wrong tool
for CSV. The skills disambiguate so you don't
conflate them.
- The user needs schema changes. This skill is
read-only against the schema. Hand off to
infrahub-managing-schemas.
- The user needs to export data from Infrahub to
CSV. Single-kind export already works via
infrahubctl object get -o csv; a future
companion skill will cover multi-kind export.
- The input is JSON, XLSX, Parquet, or any other
non-CSV format. v1 covers CSV + TSV only.
Rule Categories
| Priority |
Category |
Prefix |
Description |
| CRITICAL |
Workflow |
workflow- |
Schema introspection, profile-sample, fail-closed gate, up-front interview, self-check, pre-flight closure, branch-first, validate-error mapping |
| HIGH |
Inputs |
inputs- |
File / folder / list normalization, CSV dialect detection, same-kind merge |
| CRITICAL |
Mapping |
mapping- |
Column → attribute, value coercion, empty/null handling, dropdown label → name, reference HFID detection |
| HIGH |
Decomposition |
decomposition- |
Splitting a denormalized CSV across kinds |
| MEDIUM |
Range |
range- |
Interface-shape detection and collapse |
| LOW |
Lineage |
lineage- |
Optional source/owner stamping at import time |
| LOW |
Outputs |
outputs- |
File-level shape concerns (provenance comment) |
Schema Features This Skill Depends On
The skill emits object YAML that conforms to the
target schema's actual shape. If the schema is
missing a feature the CSV requires, the load fails —
which is why the skill checks these upfront and
escalates rather than silently working around them.
If any of these is missing for the data the user
wants to load, that's a schema migration, not an
import fix. The skill stops and says so.
Workflow
Follow these 14 steps in order. The numbering is
load-bearing — earlier steps gate later ones.
Normalize input to a flat file list. Accept a
single path, a directory (recursive scan for
*.csv / *.tsv), or a list, and resolve to a
flat list before profiling. For each file, detect
the CSV dialect (delimiter, encoding, BOM, line
endings) before reading rows. Read
rules/inputs-file-folder-list.md
and
rules/inputs-csv-dialect.md.
Discover the schema — read-only. Try sources
in priority order and stop at the first one that
returns the kinds the CSV needs:
- MCP server — the same surface
infrahub-analyzing-data uses; sees deployed
state including branch-specific dropdown
choices and HFIDs.
infrahubctl schema export --branch <name> —
CLI export against the configured server when
MCP is not connected.
/api/schema?branch=<name> REST endpoint —
direct HTTP fetch when infrahubctl is
unavailable or pointing at a different server.
- Local
schemas/*.yml in the repo — last
resort; may lag the deployed state, so the
step 11 server validate is required to catch
divergence.
Record which source you used so the user knows
how authoritative the mapping is. Never propose
a schema edit. Read
rules/workflow-introspect-first.md.
Profile each file. Read header + sample
rows (default 20; more if needed for dropdown,
range, or denormalization detection). Note
column data shapes, per-column distinct value
counts, sample values, and sequence patterns.
Read
rules/workflow-profile-sample.md.
Build a mapping draft per file using the
heuristics in reference.md:
Fail-closed gate. If any column has no
schema home, stop. Emit a structured report
listing the unmapped columns and the kinds you
checked, point the user at
infrahub-managing-schemas, and exit. No
partial writes. Read
rules/workflow-fail-closed-on-unmapped-columns.md.
Up-front interview. Batch every remaining
ambiguity into one round of multi-choice
questions before any file is written. Read
rules/workflow-up-front-interview.md.
Confirm and lock the mapping. Echo back the
complete plan (target files, kinds, column
bindings, branch name, lineage opt-in) before
the first file is written.
Emit object YAML to a local working
directory (default ./output_dir/). Each file
conforms to the managing-objects envelope:
apiVersion: infrahub.app/v1, kind: Object,
spec.kind, spec.data. Files are numbered for
load order (NN_<kind-plural>.yml). Each file
carries a leading provenance comment naming the
source CSV(s) + sha256 + emission timestamp.
Cross-reference the format rules in
../infrahub-managing-objects/rules/format-structure.md,
the file naming convention in
../infrahub-managing-objects/rules/organization-load-order.md,
and the comment shape in
rules/outputs-provenance-comment.md.
Self-check against managing-objects. Re-read
the listed managing-objects rules and walk the
emission against each one. Local only — no CLI,
no server, no branch. Fix in place before moving
on. Read
rules/workflow-self-check-against-managing-objects.md.
Pre-flight reference closure. Walk every
relationship reference in the emission and
verify the target resolves either to a row in
an upstream file or to a live object the
introspection captured. Orphan references fail
closed before any branch is touched. Read
rules/workflow-pre-flight-closure.md.
Create the branch. Only after the
self-check and pre-flight closure pass, run
infrahubctl branch create <name> (default
csv-import-YYYYMMDD-HHMM, user-overridable in
the interview). Doing this last keeps
throwaway branches out of the branch list. Read
rules/workflow-branch-before-load.md.
Server validate on the branch:
infrahubctl object validate ./output_dir/ --branch <name>. Catches schema-resolution
errors the local checks can't (kind not in
schema, attribute name miss, reference target
missing). On error, translate the diagnostic
back to the source CSV cell and ask the user
to fix the input — don't hand-edit the emitted
YAML. Read
rules/workflow-validate-error-mapping.md.
Load on the branch: infrahubctl object load ./output_dir/ --branch <name>. Object
load is not transactional across files — if
file 17 of 20 fails, files 1–16 are already on
the branch. The branch-first design means you
discard the branch and re-run with a fresh
branch name; you never clean up partial state
by hand.
Hand off. Tell the user the branch is
ready for review, the validate/load commands
that were run, and how to open a proposed
change in the UI. Don't auto-merge.
Supporting References
- examples.md — 8 worked CSV
patterns: flat list, denormalized split,
parent-with-children, dropdown label normalization,
range collapse, lineage stamping, fail-closed
report, merge + dedup
- reference.md — heuristic
order, file envelope reminder, HFID decision
matrix, file naming convention
- rules/ — individual rules by
category prefix; start at
rules/_sections.md
- ../infrahub-managing-objects/SKILL.md
— the consumer-side rules every emitted file must
conform to (envelope, value mapping, components,
range, load order, branch-first)
- ../infrahub-analyzing-data/SKILL.md
— MCP introspection pattern for live schema
discovery
- ../infrahub-managing-schemas/SKILL.md
— escape hatch when a column has no schema home
- ../infrahub-common/metadata-lineage.md
— value metadata semantics (
source is lineage
only; locking needs owner + is_protected)
- ../infrahub-common/rules/workflow-branch-for-crud.md
— shared branch-first rule that both schema and
object writes inherit from
- ../infrahub-common/rules/connectivity-server-check.md
— verify the server is reachable with
infrahubctl info before any server-dependent command in the
workflow
- ../infrahub-common/rules/connectivity-python-environment.md
— detect the project's Python env prefix
(
uv run / poetry run) for all infrahubctl
invocations
- ../infrahub-common/rules/workflow-information-priority.md
-- Skill content first; how to consult
docs.infrahub.app
on a genuine gap (e.g. deleting nodes)
1---2name: infrahub-importing-data3description: Converts CSV/TSV inputs into Infrahub object YAML and loads them onto a fresh branch. Handles a single file, a folder of files, an explicit list of paths, and one-big-denormalized-sheet exports. TRIGGER when: importing CSV, loading CSV/TSV into Infrahub, ingesting spreadsheet data, converting CSV to Infrahub objects, splitting a denormalized CSV across multiple kinds. DO NOT TRIGGER when: running `infrahubctl import load` against an LDJSON dump (different format and tool), designing or modifying schemas (this skill is read-only against the schema and fails closed on unmapped columns), exporting data from Infrahub (use `infrahubctl object get -o csv` for single-kind export), or ingesting JSON/XLSX (v1 is CSV+TSV only).4---56# CSV/TSV Import to Infrahub Objects78## Overview910Expert guidance for turning user-provided CSV or TSV11inputs — a single file, a folder of files, or any12combination — into Infrahub object YAML that13`infrahubctl object load` accepts. The skill is the14bridge between "I have a spreadsheet" and "the15objects exist on a reviewable branch."1617The skill is **strictly a consumer of the live18schema**. If a CSV column has no schema home, it19stops, lists the offending columns, and routes the20user to `infrahub-managing-schemas` to make the21schema decision separately. It never proposes22attribute additions, dropdown choices, or any other23schema edit, and it never writes directly to the24default branch.2526## Project Context2728Existing schema files:29!`find . -name "*.yml" -path "*/schemas/*" -o -name "*schema*" -name "*.yml" 2>/dev/null | head -10`3031Existing object files:32!`find . -name "*.yml" -path "*/objects/*" 2>/dev/null | head -10`3334`.infrahub.yml` if present:35!`find . -maxdepth 2 -name ".infrahub.yml" 2>/dev/null | head -1`3637Candidate CSV/TSV inputs in the working tree:38!`find . -maxdepth 3 \( -name "*.csv" -o -name "*.tsv" \) 2>/dev/null | head -10`3940If invoked with arguments (e.g.,41`/infrahub:importing-data inventory.csv`), treat the42first argument as the input file or folder; treat43remaining arguments as additional paths to include.4445## When to Use4647- A user hands you one or more CSV or TSV files and48 wants the data in Infrahub.49- The input is denormalized — a single sheet50 conflating multiple kinds — and you need to split51 it across the right schema nodes with correct52 load order.53- The CSV has columns that look like dropdown54 labels (e.g., `Status: Active`) and you need to55 emit the choice **name** (e.g., `active`).56- A parent kind's rows are repeated per child in57 the CSV, and the children belong inline as58 component children of the parent.59- Interface-shaped names (`eth0..eth47`) appear in60 sequence and you want range-collapsed emission.61- The user wants every imported value stamped with62 a lineage tag.6364## When NOT to Use6566- The input is an LDJSON dump from `infrahubctl67 export dump`. Use `infrahubctl import load`; it68 reads a different format and is the wrong tool69 for CSV. The skills disambiguate so you don't70 conflate them.71- The user needs schema changes. This skill is72 read-only against the schema. Hand off to73 `infrahub-managing-schemas`.74- The user needs to export data from Infrahub to75 CSV. Single-kind export already works via76 `infrahubctl object get -o csv`; a future77 companion skill will cover multi-kind export.78- The input is JSON, XLSX, Parquet, or any other79 non-CSV format. v1 covers CSV + TSV only.8081## Rule Categories8283| Priority | Category | Prefix | Description |84| -------- | -------- | ------ | ----------- |85| CRITICAL | Workflow | `workflow-` | Schema introspection, profile-sample, fail-closed gate, up-front interview, self-check, pre-flight closure, branch-first, validate-error mapping |86| HIGH | Inputs | `inputs-` | File / folder / list normalization, CSV dialect detection, same-kind merge |87| CRITICAL | Mapping | `mapping-` | Column → attribute, value coercion, empty/null handling, dropdown label → name, reference HFID detection |88| HIGH | Decomposition | `decomposition-` | Splitting a denormalized CSV across kinds |89| MEDIUM | Range | `range-` | Interface-shape detection and collapse |90| LOW | Lineage | `lineage-` | Optional source/owner stamping at import time |91| LOW | Outputs | `outputs-` | File-level shape concerns (provenance comment) |9293## Schema Features This Skill Depends On9495The skill emits object YAML that conforms to the96target schema's actual shape. If the schema is97missing a feature the CSV requires, the load fails —98which is why the skill checks these upfront and99escalates rather than silently working around them.100101| If the CSV has... | The schema must... | See |102| ----------------- | ------------------ | --- |103| A reference column pointing to another kind | Define `human_friendly_id` on the target node; the HFID length determines scalar vs list reference shape | [../infrahub-managing-schemas/rules/display-human-friendly-id.md](../infrahub-managing-schemas/rules/display-human-friendly-id.md) |104| A label-style value for a Dropdown column (`Active` rather than `active`) | Declare the dropdown `choices` as objects with both `name` and `label`; the emitter writes the `name` and reads `label` from the schema | [../infrahub-managing-schemas/rules/attribute-defaults-and-types.md](../infrahub-managing-schemas/rules/attribute-defaults-and-types.md) |105| Repeated parent rows with per-child columns | Pair Component (parent) and Parent (child) relationships with the same identifier, and `optional: false` on the child side | [../infrahub-managing-schemas/rules/relationship-component-parent.md](../infrahub-managing-schemas/rules/relationship-component-parent.md) |106| A column with no obvious schema home | Be extended via `infrahub-managing-schemas` — this skill fails closed and hands off | [../infrahub-managing-schemas/SKILL.md](../infrahub-managing-schemas/SKILL.md) |107108If any of these is missing for the data the user109wants to load, that's a schema migration, not an110import fix. The skill stops and says so.111112## Workflow113114Follow these 14 steps in order. The numbering is115load-bearing — earlier steps gate later ones.1161171. **Normalize input to a flat file list.** Accept a118 single path, a directory (recursive scan for119 `*.csv` / `*.tsv`), or a list, and resolve to a120 flat list before profiling. For each file, detect121 the CSV dialect (delimiter, encoding, BOM, line122 endings) before reading rows. Read123 [rules/inputs-file-folder-list.md](./rules/inputs-file-folder-list.md)124 and125 [rules/inputs-csv-dialect.md](./rules/inputs-csv-dialect.md).1261272. **Discover the schema — read-only.** Try sources128 in priority order and stop at the first one that129 returns the kinds the CSV needs:130 1. **MCP server** — the same surface131 `infrahub-analyzing-data` uses; sees deployed132 state including branch-specific dropdown133 choices and HFIDs.134 2. **`infrahubctl schema export --branch <name>`** —135 CLI export against the configured server when136 MCP is not connected.137 3. **`/api/schema?branch=<name>` REST endpoint** —138 direct HTTP fetch when `infrahubctl` is139 unavailable or pointing at a different server.140 4. **Local `schemas/*.yml`** in the repo — last141 resort; may lag the deployed state, so the142 step 11 server validate is required to catch143 divergence.144145 Record which source you used so the user knows146 how authoritative the mapping is. **Never propose147 a schema edit.** Read148 [rules/workflow-introspect-first.md](./rules/workflow-introspect-first.md).1491503. **Profile each file.** Read header + sample151 rows (default 20; more if needed for dropdown,152 range, or denormalization detection). Note153 column data shapes, per-column distinct value154 counts, sample values, and sequence patterns.155 Read156 [rules/workflow-profile-sample.md](./rules/workflow-profile-sample.md).1571584. **Build a mapping draft per file** using the159 heuristics in [reference.md](./reference.md):160 - **Column → attribute:** exact name match,161 then snake_case round-trip, then display-label162 fuzzy match, then unit-strip (`(GB)`, `(MHz)`)163 — anything past that defers to the interview.164 Read [rules/mapping-column-to-attribute.md](./rules/mapping-column-to-attribute.md).165 - **Value coercion:** Boolean / Number /166 DateTime / JSON attribute kinds require167 explicit type coercion before emission. Read168 [rules/mapping-value-coercion.md](./rules/mapping-value-coercion.md).169 - **Empty cells:** decide omit vs fail by the170 schema's `optional` and `default_value`171 declarations. Read172 [rules/mapping-empty-and-null.md](./rules/mapping-empty-and-null.md).173 - **Dropdown columns:** build a label→name174 lookup from the schema and translate. Read175 [rules/mapping-dropdown-label-to-name.md](./rules/mapping-dropdown-label-to-name.md).176 - **Reference columns:** detect by name match177 against a relationship plus value shape178 against the target kind's HFID. Read179 [rules/mapping-reference-and-hfid.md](./rules/mapping-reference-and-hfid.md).180 - **Range columns:** collapse contiguous181 interface-style sequences. Read182 [rules/range-detection.md](./rules/range-detection.md).183 - **Denormalized columns:** detect repeated184 parent groups and split the input across185 kinds. Read186 [rules/decomposition-denormalized-csv.md](./rules/decomposition-denormalized-csv.md).187 - **Same kind in multiple inputs:** merge into188 one numbered output file, dedupe by HFID,189 surface conflicts in the interview. Read190 [rules/inputs-merge-same-kind.md](./rules/inputs-merge-same-kind.md).1911925. **Fail-closed gate.** If any column has no193 schema home, **stop.** Emit a structured report194 listing the unmapped columns and the kinds you195 checked, point the user at196 `infrahub-managing-schemas`, and exit. No197 partial writes. Read198 [rules/workflow-fail-closed-on-unmapped-columns.md](./rules/workflow-fail-closed-on-unmapped-columns.md).1992006. **Up-front interview.** Batch every remaining201 ambiguity into one round of multi-choice202 questions before any file is written. Read203 [rules/workflow-up-front-interview.md](./rules/workflow-up-front-interview.md).2042057. **Confirm and lock the mapping.** Echo back the206 complete plan (target files, kinds, column207 bindings, branch name, lineage opt-in) before208 the first file is written.2092108. **Emit object YAML** to a local working211 directory (default `./output_dir/`). Each file212 conforms to the managing-objects envelope:213 `apiVersion: infrahub.app/v1`, `kind: Object`,214 `spec.kind`, `spec.data`. Files are numbered for215 load order (`NN_<kind-plural>.yml`). Each file216 carries a leading provenance comment naming the217 source CSV(s) + sha256 + emission timestamp.218 Cross-reference the format rules in219 [../infrahub-managing-objects/rules/format-structure.md](../infrahub-managing-objects/rules/format-structure.md),220 the file naming convention in221 [../infrahub-managing-objects/rules/organization-load-order.md](../infrahub-managing-objects/rules/organization-load-order.md),222 and the comment shape in223 [rules/outputs-provenance-comment.md](./rules/outputs-provenance-comment.md).2242259. **Self-check against managing-objects.** Re-read226 the listed managing-objects rules and walk the227 emission against each one. Local only — no CLI,228 no server, no branch. Fix in place before moving229 on. Read230 [rules/workflow-self-check-against-managing-objects.md](./rules/workflow-self-check-against-managing-objects.md).23123210. **Pre-flight reference closure.** Walk every233 relationship reference in the emission and234 verify the target resolves either to a row in235 an upstream file or to a live object the236 introspection captured. Orphan references fail237 closed before any branch is touched. Read238 [rules/workflow-pre-flight-closure.md](./rules/workflow-pre-flight-closure.md).23924011. **Create the branch.** Only after the241 self-check and pre-flight closure pass, run242 `infrahubctl branch create <name>` (default243 `csv-import-YYYYMMDD-HHMM`, user-overridable in244 the interview). Doing this last keeps245 throwaway branches out of the branch list. Read246 [rules/workflow-branch-before-load.md](./rules/workflow-branch-before-load.md).24724812. **Server validate** on the branch:249 `infrahubctl object validate ./output_dir/250 --branch <name>`. Catches schema-resolution251 errors the local checks can't (kind not in252 schema, attribute name miss, reference target253 missing). On error, translate the diagnostic254 back to the source CSV cell and ask the user255 to fix the input — don't hand-edit the emitted256 YAML. Read257 [rules/workflow-validate-error-mapping.md](./rules/workflow-validate-error-mapping.md).25825913. **Load** on the branch: `infrahubctl object260 load ./output_dir/ --branch <name>`. **Object261 load is not transactional across files** — if262 file 17 of 20 fails, files 1–16 are already on263 the branch. The branch-first design means you264 discard the branch and re-run with a fresh265 branch name; you never clean up partial state266 by hand.26726814. **Hand off.** Tell the user the branch is269 ready for review, the validate/load commands270 that were run, and how to open a proposed271 change in the UI. Don't auto-merge.272273## Supporting References274275- **[examples.md](./examples.md)** — 8 worked CSV276 patterns: flat list, denormalized split,277 parent-with-children, dropdown label normalization,278 range collapse, lineage stamping, fail-closed279 report, merge + dedup280- **[reference.md](./reference.md)** — heuristic281 order, file envelope reminder, HFID decision282 matrix, file naming convention283- **[rules/](./rules/)** — individual rules by284 category prefix; start at285 [rules/_sections.md](./rules/_sections.md)286- **[../infrahub-managing-objects/SKILL.md](../infrahub-managing-objects/SKILL.md)**287 — the consumer-side rules every emitted file must288 conform to (envelope, value mapping, components,289 range, load order, branch-first)290- **[../infrahub-analyzing-data/SKILL.md](../infrahub-analyzing-data/SKILL.md)**291 — MCP introspection pattern for live schema292 discovery293- **[../infrahub-managing-schemas/SKILL.md](../infrahub-managing-schemas/SKILL.md)**294 — escape hatch when a column has no schema home295- **[../infrahub-common/metadata-lineage.md](../infrahub-common/metadata-lineage.md)**296 — value metadata semantics (`source` is lineage297 only; locking needs `owner` + `is_protected`)298- **[../infrahub-common/rules/workflow-branch-for-crud.md](../infrahub-common/rules/workflow-branch-for-crud.md)**299 — shared branch-first rule that both schema and300 object writes inherit from301- **[../infrahub-common/rules/connectivity-server-check.md](../infrahub-common/rules/connectivity-server-check.md)**302 — verify the server is reachable with `infrahubctl303 info` before any server-dependent command in the304 workflow305- **[../infrahub-common/rules/connectivity-python-environment.md](../infrahub-common/rules/connectivity-python-environment.md)**306 — detect the project's Python env prefix307 (`uv run` / `poetry run`) for all `infrahubctl`308 invocations309- **[../infrahub-common/rules/workflow-information-priority.md](../infrahub-common/rules/workflow-information-priority.md)**310 -- Skill content first; how to consult `docs.infrahub.app`311 on a genuine gap (e.g. deleting nodes)