Spry Assembler is a lightweight system for organizing, transforming, and assembling your source-like files (SQL, Markdown, HTML, shell scripts, or even AI prompts) into consistent, reproducible outputs.
Spry is designed for situations where you don’t already have a full-blown framework. Languages like Java, JavaScript, and TypeScript have large ecosystems with many frameworks (Spring, React, Next.js, etc.). But SQL, shell scripts, and even “non-traditional” sources like AI prompts or Markdown don’t have much opionated structure. Spry Assembler fills that gap.
What Spry Does:
- Discover the files you already have (SQL, Markdown, HTML, AI prompts, scripts).
- Annotate them with simple tags (
@route,@title) to add meaning (liked frontmatter). - Transform them with directives (
#include, snippets, layouts). - Generate more content with helpers called foundries (Python, Bash, TypeScript, etc.).
- Assemble everything into reproducible outputs: — SQLite tables, JSON, HTML, Markdown, or other artifacts.
- Stay in sync and rebuild automatically when files change.
Sources Acquired resources Refinement & transforms Final products
"Discovery" step "Materialization" step
┌──────────────┐ ┌──────────────────┐ 1:N ┌──────────────────────┐ 1:1 ┌───────────────────┐
│ File System ├──────►│ Originators & ├────►│ Annotations (@...) ├────►│ Filesystem │
│ Databases │ │ Foundries │ | Directives (#...) │ │ (spry.d/auto/*) │
│ URLs / APIs │ │ (SQL, JSON, etc.)│ | Transformations │ │ | SQL DDL/DML, ... │
│ AI Prompts │ └──────────▲───────┘ └───────┬──────────────┘ │ HTML, JSON, etc. │
│ Other input │ │ recursive └─────────┬─────────┘
└──────────────┘ │ fan-out │
│ Destinations
└────────────────────────────────────────────────────┘
- Originators & Foundries: pull in files, fetch from DBs/APIs, or run helper scripts to create resources.
- Refinement: annotations add intent, directives insert snippets, middleware transforms or fans out new resources.
- Final products: rendered into SQLite, filesystem outputs, JSON, HTML, or other destinations.
Why Spry is useful:
- Keeps things organized — pages, prompts, or scripts can be cataloged with routes and metadata.
- Removes repetition — reuse layouts, headers, or snippets with a single directive.
- Runs your helpers — any script or program (Python, Bash, Rust, Node.js, etc.) can act as a foundry that generates SQL, JSON, or Markdown.
- Keeps outputs in sync — your source files plus Spry’s rules always produce the same results.
- Supports dev workflow — watch files for changes, rebuild automatically, and keep SQL-accepting tools up-to-date.
- Generates any kind of artifact — HTML, SQL, JSON, Markdown, or even static “sites” and engineering deliverables.
- Scales efficiently — supports partial rebuilds, incremental generation, and advanced strategies like stale-while-revalidate.
Why Spry Matters:
- For SQL & Bash (or any shell scripts): finally a framework-like system for consistency.
- For AI Prompts: treat them like source code — versioned, reproducible, and pipeline-ready.
- For Engineering Teams: structured generation: resources can come from anywhere, be refined in pipelines, and be rendered into any kind of deliverable.
- For Business Analysts: annotations and routes are easy to learn, no heavy frameworks required.
- For Large Sites or Catalogs: supports high-performance builds, partial updates, and scalable information architecture.
- For Teams: deterministic outputs mean the same build runs identically across machines.
Example Use Cases:
- A data analyst wants to keep a catalog of SQL queries and reports with consistent navigation.
- A business team wants AI prompts managed like source code, so outputs are predictable.
- A developer needs to generate thousands of static HTML pages but only re-render the ones that change.
- An engineering group wants to combine SQL queries, Python scripts, and Markdown into one reproducible workflow.
- A company wants branded, type-safe HTML reports, enforced by a design system but generated from arbitrary resource inputs.
Spry Assembler works around four ideas:
-
Annotations (
@...) — describe intent.- Example: give a file a route, title, or role.
- They don’t change your file, just add meaning.
-- @route.path /reports -- @route.title Monthly Reports
-
Directives (
#...or!...) — transform content inline.- Insert layouts, snippets, or boilerplate into your files.
-- #include layout default SELECT 'content here';
-
Foundries — helper programs.
- Write a Python script, Bash file, or TypeScript module that prints SQL, JSON, or Markdown.
- Mark it with an annotation and Spry will run it at the right time.
#!/usr/bin/env python # @spry.nature foundry after-sql-files print("SELECT 'Hello from AI prompt' AS msg;")
Foundries can even generate outputs from AI prompts or other automated sources.
-
Stores — where results go.
- Filesystem:
spry.d/auto/*(auto-generated files you can inspect or commit). - Database: an optional SQLite table that SQL-accepting tools (like SQLPage) can read directly.
- Filesystem:
This repo uses git hooks for maintenance, after cloning the repo in your sandbox please do the following:
deno task initdeno task doctorYou should see something like this:
Git dependencies
🆗 .githooks/pre-commit
🆗 .githooks/pre-push
🆗 .githooks/prepare-commit-msg
Runtime dependencies
🆗 deno 1.34.0 (release, x86_64-unknown-linux-gnu)
Build dependencies
🆗 dot - graphviz version 2.43.0 (0)
🆗 java 17 2021-09-14 LTS
🆗 PlantUML version 1.2022.6 (Tue Jun 21 13:34:49 EDT 2022)Doctor task legend:
- 🚫 is used to indicate a warning or error and should be corrected
- 💡 is used to indicate an (optional) suggestion
- 🆗 is used to indicate success
If you get any error messages for dot, Java, or PlantUML then you will not
get auto-generated entity relationship diagrams (ERDs).
When you're ready to push code:
deno task git-hook-pre-commit # run all tests/validation that will be run by Git commit hook so there are no surprises
git commit -m ... # commit your if the above shows no errors
deno task prepare-publish # bump the version tag and prepare for push
git push # push the code with the bumped versiondeno task prepare-publish is a simple wrapper but you can also use this for
more control:
git-semtag final && git push
# or git-semtag final -v "vN.N.N" && git push