Skip to content

Tutorial: Publishing a Domain Pack

In this tutorial you will take a working tenant AFS, extract it into a reusable domain pack, and use it to create a second tenant. This is how consulting firms scale their expertise — build once, deploy many.

Time: 20 minutes Prerequisites: A working tenant with signals, theses, and at least one successful build

You’ve been working with one client. Your AFS has:

  • Entity definitions and contracts
  • Source-system dispatch macros
  • 10+ signals, theses, verdicts
  • SMEbits from expert interviews
  • Reports

Now a second client in the same industry asks for the same analysis. Instead of copying files manually, you package your framework as a domain pack.

A domain pack is just a git repository with the right structure:

jinflow-pack-mypack/
jinflow.yml ← pack manifest
entities/ ← entity definitions
contracts/ ← gold, silver, findings, verdict, smebit, bitbundle
signals/ ← signal declarations
theses/ ← thesis declarations
verdicts/ ← verdict declarations
smebits/ ← expert knowledge (pack-level, not tenant-specific)
bitbundles/ ← curated narratives
reports/ ← report declarations
lineage/ ← lineage definitions
dbt/{pack}/ ← dbt project (models, macros, seeds)
models/
bronze/ ← source-system dispatch
silver/ ← validation
gold/ ← consumption contract
macros/
source_system_columns.sql ← column mappings per source system
scripts/ ← extraction, generation scripts
glossary/ ← registry glossary

Create jinflow.yml at the pack root:

pack_id: mypack
display_name: "My Analytics Pack"
brand: "My Pack"
description: "Analytical framework for [your industry]"
source_systems: [system_a, system_b]
branding:
primary_color: "#3b82f6"
tagline: "Every [thing] tells a story"

The fastest way to create a pack is to extract it from a working tenant AFS:

~/.jinflow/live/mypack/first_client/afs/
# Your tenant AFS is at:
# Copy the framework files (not tenant-specific data)
mkdir -p ~/jinflow-packs/jinflow-pack-mypack
cd ~/.jinflow/live/mypack/first_client/afs
# Copy instrument definitions
cp -r entities/ contracts/ signals/ theses/ verdicts/ \
smebits/ bitbundles/ reports/ lineage/ glossary/ \
~/jinflow-packs/jinflow-pack-mypack/
# Copy dbt project
cp -r dbt/ ~/jinflow-packs/jinflow-pack-mypack/
# Copy scripts
cp -r scripts/ ~/jinflow-packs/jinflow-pack-mypack/
# Copy the manifest (edit pack_id and remove tenant-specific fields)
cp jinflow.yml ~/jinflow-packs/jinflow-pack-mypack/

Edit the pack to remove tenant-specific references:

  • SMEbits: remove any with scope.tenant_id set to a specific tenant (keep cross-tenant ones with tenant_id: "*" or null)
  • jinflow.yml: remove tenant, display_name, dlz_root — keep only pack-level fields
  • Scripts: ensure extraction scripts work with any tenant’s data, not just the first client’s
Terminal window
cd ~/jinflow-packs/jinflow-pack-mypack
git init
git add -A
git commit -m "feat: initial domain pack from first_client"

Optionally push to GitHub:

Terminal window
git remote add origin https://github.com/org/jinflow-pack-mypack.git
git push -u origin main
Terminal window
jinflow us --pack-root ~/jinflow-packs

Now jinflow init --pack mypack will find your pack.

Terminal window
jinflow init --pack mypack --tenant second_client --source-system system_a \
--dlzroot ~/jinflow-datalandingzone \
--display-name "Second Client"

This copies the entire pack framework into a new tenant instance. Place the second client’s data in the DLZ and build:

Terminal window
jinflow make --tenant mypack.second_client --sync
jinflow explore --tenant mypack.second_client

The same signals, theses, and verdicts now run on completely different data. Findings will differ — the framework is the same, the insights are client-specific.

When you improve the pack (new signals, updated theses):

Terminal window
# Update all tenants from the pack
jinflow afs update --all --do-it
# Or one tenant at a time
jinflow afs update --tenant mypack.second_client --do-it

Three-way sync ensures tenant-specific customizations are preserved. Only pack changes are applied; conflicts are flagged, never silently overwritten.

Build framework for Client A
Extract into domain pack
Create tenant for Client B from pack
Client B findings reveal new patterns
Add new signals/theses to pack
Sync improvements back to Client A
Both clients benefit from shared learning

This is the flywheel: every new client makes the framework better, and every improvement flows back to existing clients.

  • A domain pack is a git repo with instruments, contracts, dbt models, and macros
  • Extract from a working tenant is the fastest way to create a pack
  • jinflow init --pack copies the framework into a new tenant
  • jinflow afs update syncs pack improvements to tenants (three-way merge)
  • Packs are optional — you can always work without them
  • The value is reuse: build once, deploy many, improve continuously
jazzisnow jinflow is a jazzisnow product
v0.45.1 · built 2026-04-17 08:14 UTC