For AI agents: the complete documentation index is available at https://jig.md/llms.txt, the full documentation bundle is available at https://jig.md/llms-full.txt, and this page is available as Markdown at https://jig.md/guide/contact-import.md.
DocumentationGuidePrerelease

#Turn unfamiliar CSV files into contact previews

View Markdown

Your product expects name, email, and organization. Customers bring their own column headings. This example recognizes a known export with code, asks an Agent to interpret unfamiliar headings, and uses code to check and convert rows. The importer calls the same mapping slot in all three configurations.

#Try it

With Jig installed on a supported host, use the contact import source and run from that directory. The default known-format preview uses code and needs no Agent:

jig review --allow-resolution-network
jig run

The CSV parser is an ordinary declared dependency. The resolution flag permits fresh dependency resolution during this review; inspect and approve the result. The reviewed entrypoint supplies the fixture, read attachment and one-minute deadline. Because this Flow writes deliverables, Jig chooses a fresh packet directory in operating-system temporary storage and reports it on stderr. Repeating jig run leaves earlier packets intact. The operating system may clear temporary storage; use jig run --out ./preview-result to choose a retained location. That directory must not already exist; Jig never overwrites an earlier result.

Open files/preview.json inside the reported destination. Ada and Mei have accepted contact records. Grace's invalid email appears in rejected, with CSV record number 3. result.json in that destination contains the execution result. These are synthetic contacts, and no database records are created.

To use the Agent or mixed variants, configure a supported native client through Choose an Agent. Their shared grants/agent.json is selected by bindings/model.ts. Interactive review can offer a confirmed client correction when the selected executable is missing; manual grant edits also require review. Unavailable Agent routes do not block the code preview. Mixed still requires its Agent route even when a particular input takes its code branch.

Now use different headings and a different column order:

jig run binding:code --input '{}' --attach source=fixtures/unfamiliar
jig run binding:agent --input '{}' --attach source=fixtures/unfamiliar --timeout 2m
jig run binding:mixed --input '{}' --attach source=fixtures/unfamiliar --timeout 2m

Code returns needs_mapping. The Agent is asked to interpret Organisation, Courriel, and Nom complet; the intended mapping is {"name":2,"email":1,"organization":0}. Its answer may differ or it may abstain. Mixed recognizes the known format in code and invokes the Agent only for unfamiliar headings. Try binding:mixed with fixtures/known to take the direct code path. Each invocation receives its own temporary packet unless you choose a new destination with --out DIR.

#Follow the work

Mapping shows the headings and proposed column indices. Contacts shows accepted preview records; Rejected rows explains exclusions. Lists show up to twelve records with explicit totals and marked text excerpts; the complete returned output and preview.json retain every record. Select the delivered preview reference to read its content. The mapper and converter also offer domain views when invoked independently. needs_mapping and rejected rows remain distinct from a completed import: no database is changed.

Add --display tui for a terminal workspace or --display web for the same views in a browser. Open the private link printed after execution starts. The completed inspector stays open until you explicitly close it; leaving a live display does not cancel work. Blocking causes remain reachable from every view. Plain output and --json remain available.

#Follow the composition

PackageJob
flows/importRead source/contacts.csv, call mapper, call converter, write a final preview.
flows/map-codeRecognize the exact known headings, in any order.
flows/map-agentAsk one Agent for column indices; send headings only, never rows.
flows/map-mixedRecognize known headings in code; otherwise call the Agent Flow.
flows/convertCheck column indices, select and trim values, report accepted contacts and rejected rows.

Compare bindings/code.ts, agent.ts, and mixed.ts. They select different implementations of mapper while using the same importer and converter. The mixed implementation combines code and an Agent Flow inside one leaf. Each method is self-contained; none imports another Flow's implementation. Review changes to code or Bindings before running them.

The mapping is a proposal of three zero-based column indices. It cannot contain scripts or expressions. The converter requires distinct existing columns for all three fields. Its small email rule checks basic shape, not deliverability. CSV parsing uses csv-parse, including quoted commas and multiline fields.

#Watch an unsuitable proposal stop

This is deliberate fault injection into the converter, not a captured model answer:

jig run flow:flows/convert --input @fixtures/invalid-mapping.json

The supplied email column is 7, but the file has only three columns. The result is needs_mapping, with no accepted contacts. fixtures/ambiguous contains two email columns: the Agent is instructed to abstain, but prompting cannot guarantee that it will. A structurally valid wrong mapping can still pass the code checks. Inspect the mapping and preview before using them.

fixtures/malformed has duplicate headings and fails before calling a mapper:

jig run binding:code --input '{}' --attach source=fixtures/malformed

#Know what the result means

  • done means a preview or mapping decision completed. ready can contain some or even all rejected rows. needs_mapping asks for clarification; it is not successful data import.
  • blocked and limit remain visible without automatic fallback or retries. Execution errors and cancellation propagate. Ctrl-C cancels owned work.
  • Input is one UTF-8 CSV named contacts.csv: at most 64 KiB, 100 data records, 16 columns, 80 characters per heading, and 2048 per cell. Empty or duplicate headings are rejected. Record numbers include the header; quoted newlines do not create new record numbers. Blank lines are skipped.
  • Only headings reach the configured Agent provider; headings themselves may contain sensitive text. The source stays unchanged. Only complete previews are delivered; the example does not save checkpoints.

#Make it your own

Change the destination fields, mapping instructions, and conversion rules for one import task. Keep mapping and row validation separate. Database writes, duplicate handling, and user confirmation belong to a consuming application; this example stops at its reviewable preview.

Run bun test examples/contact-import/test from the repository root after workspace setup. Tests use deterministic Agent substitutes and include a structurally valid semantic mistake to make the limit of validation explicit. The release gate also tests the application against the packed SDK.