# Gina — Roadmap This roadmap covers planned features, architectural improvements, new connectors, and AI integration. Items marked ✅ are shipped. All planned items are open to community contribution — see [CONTRIBUTING.md](./CONTRIBUTING.md) for how to get involved. > **Docs:** [gina.io/docs](https://gina.io/docs/) · **Issues:** [github.com/gina-io/gina/issues](https://github.com/gina-io/gina/issues) --- ## Timeline | Period | Version | Focus | | --- | --- | --- | | **Apr 2026** | `0.1.8` ✅ | Scaffold correctness · K8s support · Dependency injection · Automatic version migration | | **Q2 2026** | `0.2.0` ✅ | Stability · WatcherService · Redis & SQLite connectors · K8s session storage · Startup cache · Pointer compression · Couchbase v2 deprecation · Couchbase security & critical bug fixes · HTTP/2 security hardening | | **Q3 2026** | `0.3.0` ✅ | Async/await · Dev hot-reload · MySQL & PostgreSQL connectors · AI Phase 2 · Tutorials · Mobile backend guide · Route radix tree · Connector peerDependencies · 103 Early Hints · HTTP/2 observability · Security & CVE page · Couchbase connector hardening · Inspector Phase 1 + Phase 2 · CLI Tier 1 (project lifecycle, port:set, framework:get) | | **Q3 2026** | `0.3.1` ✅ | Release workflow fixes · SQL index reporting Phase A · HTTP/2 direct stream for HTML · Dependency reduction (`ssl-checker`, `colors`, `uuid` removed — engine.io sole runtime dep) | | **Q3 2026** | `0.3.2` ✅ | JSON Schema for config files · Entity short-name aliases · Model loading fix · getConfig() proxy fix · Inspector tab presets & QI propagation | | **Q3 2026** | `0.3.3` ✅ | OpenAPI spec generation · CLI port:set & framework:get · TypeScript declarations · Explicit exports · Swig npm migration · Live index introspection · Popin perf · Docker fixes | | **Q3 2026** | `0.3.4` ✅ | Patch: `gna.js` stale framework path fix · Release lifecycle `gna.js` sync | | **Q3 2026** | `0.3.5` ✅ | Security: `@rhinostone/swig` 1.5.0 (CVE-2023-25345 extended guards) · Browser-side swig parity | | **Q4 2026** | `0.3.6` ✅ | Inspector payload redaction (#R7) · Pre-commit & CI local-tool path guards · Private-token leak gate · Whisper Error fix (#B12) · `framework:init` hardening (#B13) · CORS preflight fix · `syncDocs` lockfile regen | | **Q4 2026** | `0.3.7` ✅ | Web Security CSRF trilogy (#CSRF1/2/3) · Nunjucks template engine opt-in (#NJ1–#NJ4) · Eval-safety hardening (#SCS1) · MCP server (#AI8 stdio + HTTP transports) · `connector:*` CLI (#CN10) · vendored-dep CVE-visibility lock · psl/optimist removal · Session.name drop-in identity | | **Q4 2026** | `0.3.8` ✅ | Patch: `npm install -g gina@latest` regression fix — `psl` + `@rhinostone/swig` promoted to top-level deps · install scripts decoupled from framework `lib` registry · helpers preload guarding `lib/logger` ↔ `framework/v*/helpers` circular dep | | **Q2 2026** | `0.3.9` ✅ | Consumer-feedback batch (11 framework patches): per-request middleware dispatch isolation · Couchbase 4.x JsonTranscoder · `length` filter null safety · `process.env` mirroring · 6 nunjucks render-pipeline patches (libRef fallback · namespace prefix drop · bundle filter wraps · top-level userData · `data.data` alias · ginaLoader placeholders) · `getAssets` mid-URL `{{ }}` strip-guard anchor | | **Q2 2026** | `0.3.10` ✅ | FormValidator HTML5 form-reassociation hardening trilogy (`HTMLFormControlsCollection`-based `bindForm` + `unbindForm` symmetry · radio mutual-exclusion + IDL/attribute reconciliation · `defaultChecked` cache for reset) · `X-Forwarded-Prefix` reverse-proxy path-prefix awareness | | **Q2 2026** | `0.4.0` ✅ | Couchbase v2 removal (BREAKING — SDK v2 connector + session store dropped) · HTTP/2 response trailers · async-job primitive · CSP per-response nonce · `secrets:scan` / `secrets:check` CLI · SQL column-level index coverage — of the items originally targeted here: AI agents (MCP) shipped `0.3.7`, ScyllaDB `0.3.11`, CLI Tier 2 `0.4.1`, the docs offline ZIP is live on the docs site, and the Advanced tutorial · website redesign · Bun investigation moved to `0.5.x` | | **Q2 2026** | `0.5.0` ✅ | ESM entry points (dual CJS/ESM `exports` map) · Mixed template engines per bundle (extension-keyed `.njk` / `.swig` dispatch) · Nunjucks Inspector parity — the other items originally targeted here shipped earlier: structured logging (`0.4.5`), Alt-Svc (`0.4.2`), WebSocket over HTTP/2 (`0.4.7`), Inspector production auth (`0.4.0`) | | **Q2 2026** | `0.5.1` ✅ | Patch: released-response crash family — late `throwError()` and the HTTP/2 inter-bundle query retry / late-response / redirect-intercept paths no longer kill the bundle · dev-mode hot-reload `module.children` heap leak fixed (OOM under sustained load) · inter-bundle proxy JSON bodies keep their `application/json` label · ROADMAP consistency release gate | | **Q2 2026** | `0.5.2` ✅ | Patch: released-response crash family completed across the remaining synchronous controller surface — `renderJSON()` / `redirect()` / `store()` / `push()` / `renderStream()` / request-method + form-rule helpers no longer kill the bundle when called on an already-released response · exhausted HTTP/2 502 retries surface a typed `BAD_GATEWAY` error instead of being consumed as success | | **Q2 2026** | `0.5.3` ✅ | Patch: released-response crash family finished — late `throwError(status, error)` (2- and 3-argument forms) and the HTML render delegates (swig / nunjucks + async variants) no longer crash or emit unhandled rejections when invoked on an already-released response · atomic `~/.gina` state-file writes (concurrent multi-bundle / multi-container boot can't read a torn file) · framework command-socket hardened against malformed / fragmented payloads · framework socket port no longer corrupted by a bundle's `--port` · synchronous boot-failure diagnostics under piped stdout/stderr · storage `_id` collision hardening · `gina port:set --force` | | **Q2 2026** | `0.5.4` ✅ | Node.js 26 support (engine `>= 22 <27`, CI matrix) · FormValidator fixes (`isFloat` accepts string floats · `isDate` non-ISO masks + rule chaining) · quieter live form validation (error message revealed on blur) · file-upload fixes (honour `tmpPath` / per-group `path` · enforce `maxFields` + `maxFieldsSize` unit suffix · **Security**: reject uploads to an unconfigured group, closing an `allowedExtensions` / `isMultipleAllowed` bypass) · two dev-mode heap fixes (hot-reload lib-eviction leak · HTTP/2 `self.query()` settled-stream retention) · tighter per-request config isolation (narrowed router clone · `getRouteByUrl` shared-config mutation) · dev Inspector reliability (per-tab channel under COOP · Swig render-race isolation · multi-bundle proxy log/index routing · SPA hardening) · Express-engine `/_gina/info` + `/_gina/cache/stats` parity · `bundle:add --ignore-ports` | | **Q2 2026** | `0.5.5` ✅ | WebSocket routes in `routing.json` (`method: "ws"` + `param.wsHandler` → `channels/.js`, `:param` paths, per-route `param.wsOptions`) · cross-bundle `session.query()` from WebSocket channel handlers · framework version side-by-side CLI (`framework:add` / `framework:list` / `framework:remove` / `framework:update` / `framework:reset`) · `project:move` / `project:backup` / `project:restore` · inline CLI man pages (`framework:man` / `project:man` / `bundle:man` / `service:man`) · Bun promoted to a supported, CI-gated runtime · idempotent HTTP/2 client retries (safe-method gating + per-call `retryUnsafe` opt-in) · **Security**: WebSocket-DoS dependency hardening (`ws` override) · `tail` restart hardening | | **Q3 2026** | `0.5.6` ✅ | AI-connector CLI suite — `connector:infer` (one-off inference · `--stream` NDJSON · `--raw`) + `connector:test` (CI readiness probe · `--connect` zero-token live check) · AI connector `stream()` + Inspector "AI stream" tab · application events in the Inspector — `self.emitEvent()` + a new "Events" tab, opt-in entity-event & connector-lifecycle bridges · `getModel()` exposes the AI `infer`/`stream` API · fixes: model-init fail-fast · corrupt `projects.json` registration skipped cleanly · DELETE-route regex flags + off-by-one crash · UTF-8 multipart upload filenames · native `` popin close cleanup · Couchbase dynamic field-path placeholder · `project:import` additive across release targets · `gina stop` bundles-still-running notice | | **Q3 2026** | `0.5.7` ✅ | Durable async-job stores — `jobs.store` (app.json) → `connectors.json` entry: SQLite (`node:sqlite`, zero new dependencies) · MongoDB (shared mongod, multi-pod) · Redis (`ioredis`, atomic per-state + expiry indexes, Redis Cluster via hash-tagged prefix); restart-durable, cross-process, fail-fast on an unbuildable store · opt-in failed-job retry (`maxAttempts` + exponential backoff; completion webhook fires exactly once) · npm 12 readiness (install + release tooling, `--allow-scripts=gina` guidance) · render-delegate concurrency fixes (production cross-request data bleed / wrong-controller error routing / cached-route 500) · `"connector": "redis"` entry no longer aborts boot · **Security**: static-asset path-traversal fix — resolver paths canonicalised and confined to their `statics.json` mapping target (404 on any escape, `%2F` / `%2e%2e` forms included) | | **Q3 2026** | `0.5.8` ✅ | `connector:models` — list a configured AI connector's provider models (the read sibling of `connector:test --connect`) · per-group `gina help []` · **Fixed**: reverse-proxy host context request-scoped — `PROXY_HOST` / `PROXY_HOSTNAME` no longer freeze at the first proxied request (single-hop and multi-hop `X-Forwarded-Host` both handled; raw `host:port` unchanged) · CLI help polish (per-group help output, clean message for an unknown action, em-dash flag typos) | | **Q3 2026** | `0.5.9` ✅ | **Security**: reverse-proxied deployments no longer disclose a bundle's internal `scheme://host:port` to the browser — the client `gina.config.hostname` and the fetched `/_gina/assets/routing.json` serve a public host-only origin and a host-stripped routing map to proxied clients (direct `host:port` access byte-identical), also fixing cross-bundle client `getRoute(...).toUrl()` which previously resolved to the unreachable internal host (#B66) · **Fixed**: the server-side URL / redirect / config resolvers request-scope the proxy host, so a worker serving mixed proxied + direct traffic (or several public hosts) no longer inherits a stale proxied host (#B66 S2b) · **Fixed**: `connector:add` / `connector:rm` / `connector:migrate --fix` no longer corrupt a comment-headed `connectors.json` · **Fixed**: a latent `ReferenceError` in server-side URL resolution for redirect-flagged routes | | **Q3 2026** | `0.5.10` ✅ | **Fixed**: server-side cross-bundle `getRoute('route@bundle').toUrl()` now resolves the public host on reverse-proxied deployments — a controller building a cross-bundle URL server-side (e.g. via `self.redirect`) could emit an unreachable internal host with a doubled web root on a proxied request; it now resolves the public host for both the Isaac and Express engines. Completes the `0.5.9` client-side cross-bundle URL fix on the server side (#B67) | | **Q3 2026** | `0.5.11` ✅ | `image:build` — first-class OCI packaging: synthesizes a Containerfile + build context from the project's registered state (bundles, entry, ports, env model, node floor) and builds with buildah, natively on Linux or on a container host over ssh (env override → native → `container.host` settings fallback); dev/prod parity (a non-dev env ships the release tree built in-image), deterministic `EXPOSE`, `${secret:KEY}` placeholders never baked; `--emit` / `--format=json` / `--stream` NDJSON for CI and GUI consumers · **Fixed**: framework-emitted redirects on proxied requests carry no-store cache headers, so a browser never caches a proxy-context-derived redirect (the inter-bundle query 3xx forward path inherits the set; direct production redirects unchanged) | | **Q3 2026** | `0.5.12` ✅ | FormValidator built-in rule labels localise from the per-bundle i18n catalog (`_validator.`) on both the client and server, with a `gina.validator.setErrorLabels()` per-key override · per-bundle i18n catalogs activate URL-prefix / cookie / `Accept-Language` culture negotiation and `t()` at boot, and the negotiated culture now reaches every request (it previously resolved to `en`/empty #B83, and was dropped on warm/cached reloads #B84) · `data-gina-form-rule` forms auto-boot the client validator · **Fixed**: validator correctness (empty-required single message #B78, cross-field `is` empty operand #B82, submit trigger stays operable via `aria-disabled` #B76), popin / redirect robustness (#B80 / #B77 / #B75, static directory-to-index 301 outside dev), and CLI robustness (malformed `@` rejected #B69, `GINA_HOMEDIR` re-export across child commands, `project:start` / `service:start` delegation, zero-bundle bulk commands, `framework:add` install hint #B81) | | **Q3 2026** | `0.5.13` ✅ | Unrenderable `_validator` catalog labels are caught at bundle boot — an unknown `%`-token (anything but `%l` / `%n` / `%s`, including a literal percent glued to letters as in `20%sur le prix`), a non-string label, or a non-object `_validator` section now warns and names the offending rule and catalog file. Warn-only: the catalog still loads, so a translation typo surfaces in the boot log instead of in production copy | | **Q3 2026** | `0.5.14` ✅ | Validator + error-handling robustness — a non-string validator error label now degrades to the rule's English default instead of throwing (the throw had aborted validation and left every later form on the page unbound), across all four label sources · a per-field `ApiError` message no longer leaks a raw server stack trace to the browser outside local scope · a changing validator message on a still-invalid field re-announces through the ARIA live region · release: stable publishes assert a single, correctly-named README "What's in" section | | **Q3 2026** | `0.5.15` ✅ | Client-side components (Web Components) — standards-based, zero-dependency conventions for stateful client widgets: `gina view:add` scaffolds a reference custom element (server-rendered light-DOM partial + behavior-only class), components upgrade automatically in popin/XHR-injected content with no rebinding, form-associated custom elements participate in `FormValidator`, live-data components ride the connect/disconnect lifecycle over `method:"ws"` routes or SSE, and the dev Inspector gains a component census + client component-event capture · a popin/dialog trigger can opt out of the hover/focus preload (`data-gina-dialog-preload="false"`) · **Fixed**: `gina.popin` sees every popin so a form can redirect into a different one (#B90), a redirect into a popin opens content-first (#B79), server-side validation of a data object against a rules object works (#B85), `$form.send(FormData)` nests bracket-notation field names (#B92), a fields-only multipart POST no longer hangs (#B93) and a malformed multipart body no longer crashes the bundle (#B97), `X-Powered-By` suppression reaches static and error responses (#B96), and upload reset/delete removes the preview, restores class-hidden inputs, and gains removal callbacks (#B94/#B95) | | **Q3 2026** | `0.5.16` ✅ | **Added**: a `multipart/form-data` request's non-file text fields are now captured into `request.body` (bracket-notation nested, values verbatim, capped by `upload.maxTextFields` / `upload.maxTextFieldSize` with a 400 on breach) — previously silently dropped · **Fixed**: `$form.send(FormData)` keeps its non-file fields when the payload also carries files (#B92), and a routing rule's `param.title` now reaches the browser-tab title (`page.view.title`) instead of always showing the route name, with the route name as the fallback (#B98) | | **Q3 2026** | `0.5.17` ✅ | **Fixed**: `npm install -g gina` no longer fails with `EALLOWSCRIPTS` under the npm 12 `--allow-scripts=gina` remedy — the nested framework-dependency install drops the inherited allowance, making `0.5.17` the first version installable on npm 12 (#B106) · stale project cleanup is reliable — `project:rm @ --force` (the alias) removes the entry, and `project:remove` / `:rm --force` no longer `ENOENT`-crashes on an uncreatable stale path, going straight to registry-only removal (#B104/#B105) · `bundle:start` honours a bundle's configured default scope (a typo had returned an undefined property) | | **Q3 2026** | `0.5.18` ✅ | **Added**: a redis-backed L2 render cache — rendered output is cached in a shared store, so several replicas serve the same rendered page and a freshly-started replica serves what a peer already rendered (cross-replica cold-start), degrading to per-replica caching if redis is down · pluggable cache backends (`server.cache.type`: `memory` / `fs` / `redis`) with bundle-wide `sliding` / `maxAge` fallbacks a route inherits · type-safe DTOs and a default-on validation pipe (`gina.dto` — one shape projected to runtime validation, response shaping, JSON Schema and TypeScript; `param.dto` validates the payload before the action with a localised 422, `param.responseDto` shapes the wire, `gina bundle:types` emits declarations, and `bundle:openapi` / `bundle:mcp` emit real request/response schemas) · `releaseWatch` — an opt-in stale built-release watch for local production rehearsals (source-tree fingerprint against the manifest release stamp, `GET /_gina/release/status` + an SSE stream, idle-gated rebuild-and-restart honouring in-flight requests and busy probes, a live shadow-DOM banner, and `restartMode: supervisor` for daemonless container launches) · `POST /_gina/cache/clear` + a `gina cache:clear` CLI (flush the rendered-output cache, or evict by event across bundles) · two-tier cache observability (an RFC 9211 `Cache-Status` `detail` naming the serving tier, plus an `l2` redis-health block on `/_gina/cache/stats`) · **Changed**: render-cache keys are release-namespaced, so an upgrade auto-invalidates (`GINA_CACHE_NAMESPACE`, else the framework version) · the `Cache-Status` miss form is now the RFC 9211 `gina-cache; fwd=uri-miss`, and Express bundles get their first cache-miss signal · **Fixed**: event-driven cache invalidation works — `self.cache.invalidateByEvent()` now exists, and a key carrying a querystring no longer throws a 500 that discarded an already-rendered page · the `fs` cache survives a restart (disk read-back via a `.meta` sidecar, original absolute expiry preserved, no TTL extension) · a checkbox's `value` attribute no longer decides its `checked` state (#49) · the published TypeScript declarations describe the runtime · errors surface instead of crashing, masking, or coming back as `0` (detached-context `throwError`, partial-boot `getLib()` / `getConfig()`, a bitwise-or at nine sites, and `$` in log messages) | | **Q3 2026** | `0.5.19` ✅ | **Added**: route authorization — a `routing.json` rule gates access before the action runs via `param.requireAuth` (a 401 for XHR, a non-cacheable login redirect for a browser navigation, the original request snapshotted for `resumeRequest()`), `param.roles` (ANY-of, implies `requireAuth`), and `param.policy` (a per-bundle function for the ownership/record checks roles can't express, AND-composed after roles); denials stay generic — required roles and the policy name never reach the wire — author mistakes refuse to boot, and `self.hasRole()` authorizes mid-logic · an audit trail — opt-in `self.audit(action, data)` writes a user-attributed append-only JSONL record (its own store, never the logger sinks; an actor snapshot, `X-Forwarded-For` never trusted), route-authorization denials recorded automatically, and an always-on request id correlating audit records to JSON logs · an OCI image/container CLI on the `image:build` host — `image:list` / `image:rm` / `image:run` (podman; publishes the EXPOSEd port, `--env-var` / `--env-file` keep secrets out of argv) and a `container:` group (`container:ps` / `container:stop`, reporting the rung a container came down on) · **Changed**: `redirect()` carries request data through the session by default (a one-shot flash, gone on refresh), the clear-text `?inheritedData=` URL form and its 2000-char cap now session-less-only — removing a plaintext-secret-in-URL disclosure when a session-ful bundle halts a credential-bearing POST · **Fixed**: Prometheus metrics no longer double-count under the isaac engine (#OBS1) · the relative `self.redirect('/path')` form resolves again and an unresolvable target 404s instead of crashing (`redirect()` is now async), and `getRoute()` no longer 500s on a requirements-less GET route with extra params (#B120/#B121) · `image:build` for gina-dependent projects no longer fails at gina-init and the pinned framework wins `require('gina')` (#B118/#B119) · `gina.emit` is an inert stub (#B109) and the checkbox migration warning now covers the un-tick direction (#49) | | **Q4 2026** | `0.6.0` | Security & compliance controls (technical safeguards mapping to PCI-DSS / SOC2 / HIPAA) | | **Q1 2027** | `0.5.x` | HTTP/2 priorities (blocked on Node scheduler hooks) · Beemaster admin + visual translation editor | | **Q3 2027** | `1.0.0` | First stable release — Windows alpha compatibility is a hard gate | --- ## Features | Status | Feature | Version | Target | | --- | --- | --- | --- | | ✅ | **Automatic version migration** — Upgrading or downgrading gina (e.g. `0.1.x → 0.2.0`, `0.5.x → 1.0.0`) automatically migrates `~/.gina/` config to the new version on first startup. Downgrade is free — old version data is never removed. | `0.1.8` | 2026-03-26 | | ✅ | **`watchers.json`** — First-class bundle config for file watchers. Declare watchers on config files with event-based notification (no polling). Foundation for the dev-mode hot-reload system. | `0.2.0` | 2026-03-29 | | ✅ | **i18n core** — Per-bundle message catalogs under `bundle/locales/.json` with a fallback chain (specific culture → base language → default). Server-side `t(key, [params], [culture])` global helper with parameter interpolation and CLDR pluralisation. Swig and Nunjucks filters with the same surface (`{{ "key"\|t }}`, `{{ "key"\|t({ name: x }) }}`). Per-request locale negotiation from URL prefix / cookie / `Accept-Language` / settings default. CLI: `gina i18n:scan` for missing-key coverage per culture, `i18n:add ` to seed a new catalog, `i18n:export` / `i18n:import` for `.po` / `.csv` / `.json` round-trip with translators. Headless by design — the visual translation editor lands later as the first content feature in Beemaster (admin Phase 3). Runtime + filters + `req.culture` negotiation + full CLI all shipped on the `0.3.11-alpha` track. | `0.3.11-alpha` | 2026-05-08 | | ✅ | **i18n ICU MessageFormat** — Opt-in `t.icu(key, params, culture)` variant powered by `intl-messageformat`. Adds gender / select / nested combinators (`{count, plural, one {# item} other {# items}}`, `{gender, select, female {…} male {…} other {…}}`) on top of the i18n core. Existing `t()` shape unchanged — v1 catalogs continue to work. Covers grammars (Romance, Slavic) and select expressions the v1 `{name}` + plural-forms shape can't express. Exposed as `gna.t.icu()` (global), `self.t.icu()` (controller helper), and `tIcu` template filter (swig + nunjucks). Library loaded via dynamic `import()` from a module-level loader kicked off at bundle boot — sync API after first-call resolves. | `0.3.11-alpha` | 2026-05-08 | | ✅ | **PWA scaffold** — `gina view:add` drops a `manifest.webmanifest` and a cache-first service worker stub (`sw.js`) into the bundle's `public/` directory, and adds the manifest ``, a `theme-color` ``, an apple-touch-icon ``, and an inline service-worker registration script to the default HTML layout. Zero runtime dependency — static files plus layout tags. Enables Gina apps to be installed on mobile as PWAs without additional tooling. | `0.3.13` | 2026-05-14 | | ✅ | **Per-bundle framework version** — Declare `"gina_version": "0.1.8"` on any bundle entry in `manifest.json` to pin that bundle to a specific installed framework version. The socket server continues running its own version; only the spawned bundle process uses the declared version. Validated against the tracked version list in `main.json` before start. `--gina-version=X.Y.Z` flag on `bundle:start` provides the same override without touching config files. | `0.3.0` | 2026-03-31 | | ✅ | **PATCH method** — `req.patch` populated with the parsed request body (JSON or form-encoded). `req.body` aliases `req.patch`. URI params merged. `"method": "PATCH"` valid in `routing.json`. Use PATCH for partial updates (only sent fields change) vs PUT which replaces the full resource. | `0.3.0` | 2026-03-31 | | ✅ | **HEAD method** — `req.head` populated with query-string and URI params. Full controller action runs so all response headers are set correctly; body is suppressed before writing to the wire. Both `render()` and `renderJSON()` honour HEAD. Routes declared as `GET` automatically accept HEAD — no extra routing rule needed. | `0.3.0` | 2026-03-31 | | ✅ | **Client-side components (Web Components)** — Standards-based conventions for stateful client widgets: custom elements v1, zero dependency, no build tooling. Server-rendered light-DOM authoring keeps HTML (designer) and JS (developer) separated — the behavior-only class binds its own server-rendered subtree and holds no markup strings (repeatable markup clones from a server-rendered `