JAZMIN Scout
Pro, free during the preview. JAZMIN Scout is a paid product of SmithSoft Pty Ltd. During the preview all of it
is free to use; when the preview ends it needs a paid licence (SmithSoft will announce the date and terms beforehand). The JAZMIN libraries and web viewer are
free and open source (MIT).
Open JAZMIN (.jzm) files in VS Code. Double-click a .jzm file and Scout shows its name, rows and table at the top,
and its views down the left, grouped as Explore (Document, Data, Query, Shapes), Structure (Tables & Links, Details, Files)
and Maintain (Check, Health, Performance). Prefer them across the top? Set jazminScout.navigation to tabs. In a narrow editor
the side list keeps its icons only. Every colour comes from your VS Code theme, light, dark or high contrast.
The views:
- Data: the rows as a table. Filter them, sort by any column, choose the columns to show, jump to a row, open
a row to see every value in full, and export what you see as CSV, JSON or XML.
- Query: build a query by picking (tables, joins, filters, totals, sorts) with a live preview and the same query as
JavaScript and C#; or write JavaScript queries across the file's tables, with LINQ-style operators (
where, join,
groupBy, orderBy...). Page through the result and export it as CSV, JSON or XML.
- Shapes: the export shapes the file keeps: see each one's JSON or XML output and its JSON Schema, export it, edit
it as a shape file, or remove it.
- Files: the files stored inside it (pictures, PDFs, pages). Open one in VS Code or save it to disk.
- Document: the file's own page, if it has one: the report, statement or dashboard its author built into it,
shown exactly as the JAZMIN web viewer shows it.
- Tables & Links: the file's tables as cards and the links between them as lines. Drag a column onto the column it
refers to, to link them; Scout also suggests links from column names, types and the values the columns hold. Check
a link against the rows, then save the links into the file. The same change shows as JavaScript or C# beside the map.
- Details: its columns, indexes, sort order, size, access and metadata; Change Indexes & Sort Order… changes them.
- Check: one report on the file: is every part of it sound, which JAZMIN versions read it, and what could be laid
out better.
- Health: whether compacting would help, with a coloured dot on the tab, and Compact from there.
- Performance (Pro): the lookups you run on the file, measured: which read much more than they return, and the
index or sort order that would fix it, tried on a copy first.
Scout reads only what it shows, a page of rows at a time, so large files open quickly.
New to Scout? The User Guide walks through every screen, with pictures.
Keys and passwords
- Files with a key or a password: choose Unlock… and enter it. VS Code asks for it in its own input box; it
never enters the page that shows the file.
- Shared files: use your access key (
jza1-…), and for an online key, the unlock token from the file owner's key
service. Viewers don't take a shared file's owner key: the owner can give themselves an access key that reads
everything.
- Remember the key on this computer keeps it in VS Code's secret storage (your system's keychain), so the file
opens without asking next time. JAZMIN Scout: Forget Remembered Keys removes them all.
Edit rows
Edit on the Data tab turns the table into an editor for files of your own (and shared files, with their owner
key, asked for when you save):
- Rows are found by key columns: the document's own, or a column with a sorted index whose values don't repeat;
otherwise you pick one or two, and Scout checks they don't repeat.
- Double-click a cell to change it; a value that isn't of its column's type is refused as you type it. Changed
cells are marked, with the old value in a tooltip. × deletes a row (struck through until saved), Add row
adds one, and Undo (Ctrl+Z) steps back.
- Review changes… lists them; Save writes them all in one rewrite. Rows someone else changed since you opened
the file are shown as conflicts and nothing is saved, unless you choose Save anyway. The file as it was is kept
as
<name>.bak.jzm (setting jazminScout.edit.backup).
Append Rows From… (on a .jzm in the Explorer) adds the rows of a CSV, JSON, XML or Excel file: its columns
matched by name (you pick the rest), a dry run that says how many rows have problems, then Add (appended: fast,
and the file keeps its id) or add, and replace rows with the same key. Scout offers to compact a file appended to
50 times.
Filters
The filter box takes the JSON filter language of the JAZMIN libraries, for example:
{ "country": "ZA", "amount": { "gt": 100 } }
{ "name": { "icontains": "smith" }, "joined": { "gte": "2024-01-01T00:00:00Z" } }
Filters use the file's indexes and statistics, so they read only the parts of the file that can match.
Before a read, Scout says what it will cost. As you type a filter, a line under it says whether it is quick (Quick: it reads 4,096 of 25,000,000 rows.) or not (No index answers this filter: it reads all 25,000,000 of 25,000,000 rows, about 5 s.), worked out from the file's chunk statistics and indexes without reading a row. A filter, or a sort by a
column the file isn't sorted by, that would take at least jazminScout.confirmSlowReads seconds (5 by default; 0 never
asks) asks first, with Run it and Cancel, and says what would make it quick: an index on the column, or sorting
the file by it. The time comes from reading speeds measured on this computer's first counts of the file (5,000,000
rows a second to start with; sorting by a column builds every match, about 1,000,000 a second). With JAZMIN 1.7 the rows
are exact; with earlier versions they are estimated from the share of chunks the statistics leave.
Rows and counts are read on the file's own worker thread, so a long read never holds up VS Code. The rows show as soon
as the page is read; the count of matches follows. While either is read, a spinner turns beside the row count, and
after a moment a bar shows how far it has got, with Stop: Counting matches… 57% · 2,881,022 found · 2.9 s, about 2.1 s left (with JAZMIN 1.7; with earlier versions, the time so far). Stopping a count keeps the rows, with the matches
found so far: Rows 1–100 of at least 2,965,107 matching the filter. Then the count says how long it all took, such as
Rows 1–100 of 4,911,125 matching the filter · 5.3 s (25,000,000 rows, no index on the column). Sorting by a column
the file isn't sorted by reads every match, with the same bar and Stop.
Exports
Export in the data toolbar saves the rows shown, with the filter, the columns and the order of the table, as CSV,
JSON or XML: the JAZMIN library's own formats, the same as toCSV / toJSON / toXML. In file order, the rows are
written as they are read, so a file of any size exports in little memory; sorted by another column, up to 1,000,000
rows are read and sorted first. A long export runs beside VS Code and can be cancelled from its notice.
Queries
The Query tab runs JavaScript over the file's tables. Each table is a query, named after it (or tables["name"]
when its name isn't a JavaScript name; table is the one chosen above), refined with LINQ-style operators. The value
of the last line is the result:
orders
.where({ status: 'paid', total: { gt: 100 } }) // a filter object: the file's indexes and statistics answer it
.join(customers, o => o.customerId, c => c.id,
(o, c) => ({ id: o.id, customer: c.name, total: o.total }))
.where(x => x.customer.startsWith('A')) // a lambda: checked in memory, row by row
.orderByDescending(x => x.total)
.take(50)
- Operators:
where, select, selectMany, join (inner, by a hash of the second table), groupJoin,
groupBy (each group has a key and the query operators: g.count(), g.sum(x => x.total)), orderBy,
orderByDescending, thenBy, thenByDescending, skip, take, skipWhile, takeWhile, distinct, concat.
Results: count, sum, average, min, max, first, firstOrDefault, single, last, any, all,
toArray, toDictionary. A member name works where a lambda does: orderBy('total').
- What the file does for you: a table's leading
where({ ... }) (the filter language above), select([columns]),
skip and take go to the reader, which reads only the chunks and columns they need, and count() straight after
them counts from indexes and statistics. Everything else runs in memory on the rows read.
- Values are the library's: dates as
Date, decimals as exact text (they sort by value; sum and average add
them as numbers), large integers as BigInt. In a filter object, write a date as new Date('2025-02-01') or as
ISO text: orders.where({ placed: { gte: new Date('2025-02-01') } }).
- Runs beside VS Code: a query that takes longer than
jazminScout.queryTimeout seconds stops; Stop stops it
sooner. Results keep up to 1,000,000 items.
- The query is your own code, run on your computer with the key the file was opened with; nothing is sent anywhere.
Build a query by picking
Build (top of the Query view) makes a query without writing code. Its steps run top to bottom, like a recipe:
- Data: the table to read.
- Join: other tables, by their links: the ones the file declares (★) first, then those Scout finds from column
names and values (with their match). Matching only keeps rows with a match; Keep every row keeps the rest
too, with empty columns.
- Filter: conditions such as status is paid or placed between two dates; All of or Any of them.
- Columns: the columns to show, in order (drag to move, or Alt+← and Alt+→), each with a new name if you like.
- Totals: Count, Count distinct, Sum, Average, Minimum or Maximum, by the columns you group by.
- Filter totals: conditions on the totals (spent > 1000).
- Sort and 8. Limit (skip, then take).
The file's columns are chips above the steps: drag one onto a step, or click it to show, filter, group, total or
sort by it. Each change runs the query again for a preview of its first rows (setting
jazminScout.builder.previewRows). Each step shows how many rows it kept and how: ● index when an index found
them, ▲ scan when every chunk was read.
Beside the steps, the same query is written as code: JavaScript (the JAZMIN library's from()), the Query
tab's, and C# in method and query syntax. Each gives the same rows as the preview. Decimal totals are exact,
added as whole numbers of their smallest unit; JavaScript numbers would round them, so the JavaScript forms carry
two small helper functions when a query needs them. Copy or Open the code, or Use in Code View to keep
working on it as code.
Joins hold the joined tables' rows in memory by key while the first table's rows stream past: at most 1,000,000
joined rows, and 1,000,000 groups. Filter the joined table first when it is larger.
Documents
A file's document runs in a sandbox: it has no network access (except the sites its author allowed), cannot see the
key, and gets the data from Scout a page at a time. Its downloads are saved through VS Code.
Export ▾ on the Document tab saves the page shown:
- PDF… and Image (PNG)…: the JAZMIN library renders the page, as
renderPdf and renderImage do, in Google
Chrome or Microsoft Edge on your computer (hidden, and only while exporting). The page sees jazmin.mode === 'print', so it can show every row and hide its buttons. A page that calls jazmin.ready() is rendered once it
says it is ready; another once it has loaded.
- HTML with the viewer…: the JAZMIN viewer with the
.jzm inside, still encrypted. It opens in a browser, also
offline, and asks for the key. No browser is needed to make it.
VS Code itself cannot print, so a page's own Print button offers the PDF instead, and its Save as PDF
(jazmin.savePdf()) comes to Scout, which renders it with the page settings the page asked for.
- What each file allows: a file's writer can say what viewers may do with it (JAZMIN 1.4 file
actions). Scout
offers PDF and image exports only for pages whose files allow them, and Open and Save as only for files that allow
them. Scout checks the file's own settings before it renders: a page can't widen them.
- Which browser:
jazminScout.browser: auto (Chrome, else Edge), chrome, msedge, or the path of another
Chromium-based browser (Brave, Chromium...).
- Page size and orientation:
jazminScout.pdfPageSize and jazminScout.pdfLandscape, for documents and pages
that set none. The document's page settings come first, then its page's file's, then what the page asks for.
Documents that change their data
A document can let people change the rows it shows, when its author allows it (JAZMIN 1.4 package.edit: the
columns that may change, whether rows may be added or deleted). When the document saves its changes
(jazmin.saveChanges), Scout checks them with the JAZMIN library, lists them, and asks:
- A file of your own (not shared): the changes are written into it, and the file is shown again as it is now.
- A shared file: the changes are saved as a change file for the file's owner, sealed with your submission
key. Send it to them: only the owner can open it.
JAZMIN Scout: Apply Change File… (or right-click a .jzm) is the owner's side. It writes a change file into
the file, after showing what it will do:
- what changes, what's added and what's deleted;
- what's held: rows that changed since the sender saw them, with what they saw, what they want and what the file
has now;
- what's refused: changes the document or the sender's access doesn't allow.
Held changes are written only if you choose Apply, Overwriting Held Changes. A shared file needs its owner key,
asked for each time.
Templates
A template is a folder with a file's document (its pages, styles, scripts and images) and a template.json. You write
it in VS Code, see it with a sample file's data while you work, and build it into .jzm files.
- JAZMIN Scout: New Template… (or right-click a folder) makes a starter that works and prints well. It has a
title, summary cards, a chart whose bars show their rows when clicked, and the rows a page at a time (all of them
on paper). It comes with
jazmin.d.ts, so window.jazmin has IntelliSense.
- JAZMIN Scout: Preview Template (or the preview button on
template.json) shows the folder as the document,
with the data of its sample file. It shows it again whenever you save a file of it.
- JAZMIN Scout: Build Template Into File… writes the folder's files and
template.json's settings into a .jzm.
It first shows what it adds and replaces. The file's other embedded files stay unless you choose some to remove.
A shared file needs its owner key, asked for each time and never remembered.
{
"entry": "index.html",
"title": "Statement",
"allowedOrigins": [],
"pdf": { "format": "A4", "margin": { "top": "15mm", "bottom": "15mm" } },
"sample": "../data/statement.jzm",
"actions": { "data.csv": { "open": false, "save": false } }
}
entry, title, allowedOrigins, allowWasm and pdf become the document's settings; actions says what viewers
may do with each file; sample is the file whose data the preview shows. template.json, jazmin.d.ts,
jsconfig.json and hidden files are not stored in the .jzm.
Export shapes
An export shape turns a table's rows into the nested JSON or XML you need: one entry per client with its transactions
and totals, a chart's labels and values, rows of another table linked to each row. A file can keep shapes under names.
- The Shapes tab lists the shapes the file keeps that your key can use (the default first). JSON, XML and
Schema show a shape's output (its start, for a large one) and the JSON Schema of its JSON; Use the Data tab's
filter runs it on the filter's rows; Export… saves the whole output; Edit… saves it as a shape file to
change; Remove… takes it out of the file.
- Shape files (
*.jzshape.json) are where shapes are written. VS Code checks them and completes them as you type,
from the shape language's JSON Schema ($rows, $groupBy, $sort, $sum, $from links... with snippets), and
Scout suggests the columns of the file the shape is for.
- New Shape… (on the Shapes tab, or on a
.jzm in the Explorer) makes a shape file for a file, starting with its
first columns, and opens its preview.
- Preview Shape (the button above a shape file) shows the shape's output beside it, for a
.jzm you choose once,
and runs it again as you type, saved or not: JSON, XML or the JSON Schema. A mistake is shown there, and marked at
its place in the shape file (a column that doesn't exist, or that the key can't see, is underlined).
- Save Shape Into File… keeps the shape in the
.jzm, under a name, with a description, as the default or not,
for a table, and in a shared file for the keys of some groups. A shared file needs its owner key, asked for each
time, and is refused if a key that would see the shape can't see a column it uses.
Manage Access
A shared file (one with access keys) says who may open it and what each person sees. JAZMIN Scout: Manage
Access… (the Command Palette, a .jzm in the Explorer, or Manage access… on the Details tab of a shared file)
shows it, and changes it, with the file's owner key. VS Code asks for the owner key in its own input box; Scout
keeps it only while the access panel is open, and the panel's page never sees it.
- Who can open the file: each person's name, the rows (for example the branches) and the column groups they see,
their extra file groups, when their access ends (expired keys are shown), and whether their key works offline or
online (opening also needs an unlock token from your key service).
- See: what one person's key shows: how many rows, which columns, stored files and saved shapes.
- Add a person…: choose their rows, columns, file groups, end date and mode. Scout makes their new access key and
shows it once, with Copy and Save to a file…: send it to them securely. Scout doesn't keep it.
- Change…: what someone sees. Anything you don't change stays as it was: name, rows, columns, file groups, end
date and mode.
- Remove: their key no longer opens the file (after you confirm).
- Token: an online key's unlock token, for your key service.
- Remove expired keys, and New owner key…: every key changes, yours and each person's (each new access key sees
what the old one saw). The new keys are saved first to a file you choose.
Every change writes the file again with fresh secrets (so a removed key can't read even the old data), and also leaves
out expired keys. Scout editors showing the file read it again.
Check File
JAZMIN Scout: Check File (in the Command Palette, on a .jzm in the Explorer, or the ✓ button above a file shown
in Scout), or Check the file on the Check tab, checks the file with the key it was opened with:
- Integrity: every row of every table is read and decoded (each part decrypted and its authentication tag checked),
and every stored file is read. Each index is compared with the rows: looking values up by the index finds exactly
the rows that hold them, and each sorted index read from its smallest value finds every row with a value. The chunk
statistics, which let filters skip chunks, count each column's values as the rows do. A shared file's owner
signature is checked as it opens.
- Compatibility: the format version, the reader features the file needs and so the JAZMIN versions that read it,
and what older versions leave out when they append to, update or compact it (saved shapes before 1.5, document
settings before 1.4).
- Layout: the size per row, the chunks, how many chunks one value of each indexed column lies in, and the
library's suggestions (a
sortedBy or chunk size that would make lookups read less).
- Saved shapes and the document: each saved shape checked against the columns this key sees; the entry page and
page settings.
- Sharing: for the owner, the access keys, expired ones and online ones; for an access key, its expiry.
Errors and warnings also go to the Problems panel. Copy report and Save report… give it as Markdown. The
check runs beside VS Code and Stop stops it; a large file takes about as long as reading every row.
Tables and links
Tables & Links shows how a file's tables refer to each other: orders to customers, order lines to orders and
products. Each table is a card, with its rows, its columns and their types, and marks: key for the column the table
is sorted by when its values are all different, order for the other sort columns, idx and text for indexes.
- Link two tables: drag a column onto the column it refers to in another table (
orders.customer_id onto
customers.id). The two must have the same type; Scout says so while you drag. Dragging the other way round makes
the same link. List shows the same as a table, with menus to add a link without dragging.
- Suggested links are dashed, with how many sampled values were found (
customer? 100%). Scout finds them from
names (customer_id, customerId, sku to sku), equal types, and values: up to 1,000 values of the column, from
its first 50,000 rows, looked up in the other table's key. Confirm or Not a link (remembered on this
computer, for this file).
- Check Links reads the link columns of every row: rows whose link finds nothing, rows with no value, and target
values that repeat. Show the rows that find nothing opens them on the Data tab.
- Save into File… keeps the links in the file, with a backup (
<name>.bak.jzm, setting jazminScout.edit.backup);
a shared file asks for its owner key. Only names, tables and columns are kept, never values, so every key can read
them, and the JAZMIN libraries and other tools use them too (the file's jazmin.links).
- Code shows what Save does as JavaScript or C#, kept up to date as you change the links: Copy, or Open it
in an editor tab.
Change the tables themselves. Click a table's name on the map:
- Rename it in the panel; Remove table (its links go with it); + Add Table… makes a new one from a CSV,
JSON, XML or Excel file, with each column's type suggested from its first rows: untick a column to leave it out.
- Sort order: drag a column from the card onto the table's sort order, drag the chips to change their order, × to
take one out (or + Sort by…).
- Indexes: click sorted or text beside a column to switch its index on or off. The column the rows are
sorted by first shows order: the order finds its values, with no index.
- Change a value everywhere: pick a column (the ones links point at come first), the value now and the new one,
and Find… counts the rows it changes in the table and in every table whose link points at the column (a new
value the column already has is refused: two rows would share it). Change everywhere adds it to the save, where
it changes them all in the same rewrite; rows whose sort column changes move to their place. One change of values
per table per save.
Changes wait on the map (a new table dashed, a removed one faded) until Save into File…, which lists them all and
writes them in one rewrite, with a backup; a new table's rows are read from its file as it is written, a few at a time.
The code beside the map is that one update() call, in JavaScript or C#.
The shop sample (samples/5-shop.jzm, 4 tables, 89,764 rows; npm run samples) declares two of its three links, so the
map opens with saved links and one to confirm. Reading its tables and finding links took 33 to 35 ms and 6 to 7 MB the
first time in a process (five runs; Node 24, i7-12700H), and 16 to 17 ms after that.
Indexes and sort order
Change Indexes & Sort Order… on the Details tab (or Change indexes and sort order… under the Check tab's layout
suggestions) opens an editor:
- Sorted and Text search boxes for each column. A sorted index finds values, lists of values and ranges; a
text-search index finds text a value contains. Boxes a column can't have are greyed out, with the reason. The column
the rows are sorted by first needs no sorted index, because the order already finds its values.
- Sort the rows by up to three columns, or no order.
- Apply… lists the changes and asks first. The file is written again in full and replaces the old one in one step;
the file as it was is kept as
<name>.bak.jzm (setting jazminScout.edit.backup). Afterwards Scout checks the file
has exactly what was asked. A column the rows stop being sorted by gets a sorted index, so lookups on it stay fast.
- A shared file needs its owner key, asked for when you apply.
- Before it runs, the question says roughly how long it may take for a large file (
It may take about 5 min 57 s for 25,000,000 rows.), from speeds measured on 1,000,000 and 25,000,000 rows.
- While it runs, VS Code's notification shows the step, how far it has got and the time left, such as
Writing the rows… 26% · 8 s, about 7 s left, with Cancel, which stops it and leaves the file as it was (JAZMIN 1.7). With
earlier versions it shows only that it is working: they can't stop a rewrite part-way without leaving a temporary
file, so there is no Cancel.
- Scout tries the change on a tiny file of its own first, so a JAZMIN library older than 1.6, which would ignore it,
never rewrites your file for nothing; the editor then says so.
File health
The Health tab says whether a file would gain from compacting. A dot on the tab shows it as soon as the file
opens: green when it's in good shape, amber when it could be smaller, red when compacting is worth it.
Appends are quick because they only add to the end of a file, but over time:
- the headers they replace stay in the file;
- deleted and replaced rows stay stored;
- each one adds an index segment, and lookups read every segment;
- each one adds small chunks.
The tab lists what it found, in words ("1,000 deleted rows are still stored: 33% of the rows"), with the file's
facts: size, rows, deleted rows, appends since the last full write, chunks and index segments.
- Compact writes the file again without the waste, and the old file is replaced in one step. Compact &
Regroup also writes each partition's rows of a shared file together, when its sort order allows that. Compacting
a file opened with an access key asks for the owner key. While it runs, the notification shows how far it has got
and the time left, with Cancel (JAZMIN 1.7), as for indexes and sort order.
- Measure Saving compacts a copy in the temp folder and reports the exact saving. The file itself is not changed.
- The tab also shows a bar of the bytes in use, the deleted rows and the bytes no longer used, measured exactly by
the library (JAZMIN 1.6 and later), so Measure Saving is needed less.
The dot uses only what the file reports straight away, so opening a file stays quick. The tab measures fully when you
open it.
Try it on samples/8-needs-compacting.jzm (npm run samples): 50,000 customers after 60 appends, with 12,000 deleted
rows still stored and 61 index segments. Compact puts it right (on a copy, if you want to keep the sample).
The Performance view (marked Pro) measures the lookups you run on a file and says which read much more than
they return, and what would fix it.
- The lookups: each filter you run in the Data view is kept for that file (in this workspace only, never in the
file), with how often you ran it; the newest 50 are kept. Pin a lookup adds one by hand, for a table and a filter
such as
{ "customer": "C0042" }. Pinned lookups are always kept and measured.
- Measure runs each lookup with the library's
explain() and shows the rows it returned, the bytes and chunks it
read and the time it took, with a verdict: reads much more than it returns, its rows are spread through the file,
returns much of the table (reading most of the file is right then) or reads about what it returns.
- Suggestions, each with its reason in words, most bytes saved first:
- a sorted index for a value, list or range no index finds;
- a text-search index for
contains, icontains and startsWith lookups that read every row;
- a sort order when an index finds the rows but they lie spread through many chunks.
- Try on a Copy applies the ticked suggestions to a copy in the temp folder and measures the same lookups again,
side by side; the file is not changed. Apply… writes them into the file in one rewrite, after a summary, with a
backup (the owner key for shared files).
- The same change shows as JavaScript or C# (
update() with indexes and sortedBy), with Copy and Open.
For example, on samples/4-million-orders.jzm (npm run samples): product contains 'Kettle' reads all 245 chunks,
and gets a text-search index; customer = 'C04092' finds 26 rows in 25 of the 245 chunks, and gets a sort order by
customer.
Starter packs
JAZMIN Scout: New File From Starter Pack… builds a realistic sample for an industry: a fictional South African
company's files, with tables, indexes, a document page, saved shapes, links, help, and people who each open their own
file with a demo key. Pick a pack, a folder and a size (Small, Demo, or 200,000 rows for timings at scale); Scout copies
the pack into the folder and builds into its out/ folder, on a worker with progress and Stop, then checks every file.
- Demo keys, easy to find: the main file opens with the owner key, and a file made for one person with that
person's key, so you see what they see. A file made for several people (the managers' file) shows Use a demo
key… on its locked screen: pick a role, and Scout fills in its key (and an online key's unlock token).
out/DEMO-KEYS.md lists every role's key, and Copy a Demo Key… copies one. These are made-up keys for the
sample only; make real ones with Manage Access, whose keys never go in a file.
- Sample data, clearly fake: the same seed gives the same rows every time; South African names, ID numbers with
valid check digits (in restricted column groups),
+27 00 phone numbers no one can dial, .example emails, and
product codes in GS1's restricted range. Each file says synthetic: true in its metadata.
- Change a pack: the copied folder is yours. Edit
jazmin-pack.json (VS Code completes and checks it) and run
Build Pack on it. A pack's script is code, so it runs only in a trusted workspace.
Packs included:
- Wholesale: Partner Packs (Karoo Crossing Wholesale, 1,850 outlets): a master with a finance dashboard for the
financial director, credit controller and auditor; a file for each customer (price book, order pad, statement with
queries, how to pay); a sell-out pack for each brand owner; a promotion claim to review; a blind stocktake for
counters and their supervisor; and a product recall each affected customer confirms. Orders, claims, counts and
recall answers come back as change files. Demo size: 1.2 million order lines, built and checked in about 13 seconds.
- Payroll: Pay Packs (Sable Line Logistics, 1,168 staff): a file for each audience of a payroll. Employees see
their own payslips, leave and tax certificates and ask for leave. Depot managers decide leave and see hours but no
pay. HR and finance get the run, its exceptions and the bank file after two approvals. The employment equity
manager gets pay by category without names, the auditor gets ghost-employee checks over hashes, and a lender and a
leaver get one file each. Demo size: 1,240 employees and 73,000 payslip lines, built and checked in about 7 seconds.
Make a file from your data
JAZMIN Scout: New JAZMIN File… (or Convert to JAZMIN… on CSV, JSON, XML or Excel files in the Explorer) opens
a panel where you:
- Add your files. Each file becomes a table, and so does each sheet of a workbook (hidden sheets aren't added).
For a workbook, choose the sheet and the row with the column names; for CSV, the encoding and separator (found for
you).
- Check the columns. Scout suggests a name and a type for each, from the first 10,000 rows, and says when to look
twice: codes with leading zeros ("keep it as text, or the zeros are lost"), numbers with a decimal comma, dates that
could be day or month first. Leave columns out, mark them required, add an index, choose the sort order, and see
the first rows.
- Choose the file's protection (none, a password, a key, or shared: a partition column per table, and a group
per column for columns only some people may see), what to do with a value that isn't of its column's type, and
where to write it. "Rows per chunk" suits a table to lookups by key (256) or to being read whole (16,384).
Nested columns (files then need JAZMIN 1.4 or later): give columns the same name in the Object column to
make one object of them (address from "Address street" and "Address city"), or set a table's Rows go into to put
its rows into another table as a list (order lines into orders), matched by a column of each. Both files must be
sorted by those columns; Scout says so when they aren't.
Advice on the design appears under each table as you change it, each with Dismiss: a sorted index for a
column that looks like an id, a trigram index for text you'll search, an index that isn't needed (the sort column's
is left out), sorting a shared table by its partition first, that only the owner's searches use indexes in a shared
file, a column group for personal data (id numbers, bank details, salaries, contact details), column names that sound
secret, and decimal rather than float for money. The panel says which JAZMIN versions read the file.
4. Write the file. It is written as a Build would be (below), opens in Scout, and the panel shows the control
totals. "Save these choices as a Build" (on by default) keeps a .jzbuild.json beside the file, so next month's
file is Run Build.
Open in Schema Designer (on a .jzbuild.json, or the ▦ button above one) opens a saved Build in the same panel,
with its sources read again: change the design and Save the Build, or write the file. Columns the sources gained
come in unticked; columns the Build reads but the sources lost are listed.
Builds
A Build (*.jzbuild.json) is a recipe for a .jzm: the files it reads (CSV, JSON or JSON Lines, XML as the
JAZMIN library writes it, or Excel .xlsx), the tables it makes, and how the file is protected. Run it again next
month with the new export and you get the same file with the new data. Scout completes and checks a Build as you type,
and JAZMIN Scout: Run Build (the ▷ button above a Build, or on it in the Explorer) writes the file.
{
"version": 1,
"output": "out/price-book.jzm",
"sources": [
{ "name": "products", "path": "price-book.xlsx", "sheet": "Products" },
{ "name": "customers", "path": "customers.csv" }
],
"tables": [
{ "name": "products", "source": "products", "sortedBy": ["code"],
"columns": [
{ "name": "code", "from": "Product code", "type": "string", "nullable": false },
{ "name": "price", "from": "List price", "type": "decimal" }
] },
{ "name": "customers", "source": "customers",
"columns": [{ "name": "account", "from": "Account", "type": "string", "index": "sorted" }] }
],
"protection": { "kind": "key", "secret": "ask" }
}
- Excel: Scout reads
.xlsx itself: values, dates, booleans and the saved results of formulas, one row at a time.
sheet picks the sheet (default: the first that isn't hidden) and headerRow the row with the column names (rows
above it are left out). .xls, .xlsb, OpenDocument and password-protected workbooks are refused with what to do.
- CSV: UTF-8, UTF-16 (with its byte order mark) or Windows-1252 (
encoding); the delimiter is found from the first
lines unless delimiter says it.
- Types:
decimal for money (exact; Excel's numbers as Excel shows them, so 0.1 + 0.2 is 0.3), datetime for
dates (ISO, or 05/10/2026 read day first unless the setting jazminScout.newFile.dateOrder says otherwise),
string, int, float, bool, json, binary. from names the source column when it differs.
- Bad values:
"onBadValue": stop (the default) at the first value that isn't of its column's type, naming its
row; null writes it as empty; skip-row leaves its row out. Each is reported.
- Protection:
none, password, key (jzk1-…), or shared (each person's key sees only their rows and
columns: give a table partitionBy and, if needed, columnGroups). Scout asks for the password or key in VS Code's
own input box each run, or keeps it in the system keychain with "secret": "keychain". A Build never holds a key.
A new key is saved to a file you choose before anything is written. A shared file built again keeps everyone's
access key; the first build gives you a key that reads everything.
- Mistakes are marked in the Build at their place, each with what to do.
- Control totals: the rows of each table, rows left out, and the total of each decimal column (in the Output panel,
"JAZMIN Scout Builds"), to check against the source system's own report before the file is used.
The file is written beside VS Code with progress and Stop, as <output>.partial, and renamed when it is
complete, so a stopped or failed run never leaves a half-written file.
Compare two files
JAZMIN Scout: Compare JAZMIN Files (two .jzm files selected together in the Explorer, or chosen one after the
other) shows what changed from the first to the second:
- Settings: tables and columns added, removed or retyped, indexes, sort order, sharing and column groups, metadata,
the document's settings, stored files (by their content), saved shapes, and access keys when both are opened as
owner.
- Rows, per table: added, removed and changed, found by key columns (as Edit finds them, or picked); a changed row
shows each changed column before and after. Values compare by meaning: 12.5 equals 12.50, dates to the millisecond,
JSON by content.
Tables sorted by their key are compared in order, in little memory; others hold the smaller table's keys within
jazminScout.compare.memoryMB. Export saves every difference as CSV, JSON or a .jzm; Swap compares the other
way round.
Submissions inbox
JAZMIN Scout: Open Submissions Inbox… (on a .jzm in the Explorer) lists the change files people sent back from
the file's document, waiting in a folder: inbox beside the file by default (setting jazminScout.inbox.folder), or
one chosen with Folder…. It uses the filing service's layout: <access key id>.<anything>.jzm waiting, filed/
for applied ones and rejected/ with a .txt reason beside each.
Each change file is checked against the file with a dry run and shown, oldest first, with its sender (the grant's
label) and what it does:
- Ready: its changes can be written. Apply Ready (or Apply Selected) writes them one file at a time, in
the order they arrived, and moves each to
filed/.
- Held: rows it changes were changed since the sender's copy. Click it to see each row: what the sender saw, what
they want, and what is there now. Apply, Overwriting… writes their values over it; otherwise it stays held.
- Refused: it changes nothing it may change, it was made for another file, or its key was revoked; the reason is
shown. Duplicate: the same file as one already applied, rejected or waiting.
Reject… moves the selected ones to rejected/ with the reason you give. A shared file's inbox needs its owner key,
asked once and kept only while the panel is open. Statuses are kept in .scout-inbox.json in the folder (no keys), so
nothing is applied twice; when the file changes, the waiting items are checked again.
Try it on samples/9-field-tasks/ (npm run samples): a shared task list, and inbox/ beside it with a change file
from Lerato and one from Johan (the owner key is in samples/KEYS.txt). Both changed task T-102 from the same copy, so
Apply Ready files Lerato's and holds Johan's change to T-102 (his new task is added), for you to decide.
Many Files at Once
JAZMIN Scout: Many Files at Once… (on a .jzm in the Explorer) makes one file per person, branch or customer
from one file: payslips, statements, price books, branch packs.
One file for each value of a column (an employee number, a branch). Scout shows how many files that makes and
which tables have the column; a table without it is left out, or included whole in every file if you tick it.
What each person gets:
- One file each, with only their rows, opened with an access key (the run has one owner key, saved beside
keys.csv, so you can update the files and take answers back later; access can be offline or online and expire on
a date), a key of its own, or a generated password (80 bits, like
K7QM-2HXP-9TWD-4RFA; never made from
their data, such as an ID number);
- or one shared file, with a key for each value that opens only its rows.
Each file carries the source's document, saved shapes and metadata, and the embedded files meant for everyone or
for that value (a file in a group named like the value); a saved shape whose table is left out is left out too.
Where: a folder for the files (named by the setting jazminScout.manyFiles.fileName, default
{partition}.jzm) and, in a separate place, keys.csv: it opens every file. Send each key on a different
channel from its file, then delete keys.csv.
Also, if you like:
- A recipients CSV (
partition,name,email,phone,channel,expires,mode): names on the keys and in keys.csv, and each
person's own expiry and online or offline access. Its mistakes are listed by line; people with no rows are named.
- A PDF of each file's document (when the file has one), made in one browser kept open for the run.
- Key slips:
key-slips.pdf beside keys.csv, one page per person with their file and key, for keys handed over on
paper.
Every file is opened with its own key and checked before it counts: it must show exactly its value's rows, or the
run stops. manifest.json (beside the files, with no secrets) lists each file, its id, its SHA-256 and how it opens;
it is written after every file. Run it again after a stop (or with new settings for the same split) and the files
it finished, if unchanged, are kept with their keys and the same owner key; the rest are made. Stop ends the run
and removes the file being written.
Settings
| Command |
|
| JAZMIN Scout: New Template… |
A template folder with the starter document |
| JAZMIN Scout: Preview Template |
The template with its sample's data, shown again on every save |
| JAZMIN Scout: Build Template Into File… |
The template written into a .jzm |
| JAZMIN Scout: Apply Change File… |
A change file written into the file it's for, after a dry run |
| JAZMIN Scout: Check File |
The Check tab's report on a file |
| JAZMIN Scout: Manage Access… |
Who sees what in a shared file: add, change and revoke keys |
| JAZMIN Scout: New Shape… |
A .jzshape.json export shape for a file |
| JAZMIN Scout: Preview Shape |
A shape's output, as you edit it |
| JAZMIN Scout: Save Shape Into File… |
A shape saved into its .jzm, by name |
| JAZMIN Scout: New JAZMIN File… |
A .jzm from CSV, JSON, XML or Excel files, column by column |
| JAZMIN Scout: Convert to JAZMIN… |
The same, with the files chosen in the Explorer |
| JAZMIN Scout: Run Build |
A Build file's .jzm written from its sources |
| JAZMIN Scout: Append Rows From… |
A CSV, JSON, XML or Excel file's rows added to a .jzm, after a dry run |
| JAZMIN Scout: Compare JAZMIN Files |
Two files' settings and rows: what was added, removed and changed |
| JAZMIN Scout: Open Submissions Inbox… |
Change files sent back for a file: checked, applied in order, held or rejected |
| JAZMIN Scout: Many Files at Once… |
One file (or one key) per person or branch, each checked with its own key |
| JAZMIN Scout: Open in Schema Designer |
A Build in the New File panel, to change and save |
| JAZMIN Scout: Forget Remembered Keys |
Removes every key Scout remembered (Builds' too) |
| Setting |
Default |
|
jazminScout.navigation |
rail |
Where a file's views are listed: rail (down the left side, grouped) or tabs (across the top); applies as a file opens or reloads |
jazminScout.pageSize |
100 |
Rows per page in the data table |
jazminScout.builder.previewRows |
20 |
Rows in the query builder's preview (5 to 100) |
jazminScout.priority |
balanced |
What reading favours: memory, speed or balanced |
jazminScout.queryTimeout |
60 |
Seconds a query may run before it stops |
jazminScout.browser |
auto |
The browser that renders PDFs: auto (Chrome, else Edge), chrome, msedge, or a browser's path |
jazminScout.pdfPageSize |
A4 |
PDF page size: A4, Letter, Legal, A3, A5 |
jazminScout.pdfLandscape |
false |
PDFs in landscape |
jazminScout.compare.memoryMB |
256 |
Memory for comparing tables not both sorted by their key |
jazminScout.inbox.folder |
inbox |
The submissions inbox folder, beside the file unless absolute |
jazminScout.edit.backup |
true |
Keep <name>.bak.jzm from before the Data tab's edits are saved |
jazminScout.manyFiles.fileName |
{partition}.jzm |
Many Files at Once: each file's name ({partition}, {run}) |
jazminScout.newFile.dateOrder |
dmy |
How text dates with slashes are read: dmy, mdy or ymd |
jazminScout.xlsx.maxUncompressedMB |
1024 |
Excel workbooks that unpack to more are refused (zip bombs) |
Requirements
VS Code 1.101 or later, on Windows, macOS or Linux. Exporting a document as PDF needs Google Chrome or Microsoft Edge
(or another Chromium-based browser). Scout reads files with the JAZMIN library on your computer; nothing is uploaded. It does not run in VS Code for the Web.
| |