mdlang
Documentation

Start here

Getting started

Five commands from an empty project to a typed action you can call. The only thing you have to decide up front is which model provider to use.

Install

mdlang keeps @langchain/core and zod as peer dependencies so there is exactly one copy shared with your model provider. Install them alongside it.

npm install mdlang @langchain/core zod

Then add any LangChain-compatible chat model. Any of these work, and swapping between them later is a one-line change:

npm install @langchain/openai# or @langchain/anthropic, @langchain/google-genai, @langchain/aws, …

Scaffold the project

init writes three things: a config file, a system prompt, and one example action.

npx mdlang init
.├── mdlang.config.ts        model, MCP servers, custom tools, paths, logging├── MDLANG.md               system prompt prepended to every action└── actions/    └── example.md          one action = one markdown file

Open mdlang.config.ts and set your model. Everything else has a working default.

mdlang.config.ts
import { defineConfig } from "mdlang/config";import { ChatOpenAI } from "@langchain/openai"; export default defineConfig({  model: new ChatOpenAI({ model: "gpt-4o-mini" }),});

Write an action

An action is one Markdown file. The frontmatter is the contract — name, arguments, output shape, and the tools the agent may call. The body is the instruction the agent receives.

Replace the scaffolded example with something you actually need. These docs use one action throughout — create-user, which validates a signup, hashes a password, and writes a row.

actions/create-user.md
---name: create-userdescription: Create a user account.args:  - name: email    type: string    required: true    description: The new account's email address.  - name: plan    type: string    default: freeoutput:  type: object  items:    - name: id      type: string      description: The new user's id.---Create the user and return their id in the `id` field.

Generate the client

Codegen reads every action, connects to any MCP servers you configured, and verifies that each tool an action names actually exists. Actions referencing an unknown server or tool are skipped with a warning rather than shipped broken.

npx mdlang generate

This writes actions/generated/. Commit it or add it to .gitignore and regenerate in CI — either works, as long as generate runs after any change to an action, to MDLANG.md, or to your config’s tool registry.

Call it

import { action } from "./actions/generated/index.js"; const { id } = await action("create-user", { email: "ada@example.com" });//      ^? string

The result type comes from the action’s frontmatter. Passing an argument that doesn’t match the declared schema throws before the model is called.

Where to go next

  • How it works — what each stage reads and emits, and why the generated client survives bundling.
  • Action file format — every frontmatter field and what it compiles into.
  • Configuration — MCP servers, custom tools, and logging.