a language for agents

mesh is a flow-based programming language designed from the ground up for ai agents. no variables, no state, no boilerplate. just pipes and tools.

example.mesh
# fetch data, transform, output

http.get "https://api.github.com/repos/pokelabshq/council/commits"
   json.parse
   .[0:5]
   for each commit:
      format "{{.sha}} — {{.commit.message}}"
   print

features.

everything you need to write agent workflows, nothing you don't.

no state

no variables, no assignment, no mutation. data flows through pipes from left to right. what you read is what executes.

tool-native

every operation is a tool call. built-in and external tools are the same. http.get, json.parse, sentiment.analyze — all tools.

errors are data

failures don't crash the pipeline. they flow through as values. catch them with on_error:, retry with retry 3.

parallel by default

independent operations run concurrently. parallel: blocks with named branches. merge to combine results.

agent-readable

syntax is close to natural language. agents can read, write, and generate mesh without special prompting or training.

self-describing

every mesh program documents itself. the code reads like the spec. no separate documentation needed.

syntax.

here's everything mesh can do. each example is real, runnable code.

basic pipeline
# the core of mesh: pipes

http.get "https://api.example.com/data"
   json.parse
   .items[:5]
   sort by: .name
   print
data access
# access fields, index, slice

.http.get "..."  json.parse
   .users[0]        # first
   .name               # field
   format "hello {{.}}"

# slicing works everywhere
.items[0:10]             # first 10
.items[-5:]               # last 5
conditionals + error handling
# if / then / else
check http.get "https://example.com/health"
   if .status != 200:
      log "error" "down: {{.status}}"
   else:
      log "info" "healthy"

# retry + error handling
retry 3, backoff 2s:
  http.get "https://flaky.example.com"
 on_error:
    log "failed after 3 retries"    return {ok: false}
parallel + loops
# parallel branches
parallel:
  branch users:
    http.get "url/users"  json.parse
  branch posts:
    http.get "url/posts"  json.parse
 merge
 print

# for each
.items
   for each .items:
      format "{{.name}}: {{.value}}"
       print
tool definition
# define reusable tools
tool sentiment:
  description: "analyze text sentiment"
  input:
    text: string
  output:
    score: float
    label: string
  steps:
    http.post "http://localhost:8764/api/analyze"
      body: {text: input.text}
     json.parse
     format "{{.score}} ({{.label}})"
composition
# import and compose
import "./tools/social.mesh"

# real-world: daily digest
parallel:
  branch commits:
    github.commits "pokelabshq/council"
      .since:"1d"
  branch stars:
    github.stars "pokelabshq/council"
 merge  summarize
 telegram.send "@thealxlabs"

tools.

47 built-in tools across 9 categories. everything is a tool — there's no special syntax for "built-in" vs "external".

tooldescriptionexample
io
printprint data to stdout→ print
loglog message with level→ log level="info" "msg"
formatformat data with template→ format "hi {{.name}}"
savesave to json file→ save path="out.json"
loadload from json fileload "data.json"
returnreturn data unchanged→ return
collections
filterfilter by truthinesslist → filter
mapextract field from dictslist → map "name"
sortsort listlist → sort by="date"
uniquededuplicatelist → unique
flattenflatten nested lists[[1,2],[3]] → flatten
groupgroup by fieldlist → group by="type"
taketake first nlist → take 5
skipskip first nlist → skip 10
countcount itemslist → count
firstfirst itemlist → first
lastlast itemlist → last
lengthlength of collection→ length
keysdict keys{d} → keys
valuesdict values{d} → values
mergemerge parallel results→ merge
json
json.parseparse json string'{"a":1}' → json.parse
json.stringifyserialize to json{data} → json.stringify
http
http.getget with auth/headers/params"http://..." → http.get bearer="tok"
http.postpost with body"http://..." → http.post body={}
http.putput request"http://..." → http.put body={}
http.patchpatch request"http://..." → http.patch body={}
http.deletedelete request"http://..." → http.delete
string
upperuppercase"hi" → upper
lowerlowercase"HI" → lower
trimtrim whitespace→ trim
replacereplace substring→ replace old="a" new="b"
splitsplit by delimiter→ split by=","
joinjoin with delimiter→ join with=", "
containscheck substring→ contains "needle"
math
addadd numbers5 → add 3
subsubtract5 → sub 2
mulmultiply5 → mul 3
divdivide6 → div 2
type
typeget type name42 → type
stringto string42 → string
numberto number"42" → number
system
shellrun shell commandshell "ls -la"
envread env varenv "API_KEY"
nowcurrent timestamp→ now
uuidgenerate uuid→ uuid
waitsleep secondswait 5
import
importload mesh moduleimport "tools.mesh"
tooldefine custom tooltool name: steps: ...

patterns.

common patterns for real-world agent workflows. copy, modify, ship.

service monitor

health checks · alerting · retry
monitor.mesh
loop every 60s:
  check http.get "https://pokelabs.org/health"
     timeout 10s
     retry 2:
        http.get
     if .status != 200:
        parallel:
          branch alert:
            telegram.send "@thealxlabs" "⚠️ pokelabs.org is down ({{.status}})"
          branch log:
            log.error "health check failed: {{.status}}"
     else:
        log "pokelabs.org healthy ({{.response_time}}ms)"

data pipeline

fetch · transform · output
pipeline.mesh
http.get "https://api.example.com/users"
   json.parse
   .users
   sort by: .created_at
   take 20
   for each .users:
      format "{{.name}} ({{.email}}) — {{.role}}"
   print
   save "report.json"

daily digest

parallel · merge · format · notify
digest.mesh
parallel:
  branch commits:
    http.get "api.github.com/repos/pokelabshq/council/commits"
       json.parse  take 5
  branch issues:
    http.get "api.github.com/repos/pokelabshq/council/issues"
       json.parse  count
 merge
 format "📊 daily: {{.commits | count}} commits, {{.issues | count}} open issues"
 telegram.send "@thealxlabs"

playground.

try mesh in your browser. runs entirely client-side via the mesh js runtime.

mesh v0.3
input.mesh
output
// click run to execute
ready

why not yaml?.

mesh vs other approaches for agent workflows.

yaml workflow
name: ci
on: push
jobs:
  build:
    runs-on: ubuntu
    steps:
      - uses: actions/checkout@v4
      - run: npm test
      - name: deploy
        if: success()
        run: ./deploy.sh
mesh
check shell "npm test"
  → if .code == 0:
      shell "./deploy.sh"
      → on_error:
          log "deploy failed"
          telegram.send "@ops" "deploy failed"
featureyaml workflowspython scriptsmesh
agent-readable
tool-native⚠️
error handling
parallelism
composable
observable
no boilerplate
agent-writable⚠️

get started.

up and running in 60 seconds.

terminal
# install
$ git clone https://github.com/pokelabshq/mesh.git
$ cd mesh

# try the repl
$ python3 mesh.py --repl
mesh> "hello"print
hello

# run a file
$ python3 mesh.py examples/hello.mesh

# check syntax
$ python3 mesh.py --check myfile.mesh

# list all tools (47 across 9 categories)
$ python3 mesh.py --tools

# start the execution server
$ python3 meshd.py --port 8080

# run via http
$ curl -X POST http://localhost:8080/run \
    -H "Content-Type: application/json" \
    -d '{"source": "\"hello\" → upper"}'

# start the MCP server (for Cursor, Claude Code)
$ python3 mesh_mcp.py