DEV Community

Cover image for From Python to Go: rewriting a CrewAI workflow in pure stdlib
Rodolpho Sa
Rodolpho Sa

Posted on

From Python to Go: rewriting a CrewAI workflow in pure stdlib

In the CrewAI Python framework you assemble teams of agents that collaborate via LLMs. It’s a great model when tasks require multiple specialists. But pulling in litellm, langchain, pydantic and friends makes cold starts heavy and deployment a container story.

A few months ago I started crewai-go, an idiomatic Go port with zero external dependencies. The whole core package is pure net/http, encoding/json, log/slog and friends.

This post walks through a minimal port of the canonical CrewAI “research → write” example, side-by-side with the Python version.

Python (CrewAI)

from crewai import Agent, Crew, Process, Task

researcher = Agent(
    role="Senior Researcher",
    goal="Uncover the best practices in concurrency",
    backstory="You are a veteran engineer with deep distributed-systems chops.",
)

writer = Agent(
    role="Tech Writer",
    goal="Write a concise summary",
    backstory="You turn research into tight prose.",
)

research = Task(description="Research Go concurrency best practices",
                expected_output="Bullet list of 5 best practices", agent=researcher)
write    = Task(description="Write a 1-paragraph summary from the research",
                expected_output="A single paragraph", agent=writer)

crew = Crew(agents=[researcher, writer], tasks=[research, write],
            process=Process.sequential)
print(crew.kickoff().final)
Enter fullscreen mode Exit fullscreen mode

Go (crewai-go)

package main

import (
    "context"
    "fmt"

    "github.com/rhgs/crewai-go"
    "github.com/rhgs/crewai-go/llm/openai"
)

func main() {
    llm := openai.New("gpt-4o-mini") // uses OPENAI_API_KEY
    researcher := crewai.NewAgent(
        "Senior Researcher",
        "Uncover the best practices in concurrency",
        "You are a veteran engineer with deep distributed-systems chops.",
        llm,
    )
    writer := crewai.NewAgent(
        "Tech Writer",
        "Write a concise summary",
        "You turn research into tight prose.",
        llm,
    )

    research := crewai.NewTask(
        "Research Go concurrency best practices",
        "Bullet list of 5 best practices",
        researcher,
    )
    write := crewai.NewTask(
        "Write a 1-paragraph summary from the research",
        "A single paragraph",
        writer,
    ).WithContext(research) // explicit dependency, like CrewAI’s context

    crew := crewai.NewCrew([]*crewai.Agent{researcher, writer},
                           []*crewai.Task{research, write})
    out, _ := crew.Kickoff(context.Background(), nil)
    fmt.Println(out.Final)
}
Enter fullscreen mode Exit fullscreen mode
  • Same surface, different runtime
  • Same concepts: Agent, Task, Crew, Process.
  • Sequential, Hierarchical and Staged processes (stages run in sequence; tasks within a stage run concurrently).
  • Agentic loop (opt-in Plan–Execute–Evaluate–Refine) with an independent evaluator and bounded refinements.
  • Web search, structured output with JSON Schema repair loop, guardrails, facts & provenance — all of it built on stdlib only.

Why port it?

  • Single binary (GOOS=linux GOARCH=arm64 go build from your laptop).
  • Millisecond cold start, ~10–20 MB memory footprint.
  • Thread-safe end-to-end; CI runs go test -race.
  • ~94% test coverage, hard 90% gate.

Try it

git clone https://github.com/rhgs/crewai-go
cd crewai-go
export OPENAI_API_KEY=sk-...
go run ./examples/sequential
Enter fullscreen mode Exit fullscreen mode

There’s also examples/agentic_loop which runs fully offline with a mock LLM — no API key needed.

If you’re a Go developer working on LLM orchestration, give it a star, file an issue, or open a PR. The CONTRIBUTING guide is bilingual (English + Brazilian Portuguese) and the PR checklist is short.

Repo: https://github.com/rhgs/crewai-go v0.4.0 release: https://github.com/rhgs/crewai-go/releases/tag/v0.4.0

Happy hacking.

Top comments (1)

Collapse
 
freerave profile image
freerave

Really interesting approach, especially the staged execution model.

One thing I'm curious about: go test -race gives you confidence against memory-level data races, but how are you handling semantic races when multiple tasks inside a stage run concurrently?

For example, if two agents produce facts or context that later get merged into the next stage, can completion order affect the final prompt/state?

Did you make stage outputs immutable and merge them deterministically, or is ordering deliberately part of the orchestration semantics?