DEV Community

Dominik
Dominik

Posted on AI-assisted

I wanted Claude to delegate to a local model. That became MAF.

I started building MAF because I wanted to make AI more reliable and spend less on it.

My idea was simple: use a paid claude based model for complex reasoning, planning, and judgment, then use a local model for implementation work. Keep the expensive model involved where it helps and use the local model for work it can handle.

At the time, I couldn't find an option that fit my workflow easily. My experiments with local models were also disappointing. Simple, well-explained tasks worked, but tool calls or longer agentic workflows would overflow the context window.

I started using Claude Code, but I still wanted to use a local model through Ollama and OpenCode for some side tasks.

I tried several approaches: first subagents, then skill bridges that told Claude Code how to delegate simple tasks to OpenCode. Automatic communication between the two harnesses—the tools running the agents—was unreliable or used too many Claude tokens.

I was making progress, though. I worked out a process where Claude Code wrote a task file with instructions for OpenCode to implement. I still had to point OpenCode to those files myself.

The shared-board idea came from a conversation at EuRuKo with Maciej Mensfeld. He described his own agentic workflow and how he isolated agents with Coi (Code on Incus), a tool that runs coding agents inside isolated Incus system containers. He also mentioned agents coordinating through a Kanban-like task service.

What stuck with me was the idea of agents using a task board to communicate. I wanted something similar, but local: no external task service and no web requests just to coordinate work. The agents could still use cloud models, but their board and messages would live in the project.

That gave me a way to move beyond manually passing task files between agents. It became Multi_Agent_Flow (MAF).

A shared board instead of another agent runtime

MAF is the glue that lets different coding-agent tools coordinate work on one project. It does not replace Claude Code, OpenCode, Codex, or Hermes. Those tools still run the agents, using the model access you configure for each one.

You can use Claude Code with your subscription and OpenCode with a local model, or choose another combination of harnesses and models. MAF does not require the whole team to use the same provider. It comes with predefined roles and workflow examples, but you can define your own.

MAF gives the agents a shared way to coordinate work on one repository:

  • A project-local Taskwarrior board records goals, tasks, and claims.
  • File inboxes carry messages between roles and workers.
  • Git worktrees give workers separate checkouts.
  • Resource locks let workers serialize access to something they share, such as a local model host.

The common interface is the coord CLI. An agent does not need a vendor SDK to read the board or send a message. It needs to run a command.

There is an optional shared-memory layer through graphify and an Obsidian vault. Obsidian makes it easier for you to browse the agents' knowledge.

There is also a web dashboard, which you can start by running .maf/bin/dashboard from the project root. It shows worker status, the task board, and coordination activity. It also includes analysis tools that suggest ways to reduce token usage.

The part I care about most is choosing tools by role. I can keep a cloud model on planning and review while routing scoped implementation work to another harness. MAF provides the coordination; it does not guarantee that a local model will do a task correctly or cheaply.

Roles are responsibilities, not model names

An architect decomposes a goal into tasks. Developers implement them. A tester checks behavior. A reviewer examines the result.

For example, imagine adding CSV export to an app. The architect defines the task and its acceptance criteria. A developer claims it and implements it in a separate worktree. A tester checks the behavior, and a reviewer examines the diff. If something is missing, they send feedback through the inbox instead of relying on me to copy messages between terminals.

A project manager can sit between me and the architect: I describe the outcome, and the project manager creates the goal and reports back. The lead roles do not claim implementation tasks.

A harness is the tool running a role. A worker is a running instance of that role. More than one worker can serve the same role.

This distinction matters because I do not want my project structure to depend on which model I happen to use this month.

For example, this configures a mixed team:

maf add claude:architect opencode:backend-developer claude:reviewer
Enter fullscreen mode Exit fullscreen mode

That command installs the flow and generates the role files. It does not start the agents.

OpenCode is the harness here, not the model. To use it for local implementation, I configure it to use a model served by Ollama.

You aren't limited to the predefined roles. You could define a writer, editor, researcher, or proofreader and assign each one to whichever harness and model fits best. maf role add NAME creates a stub in .maf/roles.yml; you fill in its responsibilities and permissions. You can also write your own workflow in .maf/workflow.md for the architect to follow.

MAF stays out of the project's tracked files

The tool keeps its main installation in .maf/. It uses .git/info/exclude to keep those files out of the clone's normal Git status. The knowledge graph lives separately in graphify-out/.

MAF also installs Git hooks and harness-specific files. Those are real changes to the local environment, even though the tool keeps its setup out of the project's tracked source files. A clean Git status does not mean that nothing changed on disk.

The agents' code and project documentation still go through your normal Git workflow; MAF's local setup stays outside it.

Different ways to run MAF

At first, I ran all my harnesses interactively. That let me see what each agent was doing in its own terminal window and micromanage the process when I needed to.

Now I talk to a single agent in the project manager role. The rest of the team runs in --dispatch mode, in terminals I start myself. The dispatcher waits for tasks or messages and invokes the agent when there is work. You can also ask the project manager to arrange a team with the architect, within the worker limits and allowed harnesses you configure.

One important caveat: dispatch mode bypasses approval prompts for Claude Code, Codex, and Hermes; OpenCode uses the permissions in its role file. Separate worktrees help keep changes apart, but they are not a security sandbox. Only use unattended workers with access you are comfortable granting them.

Try different approaches to see what works for you. I started with interactive sessions because I wanted to watch the coordination before leaving more of it unattended.

Try it on something small

You don't need to start with the whole team. Begin with an architect and one developer, watch how they coordinate, and add other roles when you need them.

You need Ruby 3.0 or later, Git, and Taskwarrior for the coordination layer. For actual agent work, you also need an installed coding-agent harness with the model access it requires. Graphify is optional but recommended for shared knowledge.

gem install maf
maf version
maf guide
Enter fullscreen mode Exit fullscreen mode

You can then open a coding agent in your project and ask:

Run maf guide. Read the output and help me set it up.

MAF is open source on GitHub and published on RubyGems.

You can ask your agent about MAF as you go. It can guide you through adding custom roles or workflows rather than making you learn every command first.

I'd like feedback from people whose workflows differ from mine. If you try MAF, tell me which tools you used and where setup or coordination became confusing. If you encounter a bug, please open an issue with a reproducible example.

Top comments (0)