DEV Community

Paul Scarrone
Paul Scarrone

Posted on

kwike - Agent-to-Agent Orchestration in the Unix Philosophy

I've been building kwike, an LLM-first tool for composing agentic workflows using Unix primitives - pipes, append-only logs, and event subscriptions instead of SDKs and harnesses.

The primary use case here is agentic workflows for specific repeatable actions. What I often call drudgery. Version upgrades, dependency management, or maintaining documentation.

This isn't going to run your business or make you the next 50MM in 12hr dude, but it does allow you to get some boring stuff done while you work on the stuff you like. Its a technical solution for technical problems.

LLM First

One of the features kwike focuses on is training an LLM in its use. While it has a CLI that you can use for non-agentic tooling, building a workflow is telling your LLM of choice - in my case, Claude - "You have access to kwike, an agentic workflow orchestration tool. Read kwike --help and kwike docs. I want to build a workflow that looks something like X. Let me know when you are ready to discuss." Much of what comes next can be constructed without any experience with the tool. It includes debugging tools and static analysis to validate configuration and the workflow DAG.

While setting up a new workflow isn't immediate, rather complex behavior can be recorded and committed with your projects.

Basics

Doc Updater

Deep down this is an agent-to-agent communication protocol through event dispatch and subscription. The tool exposes the following primitives:

  • dispatch (emit events to an event store)
  • consume (pull events subscribed to)
  • daemon (event store owner, can mesh across network boundaries)

The consumer watches for one or more messages defining its own partition and maintains its own read cursor. The daemon in this case acts as a mail server, essentially, and new messages are dispatched with the intent of being reactive in nature. Think of it as allowing system events or another LLM's tool use to spawn a dedicated workflow.

Each workflow step is called a uniform and is assigned to a dedicated consumer process. A uniform is a prompt template passed to the underlying tool the consumer executes. The goal here is to force the LLM to consume and produce a consistent contract so agents and scripts can exchange data. This protocol also provides some guarantee that agentic processes complete their work by requiring a JSON schema which is used to validate the agent output.

In many cases this becomes a context exchange between agents. Reminding working directories or fan-out/fan-in statuses. This context exchange is generally analogous to an email thread. A consumer can subscribe to many sources and can for claude-code force a clean context or continue a session

source: 
  types: 
    - "task.implement" # subscribed events 
    - "task.review.rejected" 
    - "task.review.approved" 

session: 
  fresh_types: [task.implement] # these create new sessions 
  resume_types: [task.review.rejected] # these resume existing sessions 
 # task.review.approved is neither → defaults to fresh
Enter fullscreen mode Exit fullscreen mode

Each tool call or agent can map lifecycle events so the output contract can inform on .done and .failed. When these mappings exist a successful tool or agent completion results in a new event dispatched as a threaded reply. Allowing other consumers to participate in the work with their own uniform defining a task.

Claude-Code Caveat

Much of this has been built around claude-code and there are some limitations towards other agents right now but this is what I have so far. Claude for example as the tool supports session resume which permits retries and replies to maintain a conversationally bound session to speed things up.

Couple Line Example

Here is an example of "watch" which is a convenience function to auto "dispatch" from any command output on an interval. Requires a running kwike daemon.

# watch a git repo, dispatch changes, consume with an agent
kwike watch "git diff --stat HEAD~1" --type repo.change --interval 60s
kwike consume --config ./agents/writer/consumer.yaml
Enter fullscreen mode Exit fullscreen mode

Anyway I have plenty of examples in the repo, https://git.sr.ht/~ninjapanzer/kwike

There is plenty left to do but I would love to hear some feedback on the architecture and assumptions around contract constraints as a mode to make LLMs behave. The crash-only approach, and the message durability that mirrors Kafka but acts more like a newsgroup server and mail clients.

Top comments (0)