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
1. When to create a pack
Section titled “1. When to create a pack”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.
2. The structure
Section titled “2. The structure”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 glossary3. Create the pack manifest
Section titled “3. Create the pack manifest”Create jinflow.yml at the pack root:
pack_id: mypackdisplay_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"4. Extract from your tenant
Section titled “4. Extract from your tenant”The fastest way to create a pack is to extract it from a working tenant AFS:
# Your tenant AFS is at:# Copy the framework files (not tenant-specific data)mkdir -p ~/jinflow-packs/jinflow-pack-mypackcd ~/.jinflow/live/mypack/first_client/afs
# Copy instrument definitionscp -r entities/ contracts/ signals/ theses/ verdicts/ \ smebits/ bitbundles/ reports/ lineage/ glossary/ \ ~/jinflow-packs/jinflow-pack-mypack/
# Copy dbt projectcp -r dbt/ ~/jinflow-packs/jinflow-pack-mypack/
# Copy scriptscp -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/5. Clean tenant-specific content
Section titled “5. Clean tenant-specific content”Edit the pack to remove tenant-specific references:
- SMEbits: remove any with
scope.tenant_idset to a specific tenant (keep cross-tenant ones withtenant_id: "*"ornull) - 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
6. Initialize git
Section titled “6. Initialize git”cd ~/jinflow-packs/jinflow-pack-mypackgit initgit add -Agit commit -m "feat: initial domain pack from first_client"Optionally push to GitHub:
git remote add origin https://github.com/org/jinflow-pack-mypack.gitgit push -u origin main7. Configure jinflow to find the pack
Section titled “7. Configure jinflow to find the pack”jinflow us --pack-root ~/jinflow-packsNow jinflow init --pack mypack will find your pack.
8. Create a second tenant
Section titled “8. Create a second tenant”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:
jinflow make --tenant mypack.second_client --syncjinflow explore --tenant mypack.second_clientThe same signals, theses, and verdicts now run on completely different data. Findings will differ — the framework is the same, the insights are client-specific.
9. Keep pack and tenants in sync
Section titled “9. Keep pack and tenants in sync”When you improve the pack (new signals, updated theses):
# Update all tenants from the packjinflow afs update --all --do-it
# Or one tenant at a timejinflow afs update --tenant mypack.second_client --do-itThree-way sync ensures tenant-specific customizations are preserved. Only pack changes are applied; conflicts are flagged, never silently overwritten.
10. The pack lifecycle
Section titled “10. The pack lifecycle”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 learningThis is the flywheel: every new client makes the framework better, and every improvement flows back to existing clients.
What you learned
Section titled “What you learned”- 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 --packcopies the framework into a new tenantjinflow afs updatesyncs 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
Next steps
Section titled “Next steps”- Domain Packs — detailed documentation of all 4 shipped packs
- Collaboration Guide — git workflows for pack and tenant management
- Tenants Guide — multi-tenant architecture
- Glossary — every term explained