Skip to main content

A declarative language for LLM-driven state machines (reference interpreter).

Project description

mklang

CI Docs License

A declarative language for LLM-driven state machines. A .mk file (mk = machine) describes an agent as a set of states; an LLM is the runtime that executes generative steps. The document is the program; the host supplies the interpreter, optional tools, and optional code-hook gates.

mklang : LangGraph  ::  a declarative spec : Python code

The idea

Each state has four faces:

Face Answers Example
structure what shape? "The output is an email reply, max 150 words"
prompt what to think? "Write a reply to {{ticket.body}}…"
execution how to act? "Do not invent policies not in the KB facts"
gates when to exit? see below

Real side effects (search, send, calc) are tool: states — host callables, not prose in execution. See examples/react.mk and examples/triage.mk.

The output of a state is stored in the shared context under its output: key, so later states read it via {{key}}. Four optional faces unlock richer reasoning: reason (traced chain-of-thought), accumulate (append to a list), fan-out (sample: N / over: {{list}}), and call (run another machine) — see Reasoning architectures.

Gates are the transitions. A state's gates list is its transition table: each gate is a natural-language condition the LLM judges, plus what happens next.

gates:
  - when: the reply resolves the request and is in the required tone
    then: ok
    to: send
  - when: information from the KB is missing
    repair: 2 # re-run this state with feedback, up to 2 times
    to: gather
  - when: the request needs a human
    escalate: true
    to: human_review

Policies: ok (advance), repair(N) (self-correct with feedback), escalate (route to a handler), fail (abort). A global step budget prevents runaway loops.

Design commitments

  • Document-first — readable without the interpreter; prose-first for the common path. Production machines still need developer judgment for tools, hooks, and untrusted inputs (see SPEC threat model).
  • LLM-as-runtime — non-deterministic by design; gates (prose + optional code hooks + budgets + trace) are the reliability mechanism. Prose-gate accuracy is an empirical claim, not a free lunch.
  • Prose, not typesstructure and gate conditions are natural language, judged by the LLM at runtime; optional hook: gates add host bool checks.
  • Provider-agnostic — a .mk never names a provider or model. States route by capability tier (fast / balanced / reasoning); the runtime maps each tier to a concrete model. Portability of the document is syntactic; whether different providers fire the same gates on the same run is measurable (see scripts/gate_divergence.py).
  • Spec + conformance — an implementation-neutral conformance suite pins interpreter semantics so a second runtime can match the language contract.
  • Language-agnostic runtime — the spec assumes only "some host with an LLM".

Files

Runtime configuration

The .mk picks a tier; a host-side config picks the model. This is the whole of "make it multi-provider":

active: deepseek # deepseek | anthropic | openai | google | openrouter | xai | mistral | local
providers:
  deepseek:
    base_url: https://api.deepseek.com
    tiers:
      {
        fast: deepseek-chat,
        balanced: deepseek-chat,
        reasoning: deepseek-reasoner,
      }
  anthropic:
    tiers:
      {
        fast: claude-haiku-4-5,
        balanced: claude-sonnet-5,
        reasoning: claude-opus-4-8,
      }
  local:
    base_url: http://localhost:11434/v1
    tiers: { fast: qwen3:8b, balanced: qwen3:32b, reasoning: deepseek-r1:70b }

The example config defaults to DeepSeek (the path we live-test against). Flip active: anthropic (or openai / local / …) and every example runs unchanged. Blocks ship for Anthropic, OpenAI, Google, DeepSeek, OpenRouter, xAI (Grok), Mistral, and local (Ollama/vLLM) — every non-Anthropic one is OpenAI-compatible, so a single adapter serves them all. OpenRouter is a meta-provider: its vendor/model ids let each tier target a different vendor through one endpoint. Per-tier params (Anthropic adaptive-thinking + effort, OpenAI/xAI reasoning_effort, …) live under params. Full map: config/runtime.example.yaml.

Reasoning architectures

Every modern reasoning/agentic pattern maps onto the core (states + gates + prose + tiers + the optional faces). Full skeletons in SPEC.md §10; operating guidance in docs/patterns.md.

Architecture mklang constructs
Chain-of-Thought reason: true
ReAct think → tool state (host callable) → observation accumulated
Reflexion / self-refine produce → self-judge gate → repair
Self-consistency sample: N → reducer state (majority)
Tree-of-Thought sample: k → score/select reducer → loop (depth via budget)
Plan-and-Execute planner (list) → over: {{steps}} → reducer
Debate / ensemble over: {{personas}} → synthesizer
Map-Reduce over: {{chunks}} → reducer
Router-of-experts classify → call specialists
Speculative cascade tier: fast draft → escalatetier: reasoning
Exact policy checks gate hook: host (ctx, output) -> bool (no LLM)

Install

pip install mklang

