A pluggable runtime for any back-end
npm install johankit-runtimeJohankit Runtime is a modular, event-driven execution runtime built around packages, events, routes, tools, and conditions.
It is not a framework in the traditional sense. It is an execution model designed to let systems grow by composition instead of coupling.
---
Most back-end systems evolve by accumulating:
* integrations
* adapters
* glue code
* shared abstractions
Johankit approaches this differently:
* Everything is a package
* Everything meaningful is an event, route, or tool
* There is no central registry
* There are no hard dependencies between packages
Packages declare behavior explicitly and are discovered automatically at runtime.
---
```
npm install johankit-runtime
---
`ts
import { bootstrap, dispatchEvent } from 'johankit-runtime'
await bootstrap({
workspace: './packages',
http: { enabled: true },
mcp: { enabled: true }
})
await dispatchEvent('user_created', { id: 1 })
`
---
A package is an isolated unit of behavior located inside the workspace directory.
A package may declare:
* event hooks
* HTTP routes
* tools (callable actions)
* predicates
* middleware
* startup logic
* commands (CLI)
Anything not explicitly declared is ignored.
---
At startup, the runtime:
1. Resolves the workspace path
2. Scans all package folders
3. Loads JavaScript files
4. Registers only annotated functions
There is no manual wiring.
---
Behavior is declared using JSDoc-style annotations.
Important rule:
Annotations must be inside the function body.
Example:
`js`
function example() {
/**
* @register_hook user_created
*/
}
Annotations outside the function are intentionally ignored.
---
Events represent something that happened.
`js`
function enrich(payload) {
/**
* @register_hook user_created
*/
return { ...payload, enriched: true }
}
Characteristics:
* Hooks run sequentially
* Returned values replace the payload
* null or undefined are ignored
* Failures do not stop execution
Events act as data pipelines, not notifications.
---
Routes expose HTTP handlers automatically.
`js`
function status() {
/**
* @register_router status
* @method GET
*/
return { ok: true }
}
Routes are automatically namespaced by package name:
``
/your-package/status
---
Tools are structured, callable actions.
`js`
function calculate() {
/**
* @register_tool calculate
* @description Performs a calculation
* @param {number} x - first value
* @param {number?} y - optional value
*/
}
Tools:
* expose input schemas
* can be listed dynamically
* can be invoked programmatically
* can be exposed via MCP or HTTP
They are ideal for automation and orchestration.
---
Commands are executable actions exposed via the Johankit CLI.
`js`
function migrate(args, context) {
/**
* @register_command migrate
*/
}
Commands are namespaced by package and executed using:
`bash`
johankit
Examples:
`bash`
johankit users:migrate
`bash`
johankit users:migrate --force true
`bash`
johankit users:migrate --params '{"force": true, "dryRun": false}'
Characteristics:
* Commands run inside the same runtime context
* Predicates and conditions apply
* Middlewares are executed
* Commands can be safely composed with the rest of the system
---
Predicates are named boolean checks.
`js`
function isAdmin() {
/**
* @register_predicate is_admin
*/
return true
}
They enable conditional behavior elsewhere in the system.
---
Middleware can be conditionally enabled using predicates.
`js`
function guard() {
/**
* @register_middleware access_guard
* @predicate is_admin
*/
}
Only predicates that evaluate to true activate the middleware.
---
Many declarations support optional conditions:
* @only web@never mobile
* @when authenticated
*
Conditions are metadata, not enforcement rules.
They enable higher-level orchestration without hardcoding logic.
---
Johankit can expose tools through an MCP-style control interface.
Capabilities:
* list tools
* inspect schemas
* invoke tools dynamically
This makes the runtime suitable for:
* automation systems
* agents
* orchestration layers
* external controllers
---
`ts``
bootstrap({
workspace: './packages',
http: { enabled: true, port: 5040 },
mcp: { enabled: true }
})
The bootstrap process:
* loads all packages
* initializes routes
* enables MCP interfaces
* starts HTTP servers if configured
---
* Explicit behavior over magic
* Composition over inheritance
* Isolation between packages
* Protocol-agnostic core
* Graceful failure handling
---
Early-stage and evolving through real usage.
APIs are intentionally minimal and may evolve as patterns emerge.