chore: decision for lua added

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-04-23 11:09:15 +02:00
parent 871ed3192e
commit 3f5744308c
4 changed files with 34 additions and 17 deletions

View File

@@ -22,6 +22,18 @@ The following are intentionally not part of the behavioral contract:
- ORM choice. - ORM choice.
- Internal state management, concurrency model, or runtime libraries. - Internal state management, concurrency model, or runtime libraries.
## Scripting Direction
bDS2 should use Lua as its user-facing scripting language.
The reason is host fit, not language fashion: Lua has a better embedding story for the BEAM than Python does, while still being small, expressive, and suitable for user-authored macros, transforms, and utility scripts. The current direction is:
- Lua script files as the persisted user script format.
- A BEAM-hosted execution boundary with explicit host capabilities instead of unrestricted runtime access.
- Bounded script execution for user-authored code.
This keeps the scripting surface lightweight and aligned with the Elixir host application. Python remains a possible integration boundary for specialized tasks, but it is no longer the default scripting model for the rewrite.
## Repository Layout ## Repository Layout
- [mix.exs](/Users/gb/Projects/bDS2/mix.exs): Mix project definition. - [mix.exs](/Users/gb/Projects/bDS2/mix.exs): Mix project definition.

View File

@@ -16,7 +16,7 @@ value ScriptEditorView {
title: String -- editable text input title: String -- editable text input
slug: String -- editable text input, auto-generated from title slug: String -- editable text input, auto-generated from title
kind: String -- select: utility | macro | transform kind: String -- select: utility | macro | transform
entrypoint: String -- select: dynamically discovered functions, "main" always first entrypoint: String -- select: discovered Lua functions available as entrypoints
enabled: Boolean -- checkbox enabled: Boolean -- checkbox
content: String -- code editor content content: String -- code editor content
created_at: String -- locale-formatted date created_at: String -- locale-formatted date
@@ -50,11 +50,11 @@ surface ScriptEditorSurface {
-- Two rows of metadata fields above the editor. -- Two rows of metadata fields above the editor.
-- Row 1: Title (text input), Slug (text input, auto-generated from title). -- Row 1: Title (text input), Slug (text input, auto-generated from title).
-- Row 2: Kind (select: utility/macro/transform), -- Row 2: Kind (select: utility/macro/transform),
-- Entrypoint (select: dynamically discovered functions with "main" always first), -- Entrypoint (select: discovered Lua functions exposed by the script),
-- Enabled (checkbox). -- Enabled (checkbox).
@guarantee EditorBody @guarantee EditorBody
-- Code editor with syntax highlighting for the configured scripting language. -- Code editor with Lua syntax highlighting.
-- Toolbar: "Content" label. -- Toolbar: "Content" label.
-- Syntax errors shown as inline markers in editor gutter. -- Syntax errors shown as inline markers in editor gutter.
@@ -66,23 +66,23 @@ surface ScriptEditorSurface {
rule ScriptSave { rule ScriptSave {
when: ScriptSaveRequested(script_id) when: ScriptSaveRequested(script_id)
-- Syntax check first using the configured scripting runtime semantics -- Lua syntax check first using the configured runtime semantics
-- If syntax error: blocks save, shows error inline in editor gutter -- If syntax error: blocks save, shows error inline in editor gutter
-- If valid: bumps version, saves to DB + rewrites the published script file -- If valid: bumps version, saves to DB + rewrites the published script file
-- Entrypoint list re-discovered from AST after save -- Entrypoint list re-discovered from Lua source after save
} }
rule ScriptCheckSyntax { rule ScriptCheckSyntax {
when: ScriptCheckSyntaxRequested(script_id) when: ScriptCheckSyntaxRequested(script_id)
-- Validates script syntax without saving -- Validates Lua syntax without saving
-- Shows errors inline in editor gutter -- Shows errors inline in editor gutter
-- Success shown as toast or status indicator -- Success shown as toast or status indicator
} }
rule ScriptRun { rule ScriptRun {
when: ScriptRunRequested(script_id) when: ScriptRunRequested(script_id)
-- Executes script in the configured runtime -- Executes the script in the configured Lua runtime
-- Calls configured entrypoint function (default: main) -- Calls the configured Lua entrypoint function
-- stdout/stderr directed to Output panel tab -- stdout/stderr directed to Output panel tab
-- Output panel auto-opens if not already visible -- Output panel auto-opens if not already visible
-- Errors shown in Output panel with line numbers -- Errors shown in Output panel with line numbers

View File

@@ -79,7 +79,7 @@ surface MenuOpmlSurface {
} }
config { config {
script_extension: String = "script" script_extension: String = "lua"
} }
-- ============================================================================ -- ============================================================================
@@ -202,7 +202,7 @@ value ScriptFrontmatter {
slug: String slug: String
title: String title: String
kind: macro | utility | transform kind: macro | utility | transform
entrypoint: String -- Default: "render" entrypoint: String -- Named Lua function used when invoking the script
enabled: Boolean enabled: Boolean
version: Integer version: Integer
created_at: Timestamp created_at: Timestamp

View File

@@ -2,11 +2,12 @@
-- bDS Scripting System -- bDS Scripting System
-- Scope: core (Wave 6 — scripting behaviour and file contracts) -- Scope: core (Wave 6 — scripting behaviour and file contracts)
-- Distilled from: src/main/engine/ScriptEngine.ts, schema.ts -- Distilled from: src/main/engine/ScriptEngine.ts, schema.ts
-- The scripting runtime is intentionally unspecified here; only behavioural -- Lua is the normative scripting language for user-authored scripts in the
-- contracts are normative. -- rewrite. The concrete embedding strategy remains an implementation choice;
-- only the behavioural contract is normative here.
config { config {
script_extension: String = "script" script_extension: String = "lua"
} }
enum ScriptStatus { enum ScriptStatus {
@@ -18,7 +19,7 @@ entity Script {
slug: String slug: String
title: String title: String
kind: macro | utility | transform kind: macro | utility | transform
entrypoint: String -- default: "render" for macros entrypoint: String -- named Lua function used as the script entrypoint
enabled: Boolean enabled: Boolean
status: ScriptStatus status: ScriptStatus
content: String? content: String?
@@ -139,7 +140,7 @@ rule PublishScript {
when: PublishScriptRequested(script) when: PublishScriptRequested(script)
requires: script.status = draft requires: script.status = draft
requires: ValidateScript(script.content) = valid requires: ValidateScript(script.content) = valid
-- AST parsing must succeed -- Lua parsing must succeed before a script can be published
ensures: script.status = published ensures: script.status = published
ensures: ScriptFileWritten(script) ensures: ScriptFileWritten(script)
ensures: script.content = null ensures: script.content = null
@@ -160,6 +161,8 @@ rule ExecuteMacro {
-- Macro scripts are invoked during template rendering -- Macro scripts are invoked during template rendering
-- via [[slug param1=value1 param2=value2]] syntax in post content -- via [[slug param1=value1 param2=value2]] syntax in post content
-- They receive named parameters and the template context, return HTML -- They receive named parameters and the template context, return HTML
-- from a bounded Lua execution environment that exposes only approved
-- host capabilities
ensures: MacroOutputProduced(script, html_output) ensures: MacroOutputProduced(script, html_output)
} }
@@ -167,7 +170,8 @@ rule ExecuteUtility {
when: RunUtilityRequested(script) when: RunUtilityRequested(script)
requires: script.kind = utility requires: script.kind = utility
requires: script.enabled = true requires: script.enabled = true
-- Runs on-demand from the UI, produces stdout output -- Runs on-demand from the UI in a bounded Lua execution environment,
-- produces stdout output
ensures: UtilityOutputProduced(script, stdout) ensures: UtilityOutputProduced(script, stdout)
} }
@@ -175,7 +179,8 @@ rule ExecuteTransform {
when: BlogmarkReceived(data) when: BlogmarkReceived(data)
-- Transform scripts run sequentially on blogmark deep link data -- Transform scripts run sequentially on blogmark deep link data
-- Input: title, content, tags, categories, source url -- Input: title, content, tags, categories, source url
-- Each transform can modify the data before post creation -- Each transform can modify the data before post creation.
-- Execution uses the same bounded Lua host API contract as other scripts.
let transforms = Scripts where kind = transform and enabled = true let transforms = Scripts where kind = transform and enabled = true
for t in ordered_by(transforms, s => s.slug): for t in ordered_by(transforms, s => s.slug):
ensures: TransformApplied(t, data) ensures: TransformApplied(t, data)