Building a Local Content Crew with CrewAI

A two-agent CrewAI pipeline that turns an article and my rough thoughts into a LinkedIn post in my voice, running entirely on local hardware. The build was straightforward. Teaching a local model to sound like me is the part I'm still working on.

Diagram of a local content pipeline: article and notes into OpenClaw, into a two-agent crew with voice documents attached, back out for review, then n8n

I read a lot of articles worth reacting to and post about a fraction of them. The bottleneck was never having an opinion. It was the drafting time between the opinion and the post.

So I extended my OpenClaw agent. I send it a webpage and a few rough thoughts over Telegram. It pulls the key details from the page, weaves in my take, and hands a rough draft to a CrewAI crew. The crew reshapes it against two documents I wrote: my brand guidelines, and a tone of voice reference built from my old blogs and posts. A draft comes back for me to review and update, then it goes out through an MCP connection to my n8n server, which publishes to LinkedIn.

Everything runs locally on the Mac Studio. Ollama hosting Gemma, no API keys, no cloud calls, no per-token bill.

[Visual: left to right flow diagram, article and notes into OpenClaw, into the crew with the two voice documents attached, out to review, then n8n]

How the crew works

CrewAI is an orchestration layer. You define agents, each with a role, a goal, and a backstory, then define tasks and run them in sequence, each agent’s output feeding the next.

Mine is a desk of two. A strategist reads the source material and my notes and produces a structured brief. A copywriter turns that brief into a post, with the brand guidelines and tone reference injected into its context at runtime. The voice documents are plain markdown under version control, so when something needs adjusting I edit a file, not a model.

The first problem was timeouts

The error read: “The model did not produce a response before the model idle timeout.” My first instinct was that something in the crew pipeline was hanging. It wasn’t. The error was coming from Ollama itself.

The root cause is obvious in hindsight. OpenClaw uses the local Ollama instance as its own LLM, and Ollama has a default idle timeout. When the model was under load, long context, complex tool call reasoning, it was hitting that limit before returning a response. Nothing was broken. A local model doing real work just takes time, and the defaults weren’t built for it.

The fix was config, not code. One line in openclaw.json:

"ollama": {
  "timeoutSeconds": 300
}

That tells OpenClaw to wait up to five minutes for a single Ollama response. The crew pipeline has its own separate timeout: the MCP bridge script gives its HTTP call to the FastAPI service eleven minutes to complete. The two settings cover different legs of the journey. One is OpenClaw waiting for its own model to think. The other is the bridge waiting for the whole crew to finish writing.

If you’re chaining local models through multiple services, a timeout will find you eventually.

Turns out the handling of timeouts is a common case. For the times when neither is quite enough, I added a check post command. When a generation is running, OpenClaw returns a task ID. I can query it later when I’m ready. The task is held in memory during the process, nothing persisted to a database or cache. I could build that, but it would solve a problem I don’t really have. I’m not in any rush. The point of running this locally is that it runs on my schedule, not the other way around.

The harder problem is the voice

The pipeline works. The part I’m still working on is the documents that drive it.

It can be really hard to give instructions to an external model that is trying to be you. So much of what you write is situational and at times emotional, and to inject that spontaneity into text as a ‘weight’ is not an easy thing to articulate. The brand guidelines were the easy part. Rules are easy. But a tone of voice document that gives a local model enough of a steer to genuinely sound like you needs far more thought and testing than I expected going in.

This surprised me. I assumed that with my old posts as reference material, the voice would mostly transfer. It doesn’t, not on its own. The document carries more of the load than the examples do, and getting it right is an iterative process I don’t think I’ve finished.

Final thoughts

The build itself was the easy part. A weekend of wiring, one timeout hunt, and the pipeline has been stable since. If you’re considering something similar: two agents in sequence did everything I needed, and the timeout lesson above will save you an evening.

The voice problem is the real project, and it’s still open. Every post that comes back is a test of the documents, and every edit I make before approving is data about what they’re missing. I’ll write that up properly once I understand it better. For now the honest status is: the plumbing is solved, the voice is not, and the second one is the interesting one.

Want something explained?

Tell me what you're stuck on. I take requests, and the good ones end up as a video.