cd /news/ai-agents/maki-the-efficient-coder · home topics ai-agents article
[ARTICLE · art-136721] src=maki.sh ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

Maki, the efficient coder

Maki, a Rust-based coding agent, parses 15 languages into structural skeletons via tree-sitter, costing 59 tokens per turn while saving 224 tokens on reads, according to the project's documentation. Maki also runs a sandboxed Python interpreter where tools are async functions, and hides Datadog's MCP server's more than 100 tool definitions behind a single search tool that loads only what the model requests. The agent ships as a native binary with a 60 FPS Rust TUI, a Lua plugin API, and tree-sitter-parsed bash permissions that flag both git and rm in chained commands.

read4 min views2 publishedSep 22, 2026
Maki, the efficient coder
Image: source

Where tokens go #

index Parses 15 languages into skeletons: imports, type defs, function signatures with their line ranges.

Costs 59 tok/turn, saves 224 on reads. Reads were ~65% of my tokens, so this one is big.

code_execution A sandboxed Python interpreter where every tool is an async function.

The model gathers 50 reads, greps them, prints the 3 lines that matter. The rest never touches your context.

tool_search Datadog's MCP server has over 100 tools. Every definition sits in your context on every request, used or not.

Maki hides them behind one search tool and loads what the model asks for.

task

The model picks weak, medium, or strong for each subagent. Haiku-tier for grep-heavy research, opus-tier for architecture.

You get a summary, not the transcript.

compaction

Long sessions get compacted: images and thinking blocks go first, then old turns get summarized.

The system prompt and tool descriptions are short too.

index: read less, know more #

Instead of reading full files, index parses with tree-sitter and returns a compact skeleton.

The model sees the structure, then reads only the lines it needs.

main.rs hover to restore

use std::fs;use clap::Parser;use color_eyre::Result; #[derive(Parser)]struct Args {    paths: Vec<PathBuf>,    #[arg(short, long)]    lines: bool,} fn count_words(text: &str) -> usize {    text.split_whitespace().count()} fn count_lines(text: &str) -> usize {    text.lines().count()} fn main() -> Result<()> {    let args = Args::parse();    for path in &args.paths {        let text = fs::read_to_string(path)?;        let n = if args.lines {            count_lines(&text)        } else {            count_words(&text)        };        println!("{}: {n}", path.display());    }    Ok(())}

maki index main.rs skeleton

imports: [1-3]
  clap::Parser, color_eyre::Result, std::fs

types:
  #[derive(Parser)]
  struct Args [5-9]
    paths: Vec<PathBuf>
    lines: bool

fns:
  count_words(text: &str) -> usize [11-13]
  count_lines(text: &str) -> usize [15-17]
  main() -> Result<()> [19-29]

code_execution: think inside the sandbox #

Tools are exposed as async Python functions.

The model writes a script, runs it sandboxed, and only the print() output enters your context.

script python

files = await glob(pattern='src/**/*.ts')
srcs = await asyncio.gather(
    *[read(path=f) for f in files]
)

exports = {}
imports = set()
for f, src in zip(files, srcs):
    for m in re.finditer(r'^export \w+ (\w+)', src, re.M):
        exports[m.group(1)] = f
    for m in re.finditer(r'import\s*\{([^}]+)\}', src):
        imports.update(n.strip() for n in m.group(1).split(','))

for name, f in exports.items():
    if name not in imports:
        print(f'{f}  {name}')

output 3 lines

src/lib/csv.ts       parseCsvLegacysrc/auth/jwt.ts      signV1src/utils/phone.ts   formatE164

What you get #

Lua plugins Extend maki in Lua with a Neovim-style plugin API: add tools, slash commands, keymaps, and UI.

Anything maki does out of the box, your plugins can do too.

Rust TUI, 60 FPS

Native binary. No javascript runtime, no react. Even the splash screen animation uses SIMD.

Syntax highlighting runs on a background thread pool so it never blocks your input.

Full visibility

Philosophy: don't hide anything. Token count, cost, and model are always in the status bar.

Each subagent gets its own chat window you can flip through with /tasks (Ctrl-X). Ctrl-F for fuzzy search.

/btw runs a side query without touching the current session. ! runs shell commands, !! runs them silently.

Sensible permissions

Bash commands are parsed with tree-sitter so maki knows what's actually being run.

git diff && rm -rf / correctly flags both git and rm. Most agents only see git. Handles subshells, command substitution, pipes.

Per-tool allow/deny rules, or --yolo to skip it all.

Also in there: parallel sessions you can switch away from, long-term memory, double-Escape to rewind, plan mode, MCP over stdio or HTTP, skills, ACP, opt-in OpenTelemetry, 26 themes, image paste, and --print for headless.

Lua plugins: hackable all the way down #

Every built-in tool, read, bash, edit, even batch, is itself a Lua plugin. Read them in ./plugins.

The API mirrors Neovim (maki.fs, maki.uv, maki.keymap, maki.treesitter), so it feels familiar.

Drop a file in ~/.config/maki/plugins/ to add tools, slash commands, keymaps, or UI.

add a ci_status tool: the model checks CI itself

maki.api.register_tool({
  name = "ci_status",
  description = "Latest CI run for this branch",
  schema = { type = "object", properties = {} },
  handler = function()
    local res, err = maki.net.request(
      "https://ci.internal/runs/json?branch=main")
    if err then
      return { llm_output = err, is_error = true }
    end
    local buf = maki.ui.buf()
    buf:lines(maki.ui.highlight(res.body, "json"))
    return { llm_output = res.body, body = buf }
  end,
})

add /standup: show yesterday's commits

maki.api.register_command({
  name = "/standup",
  description = "Yesterday's commits",
  handler = function()
    local buf = maki.ui.buf()
    local win = maki.ui.open_win(buf, { title = "standup" })
    maki.fn.jobstart(
      "git log --since=yesterday --oneline", {
        on_stdout = function(_, line) buf:line(line) end,
      })
    repeat
      local ev = win:recv()
    until not ev or ev.key == "esc"
    win:close()
  end,
})

And yes... it can even run DOOM!

── more in #ai-agents 4 stories · sorted by recency
── more on @maki 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/maki-the-efficient-c…] indexed:0 read:4min 2026-09-22 ·