Quick Start
Getting Started
Yoker provides an interactive chat interface with Ollama and tool calling capabilities.
Architecture: Yoker uses an event-driven, library-first design. The Agent emits events (thinking chunks, content, tool calls) that handlers subscribe to. This makes the library usable in headless, web, and GUI contexts.
Prerequisites
Python 3.10 or higher
Ollama running with at least one model
Install
pip install -e .
Or from PyPI:
pip install yoker
Run
python -m yoker
Or with a configuration file:
python -m yoker --config yoker.toml
Library Usage (Headless)
import asyncio
from yoker import Agent
from yoker.events import Event, ContentChunkEvent
# Create a custom async event handler (recommended)
class MyAsyncHandler:
"""Async event handler for processing events.
Async handlers are recommended for most use cases, especially when
performing I/O operations like writing to files, making network calls,
or interacting with databases.
"""
async def __call__(self, event: Event) -> None:
if isinstance(event, ContentChunkEvent):
print(event.text, end='', flush=True)
# Sync handlers are also supported for simple, fast operations
class MySyncHandler:
"""Sync handler for simple operations (no I/O).
Sync handlers are supported for cases where the handler just
performs fast, non-blocking operations like logging or counters.
"""
def __call__(self, event: Event) -> None:
if isinstance(event, ContentChunkEvent):
print(event.text, end='', flush=True)
async def main():
# Create agent and attach async handler
agent = Agent(model="llama3.2")
agent.add_event_handler(MyAsyncHandler())
# Use the agent programmatically (all methods are async)
await agent.begin_session()
await agent.process("What is 2+2?")
await agent.end_session()
# Run the async main function
asyncio.run(main())
Async Model
Yoker is built with an async-first architecture:
All Agent methods are async:
begin_session(),process(), andend_session()are all coroutinesEvent handlers can be async: Handlers receive events in the same asyncio task as
process()No thread pool bridging needed: Async handlers can directly
awaitI/O operations
class DatabaseHandler:
"""Example async handler writing to a database."""
def __init__(self, db_connection):
self.db = db_connection
async def __call__(self, event: Event) -> None:
if isinstance(event, ContentEndEvent):
# Direct await - no run_coroutine_threadsafe needed!
await self.db.save_response(event.total_length)
async def main():
agent = Agent(model="llama3.2")
agent.add_event_handler(DatabaseHandler(db))
await agent.begin_session()
await agent.process("Hello") # Handler runs in same event loop
await agent.end_session()
Threading Model:
Context |
Where handlers run |
|---|---|
|
Same asyncio task |
Interactive CLI |
Main asyncio event loop |
Web server (FastAPI) |
Request handler’s event loop |
Handlers run synchronously within the asyncio event loop. For long-running operations, use async handlers that yield control (e.g., await asyncio.sleep(0)) or offload to a separate executor.
Interactive Session
Yoker v0.3.0 - Using model: glm-5:cloud
Thinking mode: enabled (use /think on|off to toggle)
Type /help for available commands.
Press Ctrl+D (or Ctrl+Z on Windows) to quit.
> /help
Available commands:
/help - Show available commands
/think - Enable/disable thinking mode: /think [on|off]
Type a message without / prefix to chat with the LLM.
> What's in the README.md file?
I'll read the README.md file for you.
The README.md file describes **Yoker**, a Python-based agent harness...
> ^D
Goodbye!
Interactive Input Features
The session supports:
Feature |
How to use |
|---|---|
Multiline input |
|
Command history |
|
History search |
|
Mouse support |
Click to position cursor |
Slash Commands
Command |
Description |
|---|---|
|
Show available commands |
|
Enable/disable LLM thinking trace |
Thinking Mode
When enabled, the LLM shows its reasoning process in gray:
[Thinking]
Let me analyze this request...
I should check the file structure first...
[Response]
Based on my analysis, here's what I found...
Command Line Options
python -m yoker --help
Options:
-c, --config PATH Path to configuration file (default: yoker.toml)
-m, --model MODEL Model to use (overrides config)
-a, --agent PATH Path to agent definition file (Markdown with frontmatter)
Session Persistence
Yoker supports session persistence for resuming conversations:
# Start a session with persistence
python -m yoker --persist
# Resume a previous session
python -m yoker --resume <session_id>
When using --persist, the session is saved after each turn. Use --resume to continue a previous session with full context restored.
Programmatic usage:
import asyncio
from pathlib import Path
from yoker.agent import Agent
from yoker.context import BasicPersistenceContextManager
async def main():
# Create context manager for persistence
context = BasicPersistenceContextManager(
storage_path=Path(".yoker/sessions"),
session_id="my-session"
)
# Create agent with context
agent = Agent(context_manager=context)
# Use the agent (all methods are async)
await agent.begin_session()
await agent.process("What is 2+2?")
await agent.end_session()
# Later, resume the session
context = BasicPersistenceContextManager(
storage_path=Path(".yoker/sessions"),
session_id="my-session"
)
agent = Agent(context_manager=context)
# Context is automatically loaded
asyncio.run(main())
Tools
Yoker provides several tools for file operations and subagent spawning:
Tool |
Description |
|---|---|
|
Read file contents with guardrails |
|
Directory listing with pattern filtering |
|
Write files with overwrite protection |
|
Edit existing files with replace/insert/delete |
|
Search file contents or filenames |
|
Check if files or folders exist |
|
Create directories with parent creation |
|
Git operations with permission-controlled commit/push |
|
Spawn subagents with isolated context |
Agent Tool
The agent tool allows spawning subagents for specialized tasks:
> Use the agent tool to spawn a researcher agent to find all TODO comments
[Tool Call] agent(agent_path="examples/agents/researcher.md", prompt="Find all TODO comments")
The researcher agent found 15 TODO items across the codebase...
Key features:
Isolated context: Subagents start with fresh context
Recursion limits: Maximum depth of 3 by default
Timeout: 5-minute default execution limit
Tool filtering: Subagents use only their defined tools
Agent Definitions
Yoker supports loading agent definitions from Markdown files with YAML frontmatter. This allows you to define custom system prompts and tool availability.
Agent Definition Format
Create a file like examples/agents/researcher.md:
---
name: researcher
description: Research assistant that searches and reads files
tools: List, Read, Search
color: blue
---
# Researcher Agent
You are a research assistant specialized in finding and analyzing information.
## Workflow
1. Use Search to find relevant files
2. Use Read to examine file contents
3. Compile findings into a structured report
Using Agent Definitions
# Load an agent definition
python -m yoker --agent examples/agents/researcher.md
Programmatically:
from yoker.agent import Agent
from yoker.agents import load_agent_definition, validate_agent_definition
from yoker.config import load_config
# Load configuration and agent
config = load_config("yoker.toml")
agent_def = load_agent_definition("agents/researcher.md")
# Validate agent tools against config
warnings = validate_agent_definition(agent_def, config.tools)
# Create agent with definition
agent = Agent(config=config, agent_definition=agent_def)
# agent.messages[0] now contains the system prompt from the Markdown body
Example Agents
Agent |
File |
Description |
|---|---|---|
Main |
|
Default assistant with read-only tools |
Researcher |
|
Research assistant with search capabilities |
Markdown |
|
Formats all responses as structured Markdown |
Configuration
Configuration File
Create a yoker.toml file in your project directory:
[harness]
name = "my-yoke"
log_level = "INFO"
[backend]
provider = "ollama"
[backend.ollama]
base_url = "http://localhost:11434"
model = "llama3.2:latest"
timeout_seconds = 60
[backend.ollama.parameters]
temperature = 0.7
top_p = 0.9
[tools.read]
enabled = true
allowed_extensions = [".txt", ".md", ".py", ".json"]
[logging]
format = "json"
include_tool_calls = true
See examples/yoker.toml for the full configuration reference.
Environment Variables
Yoker auto-discovers configuration files in this order:
./yoker.toml(current directory)~/.yoker.toml(user home directory)Built-in defaults
You can also specify an explicit config file:
python -m yoker --config path/to/config.toml
Available Tools
Tool |
Purpose |
|---|---|
|
Read file contents |
|
List directory contents with pattern filtering |
|
Write content to files with overwrite protection |
|
Edit existing files with replace, insert, and delete |
|
Search file contents with regex or filenames with glob |
|
Git operations (status, log, diff, branch, show) |
Tool Examples
Read Tool
Reading the first 3 lines of README.md.
List Tool
Listing files matching CLAUDE* in the current directory.
Write Tool
Writing “Hello from Yoker!” to /tmp/yoker-demo.txt and reading it back.
Update Tool
Replacing text in an existing file with the update tool.
Search Tool
Searching for content with regex patterns or filenames with glob patterns.
Git Tool
Running Git operations (status, log, diff) on a repository.
Commands
Using /help, /think on, and /think off slash commands.
Thinking Mode
Thinking mode enabled shows the LLM reasoning process in gray before the response.
Next Steps
Installation - Detailed installation guide
Architecture - System design