Changelog
All notable changes to Kilnx are documented in this file.
Format based on Keep a Changelog. Versioning follows Semantic Versioning.
Unreleased
Added
fetchresults bind under the user-chosen name (fetch payment: ...exposes:payment.*); previous releases hardcoded thefetch.prefix, silently overwriting multiple fetches in the same action.- Every
fetchexposes:<name>.status_codeand:<name>.ok(true for 2xx) so actions can branch withon payment.okwithout inspecting response shape. fetchbody is encoded as JSON (with typed numbers and booleans) when the user setsheader Content-Type: application/json. Required by Stripe, OpenAI, and other JSON-only APIs; legacy form-urlencoded encoding remains the default.- Builtin function library callable from
fetchbody and header values: 27 pure functions across string (lower,upper,slugify,format, ...), crypto (bcrypt,sha256,uuid,base64), math (round,floor,ceil,clamp,min,max), and util (coalesce,regex,matches,json_get,now) groups. Opt-in vianame(args)syntax; plain:paramtemplates are unchanged. - Arithmetic and string concatenation in fetch values:
body amount: round(:total * 100),body label: format("Order {0}", :id).
Changed
- Transport-level
fetchfailures (DNS, timeout, connection refused) now abort the surrounding action with502 Bad Gatewayand roll back the implicit transaction. Jobs and schedules surface the error to the queue. HTTP 4xx / 5xx are still parsed and exposed (not treated as transport errors). Page renders continue to degrade gracefully.
Security
fetchlog lines redact the URL query string so secrets passed via:paramsubstitution do not leak to stdout.
0.1.2 - 2026-04-22
Added
- Non-unique model-level
index (field_a, field_b, ...)directive; emits idempotentCREATE INDEX IF NOT EXISTS ix_<table>_<cols>for query acceleration, validated by the analyzer the same way as composite UNIQUE - LSP and MCP surfaces advertise the composite
unique (...)andindex (...)directives; model hover lists declared groups - Composite UNIQUE via model-level
unique (field_a, field_b, ...)directive; emits idempotentCREATE UNIQUE INDEX IF NOT EXISTSand is validated by the analyzer (unknown fields, duplicated fields within a group, or duplicate groups) tenantmodifier onmodelfor multi-tenant scoping with fail-closed guards across every query path (refs #48, #52)- PostgreSQL support via
Dialectabstraction; switch engines withdatabase: postgres://...(#46) - Multi-file support via
importstatement with.kilnxextension enforcement and path traversal protection (closes #20, #43) staticdirective to serve files from a directory, validated to stay within project root (#42)fetchkeyword for outbound HTTP from actions, jobs, and webhooks (#39)- Inline fragment rendering on htmx action redirect: matching fragment is returned in the same response when redirecting to a page that defines it
Fixed
- SQL
NULLno longer rendered as truthy in template conditionals (#44) - Filters inside
{{each}}blocks now resolve from the current row, not the outer scope (#40) importtreated as directive only at column 0, allowing the token to appear elsewhere- Timezone-aware time formats parsed in
dateandtimeagofilters - Named parameter error messages clarified
Security
- Mutation bypass via SQL comment, subquery, and string literal closed (#52)
- Tenant guard fails closed and redacts sensitive user fields when rendering (#52)
- Static directory traversal blocked (#42); import traversal blocked and depth limited (#43)
0.1.1 - 2026-03-31
Added
- Governance files, issue templates, and repo automation
- Auto-assignment of PRs to CODEOWNER as reviewer and assignee
- Phase 1 credibility batch (#38)
Fixed
#characters preserved insidehtmlblocks (closes #32)
0.1.0 - 2026-03-28
Initial public release. 27 keywords, 2 runtime dependencies (SQLite + bcrypt), single-binary output.
Added
- Declarative constructs:
config,model,auth,permissions,layout,page,action,fragment,stream,socket,api,webhook,job,schedule,test - Field types:
text,email,int,float,bool,timestamp,richtext,option,password,image,phone - Constraints:
required,unique,default,auto,min,max - CLI:
kilnx run,build,check,test,migrate,lsp,version - SQLite runtime with automatic migrations
- Declarative auth with bcrypt password hashing and HMAC-signed sessions
- htmx-aware fragment rendering with
hx-target/hx-swapsemantics - Server-Sent Events via
stream, WebSockets viasocket - Background jobs and cron-style
schedule - Declarative
testblocks with automatic test database (app.kilnx.test) - Template engine for full HTML control, logical operators, comments
- Static analyzer: type checking, multi-table column validation, subquery analysis, CSRF and security linting
- Query deduplication, JOIN pruning, stream materialization hints (#12)
- Language Server Protocol via
kilnx lsp - Docker image published at
ghcr.io/kilnx-org/kilnx:0.1.0 - Install script and GoReleaser-built pre-compiled binaries for macOS and Linux
Security
All 14 hardening items from the pre-release security review landed in this version:
- CSRF protection enabled by default on every mutation path; linter
flags missing
csrftokens - Parameterized SQL with strict binding; injection paths in string literals, comments, and subqueries closed
- HTML output escaped by default; raw output requires explicit opt-in
- bcrypt password hashing with per-install cost; constant-time credential comparison
- HMAC-signed session cookies with
HttpOnly,Secure,SameSite=Lax - Rate limiting primitives on auth and action endpoints
.kilnximport sandbox: extension check, project root containment, depth limit- Sensitive field redaction in logs and error output