Editor validation for .mk files works out of the box via the JSON Schema — point yaml-language-server at https://raw.githubusercontent.com/gianlucamazza/mklang/main/schema/mklang.schema.json.

Quickstart (reference interpreter)

cp .env.example .env            # set DEEPSEEK_API_KEY=… (or another provider key)
uv run mklang check examples/self_consistency.mk
uv run mklang lint examples/self_consistency.mk   # + static analysis
uv run mklang run examples/self_consistency.mk \
  --set question.text="What is the capital of Australia?"
# default provider is deepseek; override with --provider anthropic|openai|…

# pause on budget, resume later (exit code 3 = suspended):
uv run mklang run examples/self_consistency.mk --max-tokens 300 --checkpoint ck.json
uv run mklang resume ck.json --max-tokens 5000

# human-in-the-loop: escalate gates suspend; resume with the human decision:
uv run mklang run examples/expense_approval.mk --checkpoint ck.json --hitl
uv run mklang resume ck.json --set human.reply="approved, cost center 42"

The .mk picks tiers; config/runtime.example.yaml maps them to models (active: deepseek by default); the key comes from .env. Same machine, any provider.

Test your machine without API keys

mklang test runs your machine against a script of named scenarios with a scripted LLM (produce texts, judge picks) and scripted tools/hooks — fully deterministic, no provider or key. It pins the paths you care about before you spend a token on a live run.

uv run mklang test examples/triage.mk --script examples/triage.test.yaml
# PASS happy-path
# PASS kb-empty-escalates

Each scenario declares a scripted llm:/tools:/hooks: and an expect: (status, error, result, at, trace skeleton, context keys) — the same case format the conformance suite uses. A mismatch prints a minimal diff (the first differing key, expected vs actual) and exits 1. See examples/triage.test.yaml.

Status

Language v0.2 / package 0.5.4 — core complete: states + gates + prose, tiers, reason / accumulate / fan-out / call / tool states / code-hook gates; multi-provider interpreter with entry-point plugins (tools, hooks, providers); resumable checkpoints (mklang resume, ADR 0007); human-in-the-loop (--hitl, ADR 0008); mklang check / lint / test (scripted scenarios, no API keys); implementation-neutral conformance suite (ADR 0009). Gate judging follows the state tier by default; see CHANGELOG 0.5.2 for the observable change and 0.5.3 for authoring tooling.

  • Live: DeepSeek (default) and OpenAI green (2026-07-16), including examples on the current OpenAI tier map (fast: gpt-5.4-mini, balanced/reasoning: gpt-5.5 — latest chat-completions models on this account; gpt-5.5-pro is Responses-API only and not mapped). Anthropic unit-tested; live blocked by provider billing. Gate-divergence (deepseek×openai): agreement 1.0 — see docs/experiments/gate-divergence.md.
  • Release policy: DeepSeek + OpenAI smoke and three-run gate agreement are blocking; other configured providers are reported without blocking. PyPI publication uses GitHub OIDC Trusted Publishing from the release workflow.
  • Open: Anthropic live once the account has credit; accept/implement ADR 0011 (MCP) and then ADR 0010 (LLM lint) when ready.
  • Roadmap and full release notes: ROADMAP.md, CHANGELOG.md.

License

Apache-2.0. Contributions welcome — see CONTRIBUTING.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mklang-0.5.4.tar.gz (166.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mklang-0.5.4-py3-none-any.whl (50.5 kB view details)

Uploaded Python 3

File details

Details for the file mklang-0.5.4.tar.gz.

File metadata

  • Download URL: mklang-0.5.4.tar.gz
  • Upload date:
  • Size: 166.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mklang-0.5.4.tar.gz
Algorithm Hash digest
SHA256 dfd6d814871a5b988fe205e6eb29badbdad9a3053d7f1a6661cfcdb87cbf1054
MD5 a23c344894ec5332c5f2a35b3750368c
BLAKE2b-256 42e56a280bdee081acf636cb09220678f657636287bd30fdd079515545a06630

See more details on using hashes here.

Provenance

The following attestation bundles were made for mklang-0.5.4.tar.gz:

Publisher: release.yml on gianlucamazza/mklang

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mklang-0.5.4-py3-none-any.whl.

File metadata

  • Download URL: mklang-0.5.4-py3-none-any.whl
  • Upload date:
  • Size: 50.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mklang-0.5.4-py3-none-any.whl
Algorithm Hash digest
SHA256 6e9e31c2c30d3421d27e6f958b9d3ef2231a8d8bdb33c9c197a5e76a22f53deb
MD5 e86fcb2a1f7050ad230640bdbedc70af
BLAKE2b-256 a4a982ee7ebad0e301e152d35c9d5d320b30a6849754a19c392350df93c4ff7a

See more details on using hashes here.

Provenance

The following attestation bundles were made for mklang-0.5.4-py3-none-any.whl:

Publisher: release.yml on gianlucamazza/mklang

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page