All notable changes to this project will be documented in this file.
The format follows Keep a Changelog, and this project adheres to Semantic Versioning.
- Parametric flows — flows can declare typed parameters:
flow "analysis" (topic: "string", depth: "number") { ... }. Parameters resolve as values in agent expressions and are injected viaRuntimeOptions.params. Parameter types are advisory; the runtime does not enforce them. - Functional import —
import "file.slang" as aliasnow fully works at runtime. The imported sub-flow runs to completion before the parent flow's main loop. Its output is exposed as a synthetic committed agent named by the alias, enablingawait data <- @aliasin parent agents. RequiresRuntimeOptions.importLoadercallback. FlowParamAST node type exported fromsrc/ast.tsparamsfield onFlowState— accessible afterrunFlowto inspect injected parametersimportLoader?: (path: string) => string | Promise<string>inRuntimeOptionsparams?: Record<string, unknown>inRuntimeOptions- New examples:
examples/parametric.slang,examples/import-composition.slang
- Documentation restructuring — moved detailed guides to
docs/folder for improved organization:docs/IDE.md— IDE & editor support (VS Code, Neovim, Vim, Sublime, JetBrains, LSP)docs/PLAYGROUND.md— web editor features and usagedocs/CLI.md— command-line interface, commands, options, and environment variablesdocs/API.md— programmatic usage, adapters, tools, checkpoint & resume, static analysisdocs/MCP.md— Model Context Protocol integration with Claude Desktop
- README.md — streamlined with focus on core content; links to detailed docs in
docs/folder - Examples section — reduced to essentials, pointing to the
examples/folder with quick launch commands - Updated copilot-instructions.md to reference new docs location
- False-positive deadlock detection —
detectDeadlocks()incorrectly flagged sequential await-stake-await patterns (e.g. research flow: Analyst awaits Researcher, stakes to Critic, then awaits Critic) as cyclic deadlocks. Now only leading awaits (before any stake/commit) are considered for cycle detection. Affects core runtime, LSP diagnostics, MCPcheck_flow, and playground.
initialAwaitsFromfield inAgentDepto distinguish blocking initial awaits from sequential mid-flow awaits- Playground: Flow Analysis panel — replaced the Run (Echo) tab with a static analysis section showing convergence verdict, deadlock cycles, diagnostics, and per-agent status
slang playgroundstatic server — asset requests with/slang/base path prefix were not resolved correctly, causing MIME type errors (text/htmlinstead ofapplication/javascript)
- GitHub Pages deployment — playground was not served; GitHub Pages rendered the README instead of the built playground app
- Added
.nojekyllto build output to prevent Jekyll processing - Fixed Vite
baseconfig to use/slang/only in production builds,/in dev mode
expectstatement — flow-level test assertion, evaluated after flow executionexpect @Agent.output contains "text"— string containment assertionexpect @Agent.committed == true— equality assertionexpect @Agent.status == "committed"— status assertion
containsoperator — binary operator for string containment, usable inexpectandwhenblocks- Mock adapter —
createMockAdapter({ responses, defaultResponse })for deterministic, per-agent testing without LLM calls testFlow()function — parses, executes with mock adapter, evaluates allexpectstatements, returnsTestResultslang testCLI command — native test runner for.slangfilesslang test flow.slang— run with default mock responsesslang test flow.slang --mock "Agent:response,Agent2:response2"— custom per-agent mock responses
- Playground test integration — auto-detects
expectstatements and usestestFlowwith mock adapter when RUN is clicked - New runtime events:
expect_pass,expect_fail - New error code:
E407(Test assertion failed) - New example:
examples/test-flow.slang— testing pattern with assertions - 21 new tests (266 total)
- Local stake —
stakewithout-> @Targetexecutes locally, storing the result in the agent's output without sending to the mailboxstake func(args)— execute LLM call, result stored in agent output onlylet var = stake func(args)— execute and store result in a new variableset var = stake func(args)— execute and update an existing variablelet var = stake func(args) -> @Target— both store locally and send to recipient- Enables chaining multiple LLM calls within a single agent without
await
- New AST field:
StakeOp.binding(optional variable name for binding stake results) - New example:
examples/local-stake.slang— single-agent multi-step pattern - 12 new tests (245 total)
StakeOprecipients list is now optional (empty array = local execution)- Parser accepts
stake func(args)without->(no longer requires-> @recipient) GRAMMAR.md,SPEC.md,ZERO_SETUP_PROMPT.mdupdated with local stake syntax and semantics
- LSP Server (
@riktar/slang-lsp) — full Language Server Protocol implementation for.slangfiles- Real-time diagnostics from
parseWithRecovery()+analyzeFlow()+detectDeadlocks() - Autocompletion — keywords,
@AgentRefreferences, meta keys (role:,model:,tools:, etc.) - Go-to-definition — click on
@AgentNameto jump to the agent declaration - Hover information — keyword docs, agent metadata summary, special ref descriptions (
@out,@all,@Human) - Document symbols — outline view with flows, agents, operations
- Communicates via stdio — works with any LSP-compatible editor
- Real-time diagnostics from
- VS Code Extension (
vscode-slang) — first-class IDE support- TextMate grammar for full syntax highlighting (keywords, primitives, agent refs, strings, operators)
- Language configuration: bracket matching, auto-closing, comment toggling (
--), folding - 18 snippets for common patterns:
flow,agent,stake/await/commit,when/else,repeat until,converge,budget,deliver,import, and a fullflow-researchtemplate - LSP client for real-time diagnostics, completions, hover, go-to-definition
- Editor grammars for Vim, Sublime Text, and JetBrains IDEs
- Vim/Neovim: syntax file (
editors/vim/syntax/slang.vim) + filetype detection (editors/vim/ftdetect/slang.vim) - Sublime Text:
.sublime-syntaxdefinition (editors/sublime/slang.sublime-syntax) - JetBrains: TextMate bundle ready for import (
editors/jetbrains/)
- Vim/Neovim: syntax file (
- IDE documentation — new docs/IDE.md with setup instructions for all editors
- Monorepo workspace support via npm workspaces (
packages/slang-lsp,packages/vscode-slang) - New build scripts:
build:lsp,build:vscode,build:all
- Silent output by default — round-by-round agent outputs are now hidden during flow execution. Only a progress indicator and the final result are shown.
--debugflag — pass--debugto restore full verbose output (round headers, agent operations, LLM responses, tool calls).- Committed agent outputs in result — the final result section now always displays each committed agent's output, so the flow content is always visible at the end.
- Deliver output resolution —
deliver:handlers now receive actual agent output instead ofundefined. When no agent stakes to@out, the flow collects committed agents' outputs as the deliver payload (single agent → its output directly, multiple agents → a{ AgentName: output }map). - Deliver ident args resolve to agent output — identifier arguments in
deliver: handler(AgentName)now resolve to the named agent's committed output instead of passing the agent name as a plain string.
- CLI
--key=valueargument parsing — flags like--deliverers=tools.jsand--tools=handlers.jsnow work correctly. Previously only--key value(space-separated) was supported, causing--key=valueto silently ignore the flag. - Deliver handlers always fire —
deliver:statements andonConvergenow execute on any terminal flow status (converged,budget_exceeded,deadlock,escalated) instead of only onconverged.
- Deliver handlers always fire —
deliver:statements andonConvergenow execute on any terminal flow status (converged,budget_exceeded,deadlock,escalated) instead of only onconverged. This ensures side effects are never silently skipped when a flow ends due to budget exhaustion or a deadlock.
--deliverersCLI flag — pass a JS/TS file with post-convergence deliver handlers viaslang run ... --deliverers deliverers.js(same pattern as--tools)
evalConvergencedummyAgentStatewas missing thevariablesfield (TypeScript error)- CLI version string was showing v0.5.0 instead of v0.6.0
Internal release — skipped in changelog.
- Variables & State —
let/setstatements for agent-local variableslet name = expression— declare a new variable scoped to the agentset name = expression— update an existing variable's value- Variables persist across rounds and are included in the agent's LLM prompt context
- Variables are resolved before
awaitbindings in expression evaluation
- Conditionals:
else/otherwise— mutually exclusive branches forwhenblockswhen expr { ... } else { ... }— execute the else block when the condition is falseotherwiseis an alias forelse- Backward compatible:
whenblocks withoutelsebehave as before
- Loops:
repeat until— explicit iterationrepeat until condition { ...operations... }— repeat the body until the condition is true- Safety limit of 100 iterations prevents infinite loops
- Deliver: post-convergence side effects —
deliver:flow-level statementdeliver: handler(args)— declares a handler to execute after flow convergence- Multiple deliver statements execute in declaration order
- Handlers provided via
RuntimeOptions.deliverers(same pattern astools) - Only runs on successful convergence — not on budget_exceeded, escalated, or deadlock
onConvergeruntime hook —RuntimeOptions.onConvergecallback fires after all deliver handlers complete--deliverersCLI flag — pass a JS/TS file with deliver handlers viaslang run ... --deliverers deliverers.js- New AST node types:
LetOp,SetOp,RepeatBlock,ElseBlock,DeliverStmt - New tokens:
Let,Set,Else,Otherwise,Repeat,Until,Eq,Deliver - New runtime types:
DeliverHandler,RuntimeEventdeliver/on_converge events - New example:
examples/finalizer.slang— Finalizer pattern with deliver - 38 new tests (223 total)
slang init [dir]— scaffold a new SLANG project- Generates
hello.slang,research.slang,tools.js,.env.example - Idempotent: skips files that already exist
- Prints next-steps guide after scaffolding
- Generates
.envsupport — the CLI automatically loads a.envfile from the current directory- Standard
KEY=VALUEformat with comments (#) and optional quotes - Real environment variables take precedence over
.envvalues - Supported:
SLANG_ADAPTER,SLANG_API_KEY,SLANG_MODEL,SLANG_BASE_URL, plus provider-specific keys
- Standard
- CLI now reads
SLANG_ADAPTER,SLANG_MODEL, andSLANG_BASE_URLfrom environment (not just--flags) - 10 new CLI tests for init scaffolding and .env loading (185 total)
- Playground packaging — only
playground/dist/is included in the npm package (380 KB vs 145 MB)- CLI serves pre-built static files via
node:httpinstead of spawning Vite build:playgroundscript added for pre-build step
- CLI serves pre-built static files via
- CLI version updated to 0.5.0
- Error System — centralized error codes, human-friendly messages, and source context
SlangErrorCodeenum with documented codes: L1xx (lexer), P2xx (parser), R3xx (resolver), E4xx (runtime)formatErrorMessage(code, params?)for template-based human-readable messagesSlangErrorbase class withcode,line,column, source context display (caret pointer), andtoJSON()serializationLexerError,ParseError,RuntimeErrorall extendSlangErrorwith proper error codes and location tracking
- Parser Error Recovery —
parseWithRecovery(source)returns{ program, errors }instead of throwing on first error- Collects all parse errors and returns partial AST for IDE/playground use
- Synchronizes to next valid token after encountering an error
- Original
parse()still fails fast for CLI/production use
- Runtime Error Improvements —
RuntimeErrorcarries line/column from AST operation spans- "No flow found" →
RuntimeError(E400)with location - "Retries exhausted" →
RuntimeError(E406)with agent name, retry count, and source location
- "No flow found" →
- SLANG Playground — interactive web playground for writing and testing SLANG flows
- React 19 + Vite 6 + Tailwind CSS v4 webapp
- Online editor with real-time parsing and error display
- SVG dependency graph visualization with color-coded nodes (ready/blocked/deadlocked)
- AST viewer with JSON tree
- Live execution with echo adapter and streaming event display
- Example flows dropdown (hello, review, research, broadcast, deadlock)
- CLI:
slang playground [--port N]— launches the dev server (default port 5174)
- New exports:
parseWithRecovery,ParseResult,SlangError,SlangErrorCode,formatErrorMessage,RuntimeError - 21 new tests for error system and parser recovery (175 total)
- CLI:
--toolsflag — load tool handlers from an external JS/TS fileslang run flow.slang --adapter openrouter --tools tools.js- The file must default-export an object
{ name: asyncHandler }— each handler is(args) => Promise<string> - Dynamic import via
pathToFileURLfor cross-platform compatibility - Loaded tools are logged at startup and passed to the runtime
- Example tool handlers file:
examples/tools.js(stubs forweb_searchandcode_exec) - CLI displays
tool_callandtool_resultevents during execution
- OpenRouter Adapter —
createOpenRouterAdapter()for access to 300+ models via OpenRouter with a single API key- Supports
siteUrlandappNameoptions for OpenRouter analytics OpenRouterAdapterConfigtype exported from public API
- Supports
- CLI:
--adapter openrouteroption; falls back toOPENROUTER_API_KEYenv var - MCP server:
openrouteradapter option inrun_flowtool andSLANG_ADAPTERenv var - README: CLI vs Zero-Setup feature comparison table
- Checkpoint & Resume — persist
FlowStateafter each round for crash recoverycheckpointcallback inRuntimeOptions— called with a deep-cloned snapshot after each round and on terminationresumeFrominRuntimeOptions— resume a flow from a previously saved stateserializeFlowState()/deserializeFlowState()helpers for JSON-safeMapserialization- New
checkpointruntime event
- Functional Tools — agent
tools:declarations become executabletoolsrecord inRuntimeOptions— user-provided tool handler functions- Tool call loop in
executeStake: LLM requests a tool viaTOOL_CALL: name(args), runtime executes the handler, feeds result back, LLM continues - Only tools declared in agent meta and provided in runtime options are available (intersection)
- Safety limit of 10 tool calls per stake operation
- New
tool_callandtool_resultruntime events
ToolHandlertype exported from public API- MCP server logs tool_call, tool_result, and checkpoint events
- CLI version updated to 0.3.0
- Zero-setup prompt rule 13 for tools
- Retry & Error Handling —
retry: Nin agent metadata with exponential backoff - Structured Output Contracts —
output: { field: "type" }on stake operations - Extended Static Analysis —
analyzeFlow()checks for missing converge, budget, unknown recipients/sources, uncommitted agents agent_retryruntime eventFlowDiagnostictype withlevel+messagecheck_flowMCP tool now returns extended diagnostics
- Initial release of SLANG — Super Language for Agent Negotiation & Governance
- Three core primitives:
stake,await,commit/escalate - Agents with
role:,model:, andtools:metadata - Inline and block conditionals (
if,when) - Flow-level
converge when:andbudget:constraints importfor flow composition- Special recipients:
@out,@all,@Human - Agent state access via dot notation (
@Agent.output,@Agent.committed) - Flow state variables:
committed_count,all_committed,round,tokens_used - CLI with
run,parse,check,promptsubcommands - LLM adapters: MCP Sampling (default in MCP mode), OpenAI, Anthropic, Echo (testing)
- Custom base URL support for Ollama and OpenAI-compatible endpoints
- MCP server (
slang-mcp) with 4 tools:run_flow,parse_flow,check_flow,get_zero_setup_prompt - Zero-setup mode — system prompt for paste-into-any-LLM interpretation
- Static deadlock detection via DFS on the dependency graph
- Public TypeScript/ESM + CJS library with full type definitions
- Example flows: hello world, writer/reviewer loop, competitive research
- Formal EBNF grammar (
GRAMMAR.md) - Language specification (
SPEC.md)