yoker 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
yoker-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,263 @@
1
+ Metadata-Version: 2.4
2
+ Name: yoker
3
+ Version: 0.1.0
4
+ Summary: A Python agent harness with configurable tools and guardrails - one who yokes agents together
5
+ Author-email: Christophe VG <contact@christophe.vg>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/christophevg/yoker
8
+ Project-URL: Documentation, https://yoker.readthedocs.io/
9
+ Project-URL: Repository, https://github.com/christophevg/yoker
10
+ Project-URL: Issues, https://github.com/christophevg/yoker/issues
11
+ Keywords: agent,llm,ollama,ai,harness
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ Requires-Dist: httpx>=0.25.0
24
+ Requires-Dist: ollama>=0.6.0
25
+ Requires-Dist: rich>=14.0.0
26
+ Requires-Dist: structlog>=23.0.0
27
+ Requires-Dist: pyyaml>=6.0
28
+ Requires-Dist: tomli>=2.0; python_version < "3.11"
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
31
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
32
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
33
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
34
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
35
+ Requires-Dist: build>=1.0.0; extra == "dev"
36
+ Requires-Dist: twine>=5.0.0; extra == "dev"
37
+ Requires-Dist: sphinx>=7.0.0; extra == "dev"
38
+ Requires-Dist: sphinx-rtd-theme>=2.0.0; extra == "dev"
39
+ Requires-Dist: myst-parser>=2.0.0; extra == "dev"
40
+ Requires-Dist: tox>=4.0.0; extra == "dev"
41
+
42
+ # Yoker
43
+
44
+ A Python-based agent harness with configurable tools, guardrails, and Ollama backend integration.
45
+
46
+ ## Current Status
47
+
48
+ **Minimal prototype available!** The basic chat loop with tool calling is working:
49
+
50
+ ```bash
51
+ # Install (requires Python 3.10+)
52
+ pip install -e .
53
+
54
+ # Run interactive chat
55
+ python -m yoker
56
+ ```
57
+
58
+ The prototype includes:
59
+ - Interactive chat loop with Ollama
60
+ - Basic `read` tool for file reading
61
+ - Streaming responses
62
+ - Structured logging
63
+
64
+ See [Quick Start](#quick-start) below for details.
65
+
66
+ ## Name
67
+
68
+ **"yoker"** - One who yokes. A person or device that joins or attaches things together, specifically one who yokes oxen or links things together.
69
+
70
+ From the agent noun of "yoke", which derives from PIE *\yeug-* meaning "to join" (same root as yoga, conjugate, junction).
71
+
72
+ Pairs beautifully with "clitic" (both are joining tools - clitic joins words, yoker joins agents).
73
+
74
+ See `docs/NAME.md` for full naming documentation.
75
+
76
+ ## Vision
77
+
78
+ Create a lightweight, configurable agent harness that provides a structured environment for AI agents to operate within defined boundaries. The harness manages tool access, enforces guardrails, handles context persistence, and integrates with Ollama as the LLM backend.
79
+
80
+ ## Goals
81
+
82
+ 1. **Safety First**: Guardrails prevent agents from performing unintended operations
83
+ 2. **Configurability**: All tools, parameters, and limits configurable via TOML
84
+ 3. **Simplicity**: Specific tools instead of generic shell access
85
+ 4. **Transparency**: Clear logging and reporting of all agent actions
86
+ 5. **Extensibility**: Easy to add new tools while maintaining guardrails
87
+ 6. **Compatibility**: Agent definitions compatible with Claude Code format
88
+
89
+ ## Core Components
90
+
91
+ ### 1. Configuration System
92
+
93
+ - **TOML configuration file**: Harness settings, tool guardrails, Ollama parameters
94
+ - **Markdown agent definitions**: With YAML frontmatter (compatible with Claude Code)
95
+
96
+ ### 2. Tool System
97
+
98
+ MVP tools (no generic Bash):
99
+
100
+ | Tool | Purpose | Guardrails |
101
+ |------|---------|------------|
102
+ | List | Directory listing | Path restrictions, pattern filters |
103
+ | Read | File reading | Path restrictions, size limits |
104
+ | Write | File writing | Path restrictions, overwrite protection |
105
+ | Update | File editing | Path restrictions, diff validation |
106
+ | Search | Grep/glob-like | Path restrictions, pattern limits |
107
+ | Agent | Spawn subagents | Recursion depth, tool subset |
108
+
109
+ ### 3. Context Manager
110
+
111
+ Persists context for consecutive LLM calls:
112
+ - Conversation history (JSONL format - append-friendly)
113
+ - Agent state
114
+ - Working memory
115
+ - Per-session files in configurable location
116
+
117
+ ### 4. Ollama Integration
118
+
119
+ - Assumes Ollama is running externally
120
+ - All configurable parameters exposed
121
+ - Model selection per agent possible
122
+
123
+ ### 5. Agent Definitions
124
+
125
+ Markdown files with YAML frontmatter:
126
+
127
+ ```markdown
128
+ ---
129
+ name: researcher
130
+ description: Research assistant
131
+ tools: List, Read, Search
132
+ ---
133
+
134
+ # Researcher Agent
135
+
136
+ You are a research assistant...
137
+ ```
138
+
139
+ ## Architecture
140
+
141
+ ```
142
+ ┌─────────────────────────────────────────────────────────┐
143
+ │ Yoker │
144
+ ├─────────────────────────────────────────────────────────┤
145
+ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
146
+ │ │ Config │ │ Context │ │ Logging/ │ │
147
+ │ │ Loader │ │ Manager │ │ Reporting │ │
148
+ │ │ (TOML) │ │ (JSONL) │ │ │ │
149
+ │ └──────┬──────┘ └──────┬──────┘ └────────┬────────┘ │
150
+ │ │ │ │ │
151
+ │ ▼ ▼ ▼ │
152
+ │ ┌─────────────────────────────────────────────────────┐│
153
+ │ │ Tool Execution Layer ││
154
+ │ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌───────┐ ││
155
+ │ │ │List │ │Read │ │Write│ │Update│ │Search│ │Agent │ ││
156
+ │ │ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └───────┘ ││
157
+ │ └─────────────────────────────────────────────────────┘│
158
+ │ │ │
159
+ │ ▼ │
160
+ │ ┌─────────────────────────────────────────────────────┐│
161
+ │ │ Ollama Backend Client ││
162
+ │ │ (HTTP API, configurable parameters) ││
163
+ │ └─────────────────────────────────────────────────────┘│
164
+ └─────────────────────────────────────────────────────────┘
165
+ ```
166
+
167
+ ## Project Structure
168
+
169
+ ```
170
+ yoker/
171
+ ├── src/yoker/ # Main package
172
+ ├── tests/ # Test suite
173
+ ├── docs/ # Sphinx documentation
174
+ ├── examples/ # Example configurations
175
+ ├── analysis/ # Functional analysis
176
+ ├── pyproject.toml # Package configuration
177
+ └── README.md
178
+ ```
179
+
180
+ ## Quick Start
181
+
182
+ ### Minimal Prototype
183
+
184
+ The current prototype provides a basic interactive chat with tool calling:
185
+
186
+ ```bash
187
+ # Install
188
+ pip install -e .
189
+
190
+ # Run
191
+ python -m yoker
192
+ ```
193
+
194
+ Example session:
195
+ ```
196
+ Yoker v0.1.0 - Using model: glm-5:cloud
197
+ Type your message and press Enter. Press Ctrl+D to quit.
198
+
199
+ > What's in the README.md file?
200
+
201
+ I'll read the README.md file for you.
202
+
203
+ [13:49:49] INFO yoker.agent - Tool call: read({'path': 'README.md'})
204
+ [13:49:49] INFO yoker.agent - Tool result: # Yoker...
205
+
206
+ The README.md file describes **Yoker**, a Python-based agent harness...
207
+
208
+ > ^D
209
+ Goodbye!
210
+ ```
211
+
212
+ ### Planned Full Usage
213
+
214
+ ```bash
215
+ # Create config
216
+ cat > yoker.toml << EOF
217
+ [ollama]
218
+ model = "llama3.2"
219
+ base_url = "http://localhost:11434"
220
+
221
+ [tools.list]
222
+ allowed_paths = ["/workspace"]
223
+
224
+ [tools.read]
225
+ allowed_paths = ["/workspace"]
226
+ max_size_kb = 100
227
+
228
+ [tools.agent]
229
+ max_recursion_depth = 3
230
+
231
+ [agents]
232
+ directory = "./agents"
233
+ EOF
234
+
235
+ # Create agent definition
236
+ mkdir agents
237
+ cat > agents/main.md << EOF
238
+ ---
239
+ name: main
240
+ description: Default assistant
241
+ tools: List, Read, Write, Update, Search, Agent
242
+ ---
243
+
244
+ You are a helpful assistant.
245
+ EOF
246
+
247
+ # Run harness (planned)
248
+ yoker --config yoker.toml
249
+ ```
250
+
251
+ ## Documentation
252
+
253
+ - Name documentation: `docs/NAME.md`
254
+ - Functional analysis: `analysis/functional.md`
255
+ - Interview notes: `analysis/interview.md`
256
+
257
+ ## Integration with Clitic
258
+
259
+ Yoker provides the agent runtime, Clitic provides the TUI:
260
+
261
+ - Build agents using Yoker APIs
262
+ - Optionally add Clitic-based CLI interface
263
+ - Deploy agents with or without UI (daemon mode)
yoker-0.1.0/README.md ADDED
@@ -0,0 +1,222 @@
1
+ # Yoker
2
+
3
+ A Python-based agent harness with configurable tools, guardrails, and Ollama backend integration.
4
+
5
+ ## Current Status
6
+
7
+ **Minimal prototype available!** The basic chat loop with tool calling is working:
8
+
9
+ ```bash
10
+ # Install (requires Python 3.10+)
11
+ pip install -e .
12
+
13
+ # Run interactive chat
14
+ python -m yoker
15
+ ```
16
+
17
+ The prototype includes:
18
+ - Interactive chat loop with Ollama
19
+ - Basic `read` tool for file reading
20
+ - Streaming responses
21
+ - Structured logging
22
+
23
+ See [Quick Start](#quick-start) below for details.
24
+
25
+ ## Name
26
+
27
+ **"yoker"** - One who yokes. A person or device that joins or attaches things together, specifically one who yokes oxen or links things together.
28
+
29
+ From the agent noun of "yoke", which derives from PIE *\yeug-* meaning "to join" (same root as yoga, conjugate, junction).
30
+
31
+ Pairs beautifully with "clitic" (both are joining tools - clitic joins words, yoker joins agents).
32
+
33
+ See `docs/NAME.md` for full naming documentation.
34
+
35
+ ## Vision
36
+
37
+ Create a lightweight, configurable agent harness that provides a structured environment for AI agents to operate within defined boundaries. The harness manages tool access, enforces guardrails, handles context persistence, and integrates with Ollama as the LLM backend.
38
+
39
+ ## Goals
40
+
41
+ 1. **Safety First**: Guardrails prevent agents from performing unintended operations
42
+ 2. **Configurability**: All tools, parameters, and limits configurable via TOML
43
+ 3. **Simplicity**: Specific tools instead of generic shell access
44
+ 4. **Transparency**: Clear logging and reporting of all agent actions
45
+ 5. **Extensibility**: Easy to add new tools while maintaining guardrails
46
+ 6. **Compatibility**: Agent definitions compatible with Claude Code format
47
+
48
+ ## Core Components
49
+
50
+ ### 1. Configuration System
51
+
52
+ - **TOML configuration file**: Harness settings, tool guardrails, Ollama parameters
53
+ - **Markdown agent definitions**: With YAML frontmatter (compatible with Claude Code)
54
+
55
+ ### 2. Tool System
56
+
57
+ MVP tools (no generic Bash):
58
+
59
+ | Tool | Purpose | Guardrails |
60
+ |------|---------|------------|
61
+ | List | Directory listing | Path restrictions, pattern filters |
62
+ | Read | File reading | Path restrictions, size limits |
63
+ | Write | File writing | Path restrictions, overwrite protection |
64
+ | Update | File editing | Path restrictions, diff validation |
65
+ | Search | Grep/glob-like | Path restrictions, pattern limits |
66
+ | Agent | Spawn subagents | Recursion depth, tool subset |
67
+
68
+ ### 3. Context Manager
69
+
70
+ Persists context for consecutive LLM calls:
71
+ - Conversation history (JSONL format - append-friendly)
72
+ - Agent state
73
+ - Working memory
74
+ - Per-session files in configurable location
75
+
76
+ ### 4. Ollama Integration
77
+
78
+ - Assumes Ollama is running externally
79
+ - All configurable parameters exposed
80
+ - Model selection per agent possible
81
+
82
+ ### 5. Agent Definitions
83
+
84
+ Markdown files with YAML frontmatter:
85
+
86
+ ```markdown
87
+ ---
88
+ name: researcher
89
+ description: Research assistant
90
+ tools: List, Read, Search
91
+ ---
92
+
93
+ # Researcher Agent
94
+
95
+ You are a research assistant...
96
+ ```
97
+
98
+ ## Architecture
99
+
100
+ ```
101
+ ┌─────────────────────────────────────────────────────────┐
102
+ │ Yoker │
103
+ ├─────────────────────────────────────────────────────────┤
104
+ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
105
+ │ │ Config │ │ Context │ │ Logging/ │ │
106
+ │ │ Loader │ │ Manager │ │ Reporting │ │
107
+ │ │ (TOML) │ │ (JSONL) │ │ │ │
108
+ │ └──────┬──────┘ └──────┬──────┘ └────────┬────────┘ │
109
+ │ │ │ │ │
110
+ │ ▼ ▼ ▼ │
111
+ │ ┌─────────────────────────────────────────────────────┐│
112
+ │ │ Tool Execution Layer ││
113
+ │ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌───────┐ ││
114
+ │ │ │List │ │Read │ │Write│ │Update│ │Search│ │Agent │ ││
115
+ │ │ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └───────┘ ││
116
+ │ └─────────────────────────────────────────────────────┘│
117
+ │ │ │
118
+ │ ▼ │
119
+ │ ┌─────────────────────────────────────────────────────┐│
120
+ │ │ Ollama Backend Client ││
121
+ │ │ (HTTP API, configurable parameters) ││
122
+ │ └─────────────────────────────────────────────────────┘│
123
+ └─────────────────────────────────────────────────────────┘
124
+ ```
125
+
126
+ ## Project Structure
127
+
128
+ ```
129
+ yoker/
130
+ ├── src/yoker/ # Main package
131
+ ├── tests/ # Test suite
132
+ ├── docs/ # Sphinx documentation
133
+ ├── examples/ # Example configurations
134
+ ├── analysis/ # Functional analysis
135
+ ├── pyproject.toml # Package configuration
136
+ └── README.md
137
+ ```
138
+
139
+ ## Quick Start
140
+
141
+ ### Minimal Prototype
142
+
143
+ The current prototype provides a basic interactive chat with tool calling:
144
+
145
+ ```bash
146
+ # Install
147
+ pip install -e .
148
+
149
+ # Run
150
+ python -m yoker
151
+ ```
152
+
153
+ Example session:
154
+ ```
155
+ Yoker v0.1.0 - Using model: glm-5:cloud
156
+ Type your message and press Enter. Press Ctrl+D to quit.
157
+
158
+ > What's in the README.md file?
159
+
160
+ I'll read the README.md file for you.
161
+
162
+ [13:49:49] INFO yoker.agent - Tool call: read({'path': 'README.md'})
163
+ [13:49:49] INFO yoker.agent - Tool result: # Yoker...
164
+
165
+ The README.md file describes **Yoker**, a Python-based agent harness...
166
+
167
+ > ^D
168
+ Goodbye!
169
+ ```
170
+
171
+ ### Planned Full Usage
172
+
173
+ ```bash
174
+ # Create config
175
+ cat > yoker.toml << EOF
176
+ [ollama]
177
+ model = "llama3.2"
178
+ base_url = "http://localhost:11434"
179
+
180
+ [tools.list]
181
+ allowed_paths = ["/workspace"]
182
+
183
+ [tools.read]
184
+ allowed_paths = ["/workspace"]
185
+ max_size_kb = 100
186
+
187
+ [tools.agent]
188
+ max_recursion_depth = 3
189
+
190
+ [agents]
191
+ directory = "./agents"
192
+ EOF
193
+
194
+ # Create agent definition
195
+ mkdir agents
196
+ cat > agents/main.md << EOF
197
+ ---
198
+ name: main
199
+ description: Default assistant
200
+ tools: List, Read, Write, Update, Search, Agent
201
+ ---
202
+
203
+ You are a helpful assistant.
204
+ EOF
205
+
206
+ # Run harness (planned)
207
+ yoker --config yoker.toml
208
+ ```
209
+
210
+ ## Documentation
211
+
212
+ - Name documentation: `docs/NAME.md`
213
+ - Functional analysis: `analysis/functional.md`
214
+ - Interview notes: `analysis/interview.md`
215
+
216
+ ## Integration with Clitic
217
+
218
+ Yoker provides the agent runtime, Clitic provides the TUI:
219
+
220
+ - Build agents using Yoker APIs
221
+ - Optionally add Clitic-based CLI interface
222
+ - Deploy agents with or without UI (daemon mode)
@@ -0,0 +1,135 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "yoker"
7
+ version = "0.1.0"
8
+ description = "A Python agent harness with configurable tools and guardrails - one who yokes agents together"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ {name = "Christophe VG", email = "contact@christophe.vg"}
14
+ ]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
24
+ "Typing :: Typed",
25
+ ]
26
+ keywords = ["agent", "llm", "ollama", "ai", "harness"]
27
+
28
+ dependencies = [
29
+ "httpx>=0.25.0",
30
+ "ollama>=0.6.0",
31
+ "rich>=14.0.0",
32
+ "structlog>=23.0.0",
33
+ "pyyaml>=6.0",
34
+ "tomli>=2.0;python_version<'3.11'",
35
+ ]
36
+
37
+ [project.optional-dependencies]
38
+ dev = [
39
+ "pytest>=7.0.0",
40
+ "pytest-cov>=4.0.0",
41
+ "pytest-asyncio>=0.21.0",
42
+ "mypy>=1.0.0",
43
+ "ruff>=0.1.0",
44
+ "build>=1.0.0",
45
+ "twine>=5.0.0",
46
+ "sphinx>=7.0.0",
47
+ "sphinx-rtd-theme>=2.0.0",
48
+ "myst-parser>=2.0.0",
49
+ "tox>=4.0.0",
50
+ ]
51
+
52
+ [project.urls]
53
+ Homepage = "https://github.com/christophevg/yoker"
54
+ Documentation = "https://yoker.readthedocs.io/"
55
+ Repository = "https://github.com/christophevg/yoker"
56
+ Issues = "https://github.com/christophevg/yoker/issues"
57
+
58
+ [project.scripts]
59
+ yoker = "yoker.__main__:main"
60
+
61
+ [tool.setuptools.packages.find]
62
+ where = ["src"]
63
+
64
+ [tool.setuptools.package-data]
65
+ yoker = ["py.typed"]
66
+
67
+ [tool.pytest.ini_options]
68
+ testpaths = ["tests"]
69
+ asyncio_mode = "auto"
70
+ addopts = "-v --cov=yoker --cov-report=term-missing"
71
+
72
+ [tool.mypy]
73
+ python_version = "3.10"
74
+ warn_return_any = true
75
+ warn_unused_configs = true
76
+ disallow_untyped_defs = true
77
+ disallow_incomplete_defs = true
78
+ check_untyped_defs = true
79
+ disallow_untyped_decorators = true
80
+ no_implicit_optional = true
81
+ warn_redundant_casts = true
82
+ warn_unused_ignores = true
83
+ warn_no_return = true
84
+ strict_equality = true
85
+
86
+ [tool.ruff]
87
+ line-length = 100
88
+ target-version = "py310"
89
+
90
+ [tool.ruff.lint]
91
+ select = [
92
+ "E", # pycodestyle errors
93
+ "W", # pycodestyle warnings
94
+ "F", # pyflakes
95
+ "I", # isort
96
+ "B", # flake8-bugbear
97
+ "C4", # flake8-comprehensions
98
+ "UP", # pyupgrade
99
+ ]
100
+ ignore = [
101
+ "E501", # line too long (handled by formatter)
102
+ ]
103
+
104
+ [tool.ruff.lint.isort]
105
+ known-first-party = ["yoker"]
106
+
107
+ [tool.coverage.run]
108
+ source = ["src"]
109
+ branch = true
110
+
111
+ [tool.coverage.report]
112
+ exclude_lines = [
113
+ "pragma: no cover",
114
+ "def __repr__",
115
+ "raise NotImplementedError",
116
+ "if TYPE_CHECKING:",
117
+ ]
118
+
119
+ [tool.tox]
120
+ env_list = ["py310", "py311", "py312"]
121
+
122
+ [tool.tox.env_run_base]
123
+ extras = ["dev"]
124
+ commands = [
125
+ ["pytest", "-v", "--cov=yoker", "--cov-report=term-missing"],
126
+ ]
127
+
128
+ [tool.tox.env.py310]
129
+ base_python = ["python3.10"]
130
+
131
+ [tool.tox.env.py311]
132
+ base_python = ["python3.11"]
133
+
134
+ [tool.tox.env.py312]
135
+ base_python = ["python3.12"]
yoker-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,11 @@
1
+ """
2
+ yoker - A Python agent harness with configurable tools and guardrails.
3
+
4
+ One who yokes - the agent noun from "yoke" (PIE *yeug-* meaning "to join").
5
+ Pairs with "clitic" (both are joining tools).
6
+ """
7
+
8
+ __version__ = "0.1.0"
9
+ __author__ = "Christophe VG"
10
+
11
+ # Public API will be exported here as implementation progresses
@@ -0,0 +1,34 @@
1
+ """Entry point for running Yoker as a module.
2
+
3
+ Usage: python -m yoker
4
+ """
5
+
6
+ import logging
7
+
8
+ from rich.logging import RichHandler
9
+
10
+ from yoker import __version__
11
+ from yoker.agent import Agent
12
+
13
+ # Configure logging
14
+ logging.basicConfig(
15
+ level=logging.INFO,
16
+ format="%(name)s - %(message)s",
17
+ datefmt="[%X]",
18
+ handlers=[RichHandler()],
19
+ )
20
+
21
+ # Silence noisy modules
22
+ for module in ["httpx", "httpcore", "ollama"]:
23
+ logging.getLogger(module).setLevel(logging.WARNING)
24
+
25
+
26
+ def main() -> None:
27
+ """Run the interactive agent."""
28
+ print(f"Yoker v{__version__}")
29
+ print("=" * 40)
30
+ Agent().start()
31
+
32
+
33
+ if __name__ == "__main__":
34
+ main()
@@ -0,0 +1,89 @@
1
+ """Minimal Agent implementation for Yoker prototype."""
2
+
3
+ import logging
4
+
5
+ from ollama import Client
6
+
7
+ from yoker.tools import AVAILABLE_TOOLS
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ class Agent:
13
+ """Minimal agent that chats with Ollama and uses tools."""
14
+
15
+ def __init__(self, model: str = "glm-5:cloud"):
16
+ self.client = Client()
17
+ self.model = model
18
+ self.tools = AVAILABLE_TOOLS
19
+
20
+ def start(self) -> None:
21
+ """Start the interactive chat loop."""
22
+ messages: list[dict] = [
23
+ {"role": "system", "content": "You are a helpful assistant."},
24
+ ]
25
+
26
+ print(f"Yoker v0.1.0 - Using model: {self.model}")
27
+ print("Type your message and press Enter. Press Ctrl+D (or Ctrl+Z on Windows) to quit.\n")
28
+
29
+ while True:
30
+ try:
31
+ user_input = input("> ")
32
+ except EOFError:
33
+ print("\nGoodbye!")
34
+ break
35
+
36
+ if not user_input.strip():
37
+ continue
38
+
39
+ messages.append({"role": "user", "content": user_input})
40
+
41
+ # Process with model, handling tool calls in a loop
42
+ while True:
43
+ response = self.client.chat(
44
+ model=self.model,
45
+ messages=messages,
46
+ tools=list(self.tools.values()),
47
+ )
48
+
49
+ # Extract response content
50
+ content = response.message.content or ""
51
+ tool_calls = response.message.tool_calls or []
52
+
53
+ # Show assistant response
54
+ if content:
55
+ print(f"\n{content}\n")
56
+
57
+ # If no tool calls, we're done with this turn
58
+ if not tool_calls:
59
+ break
60
+
61
+ # Add assistant message to history
62
+ messages.append({
63
+ "role": "assistant",
64
+ "content": content,
65
+ "tool_calls": tool_calls,
66
+ })
67
+
68
+ # Process tool calls
69
+ for call in tool_calls:
70
+ tool_name = call.function.name
71
+ tool_args = call.function.arguments
72
+
73
+ logger.info(f"Tool call: {tool_name}({tool_args})")
74
+
75
+ try:
76
+ result = self.tools[tool_name](**tool_args)
77
+ except KeyError:
78
+ result = f"Error: Unknown tool '{tool_name}'"
79
+ except Exception as e:
80
+ result = f"Error executing tool: {e}"
81
+
82
+ logger.info(f"Tool result: {result[:100]}...")
83
+
84
+ # Add tool result to messages
85
+ messages.append({
86
+ "role": "tool",
87
+ "name": tool_name,
88
+ "content": str(result),
89
+ })
File without changes
@@ -0,0 +1,26 @@
1
+ """Minimal tools for Yoker prototype."""
2
+
3
+ from pathlib import Path
4
+
5
+
6
+ def read(path: str) -> str:
7
+ """Read the content of a file.
8
+
9
+ Args:
10
+ path: The path to the file to read.
11
+
12
+ Returns:
13
+ The content of the file.
14
+ """
15
+ try:
16
+ return Path(path).read_text()
17
+ except FileNotFoundError:
18
+ return f"Error: File not found: {path}"
19
+ except Exception as e:
20
+ return f"Error reading file: {e}"
21
+
22
+
23
+ # Tool registry - maps tool names to functions
24
+ AVAILABLE_TOOLS = {
25
+ "read": read,
26
+ }
@@ -0,0 +1,263 @@
1
+ Metadata-Version: 2.4
2
+ Name: yoker
3
+ Version: 0.1.0
4
+ Summary: A Python agent harness with configurable tools and guardrails - one who yokes agents together
5
+ Author-email: Christophe VG <contact@christophe.vg>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/christophevg/yoker
8
+ Project-URL: Documentation, https://yoker.readthedocs.io/
9
+ Project-URL: Repository, https://github.com/christophevg/yoker
10
+ Project-URL: Issues, https://github.com/christophevg/yoker/issues
11
+ Keywords: agent,llm,ollama,ai,harness
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ Requires-Dist: httpx>=0.25.0
24
+ Requires-Dist: ollama>=0.6.0
25
+ Requires-Dist: rich>=14.0.0
26
+ Requires-Dist: structlog>=23.0.0
27
+ Requires-Dist: pyyaml>=6.0
28
+ Requires-Dist: tomli>=2.0; python_version < "3.11"
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
31
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
32
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
33
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
34
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
35
+ Requires-Dist: build>=1.0.0; extra == "dev"
36
+ Requires-Dist: twine>=5.0.0; extra == "dev"
37
+ Requires-Dist: sphinx>=7.0.0; extra == "dev"
38
+ Requires-Dist: sphinx-rtd-theme>=2.0.0; extra == "dev"
39
+ Requires-Dist: myst-parser>=2.0.0; extra == "dev"
40
+ Requires-Dist: tox>=4.0.0; extra == "dev"
41
+
42
+ # Yoker
43
+
44
+ A Python-based agent harness with configurable tools, guardrails, and Ollama backend integration.
45
+
46
+ ## Current Status
47
+
48
+ **Minimal prototype available!** The basic chat loop with tool calling is working:
49
+
50
+ ```bash
51
+ # Install (requires Python 3.10+)
52
+ pip install -e .
53
+
54
+ # Run interactive chat
55
+ python -m yoker
56
+ ```
57
+
58
+ The prototype includes:
59
+ - Interactive chat loop with Ollama
60
+ - Basic `read` tool for file reading
61
+ - Streaming responses
62
+ - Structured logging
63
+
64
+ See [Quick Start](#quick-start) below for details.
65
+
66
+ ## Name
67
+
68
+ **"yoker"** - One who yokes. A person or device that joins or attaches things together, specifically one who yokes oxen or links things together.
69
+
70
+ From the agent noun of "yoke", which derives from PIE *\yeug-* meaning "to join" (same root as yoga, conjugate, junction).
71
+
72
+ Pairs beautifully with "clitic" (both are joining tools - clitic joins words, yoker joins agents).
73
+
74
+ See `docs/NAME.md` for full naming documentation.
75
+
76
+ ## Vision
77
+
78
+ Create a lightweight, configurable agent harness that provides a structured environment for AI agents to operate within defined boundaries. The harness manages tool access, enforces guardrails, handles context persistence, and integrates with Ollama as the LLM backend.
79
+
80
+ ## Goals
81
+
82
+ 1. **Safety First**: Guardrails prevent agents from performing unintended operations
83
+ 2. **Configurability**: All tools, parameters, and limits configurable via TOML
84
+ 3. **Simplicity**: Specific tools instead of generic shell access
85
+ 4. **Transparency**: Clear logging and reporting of all agent actions
86
+ 5. **Extensibility**: Easy to add new tools while maintaining guardrails
87
+ 6. **Compatibility**: Agent definitions compatible with Claude Code format
88
+
89
+ ## Core Components
90
+
91
+ ### 1. Configuration System
92
+
93
+ - **TOML configuration file**: Harness settings, tool guardrails, Ollama parameters
94
+ - **Markdown agent definitions**: With YAML frontmatter (compatible with Claude Code)
95
+
96
+ ### 2. Tool System
97
+
98
+ MVP tools (no generic Bash):
99
+
100
+ | Tool | Purpose | Guardrails |
101
+ |------|---------|------------|
102
+ | List | Directory listing | Path restrictions, pattern filters |
103
+ | Read | File reading | Path restrictions, size limits |
104
+ | Write | File writing | Path restrictions, overwrite protection |
105
+ | Update | File editing | Path restrictions, diff validation |
106
+ | Search | Grep/glob-like | Path restrictions, pattern limits |
107
+ | Agent | Spawn subagents | Recursion depth, tool subset |
108
+
109
+ ### 3. Context Manager
110
+
111
+ Persists context for consecutive LLM calls:
112
+ - Conversation history (JSONL format - append-friendly)
113
+ - Agent state
114
+ - Working memory
115
+ - Per-session files in configurable location
116
+
117
+ ### 4. Ollama Integration
118
+
119
+ - Assumes Ollama is running externally
120
+ - All configurable parameters exposed
121
+ - Model selection per agent possible
122
+
123
+ ### 5. Agent Definitions
124
+
125
+ Markdown files with YAML frontmatter:
126
+
127
+ ```markdown
128
+ ---
129
+ name: researcher
130
+ description: Research assistant
131
+ tools: List, Read, Search
132
+ ---
133
+
134
+ # Researcher Agent
135
+
136
+ You are a research assistant...
137
+ ```
138
+
139
+ ## Architecture
140
+
141
+ ```
142
+ ┌─────────────────────────────────────────────────────────┐
143
+ │ Yoker │
144
+ ├─────────────────────────────────────────────────────────┤
145
+ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
146
+ │ │ Config │ │ Context │ │ Logging/ │ │
147
+ │ │ Loader │ │ Manager │ │ Reporting │ │
148
+ │ │ (TOML) │ │ (JSONL) │ │ │ │
149
+ │ └──────┬──────┘ └──────┬──────┘ └────────┬────────┘ │
150
+ │ │ │ │ │
151
+ │ ▼ ▼ ▼ │
152
+ │ ┌─────────────────────────────────────────────────────┐│
153
+ │ │ Tool Execution Layer ││
154
+ │ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌───────┐ ││
155
+ │ │ │List │ │Read │ │Write│ │Update│ │Search│ │Agent │ ││
156
+ │ │ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └───────┘ ││
157
+ │ └─────────────────────────────────────────────────────┘│
158
+ │ │ │
159
+ │ ▼ │
160
+ │ ┌─────────────────────────────────────────────────────┐│
161
+ │ │ Ollama Backend Client ││
162
+ │ │ (HTTP API, configurable parameters) ││
163
+ │ └─────────────────────────────────────────────────────┘│
164
+ └─────────────────────────────────────────────────────────┘
165
+ ```
166
+
167
+ ## Project Structure
168
+
169
+ ```
170
+ yoker/
171
+ ├── src/yoker/ # Main package
172
+ ├── tests/ # Test suite
173
+ ├── docs/ # Sphinx documentation
174
+ ├── examples/ # Example configurations
175
+ ├── analysis/ # Functional analysis
176
+ ├── pyproject.toml # Package configuration
177
+ └── README.md
178
+ ```
179
+
180
+ ## Quick Start
181
+
182
+ ### Minimal Prototype
183
+
184
+ The current prototype provides a basic interactive chat with tool calling:
185
+
186
+ ```bash
187
+ # Install
188
+ pip install -e .
189
+
190
+ # Run
191
+ python -m yoker
192
+ ```
193
+
194
+ Example session:
195
+ ```
196
+ Yoker v0.1.0 - Using model: glm-5:cloud
197
+ Type your message and press Enter. Press Ctrl+D to quit.
198
+
199
+ > What's in the README.md file?
200
+
201
+ I'll read the README.md file for you.
202
+
203
+ [13:49:49] INFO yoker.agent - Tool call: read({'path': 'README.md'})
204
+ [13:49:49] INFO yoker.agent - Tool result: # Yoker...
205
+
206
+ The README.md file describes **Yoker**, a Python-based agent harness...
207
+
208
+ > ^D
209
+ Goodbye!
210
+ ```
211
+
212
+ ### Planned Full Usage
213
+
214
+ ```bash
215
+ # Create config
216
+ cat > yoker.toml << EOF
217
+ [ollama]
218
+ model = "llama3.2"
219
+ base_url = "http://localhost:11434"
220
+
221
+ [tools.list]
222
+ allowed_paths = ["/workspace"]
223
+
224
+ [tools.read]
225
+ allowed_paths = ["/workspace"]
226
+ max_size_kb = 100
227
+
228
+ [tools.agent]
229
+ max_recursion_depth = 3
230
+
231
+ [agents]
232
+ directory = "./agents"
233
+ EOF
234
+
235
+ # Create agent definition
236
+ mkdir agents
237
+ cat > agents/main.md << EOF
238
+ ---
239
+ name: main
240
+ description: Default assistant
241
+ tools: List, Read, Write, Update, Search, Agent
242
+ ---
243
+
244
+ You are a helpful assistant.
245
+ EOF
246
+
247
+ # Run harness (planned)
248
+ yoker --config yoker.toml
249
+ ```
250
+
251
+ ## Documentation
252
+
253
+ - Name documentation: `docs/NAME.md`
254
+ - Functional analysis: `analysis/functional.md`
255
+ - Interview notes: `analysis/interview.md`
256
+
257
+ ## Integration with Clitic
258
+
259
+ Yoker provides the agent runtime, Clitic provides the TUI:
260
+
261
+ - Build agents using Yoker APIs
262
+ - Optionally add Clitic-based CLI interface
263
+ - Deploy agents with or without UI (daemon mode)
@@ -0,0 +1,13 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/yoker/__init__.py
4
+ src/yoker/__main__.py
5
+ src/yoker/agent.py
6
+ src/yoker/py.typed
7
+ src/yoker/tools.py
8
+ src/yoker.egg-info/PKG-INFO
9
+ src/yoker.egg-info/SOURCES.txt
10
+ src/yoker.egg-info/dependency_links.txt
11
+ src/yoker.egg-info/entry_points.txt
12
+ src/yoker.egg-info/requires.txt
13
+ src/yoker.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ yoker = yoker.__main__:main
@@ -0,0 +1,21 @@
1
+ httpx>=0.25.0
2
+ ollama>=0.6.0
3
+ rich>=14.0.0
4
+ structlog>=23.0.0
5
+ pyyaml>=6.0
6
+
7
+ [:python_version < "3.11"]
8
+ tomli>=2.0
9
+
10
+ [dev]
11
+ pytest>=7.0.0
12
+ pytest-cov>=4.0.0
13
+ pytest-asyncio>=0.21.0
14
+ mypy>=1.0.0
15
+ ruff>=0.1.0
16
+ build>=1.0.0
17
+ twine>=5.0.0
18
+ sphinx>=7.0.0
19
+ sphinx-rtd-theme>=2.0.0
20
+ myst-parser>=2.0.0
21
+ tox>=4.0.0
@@ -0,0 +1 @@
1
+ yoker