kerf 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.
- kerf-0.1.0/.github/workflows/docs.yml +33 -0
- kerf-0.1.0/.github/workflows/publish.yml +24 -0
- kerf-0.1.0/.github/workflows/tests.yml +20 -0
- kerf-0.1.0/.gitignore +28 -0
- kerf-0.1.0/PKG-INFO +102 -0
- kerf-0.1.0/README.md +73 -0
- kerf-0.1.0/docs/concepts/design-decisions.md +40 -0
- kerf-0.1.0/docs/concepts/engine.md +52 -0
- kerf-0.1.0/docs/concepts/fallback-policies.md +30 -0
- kerf-0.1.0/docs/getting-started/installation.md +50 -0
- kerf-0.1.0/docs/getting-started/project-structure.md +41 -0
- kerf-0.1.0/docs/getting-started/quickstart.md +101 -0
- kerf-0.1.0/docs/guides/logs.md +59 -0
- kerf-0.1.0/docs/guides/mcp.md +55 -0
- kerf-0.1.0/docs/guides/server.md +59 -0
- kerf-0.1.0/docs/guides/tools.md +101 -0
- kerf-0.1.0/docs/guides/workflows.md +101 -0
- kerf-0.1.0/docs/index.md +37 -0
- kerf-0.1.0/docs/reference/builtins.md +136 -0
- kerf-0.1.0/docs/reference/cli.md +145 -0
- kerf-0.1.0/docs/reference/configuration.md +56 -0
- kerf-0.1.0/docs/reference/server-api.md +49 -0
- kerf-0.1.0/docs/reference/tool-api.md +65 -0
- kerf-0.1.0/docs/reference/workflow-format.md +87 -0
- kerf-0.1.0/mkdocs.yml +56 -0
- kerf-0.1.0/pyproject.toml +56 -0
- kerf-0.1.0/src/kerf/__init__.py +3 -0
- kerf-0.1.0/src/kerf/builtins.py +136 -0
- kerf-0.1.0/src/kerf/cli.py +259 -0
- kerf-0.1.0/src/kerf/config.py +60 -0
- kerf-0.1.0/src/kerf/engine.py +127 -0
- kerf-0.1.0/src/kerf/gar.py +93 -0
- kerf-0.1.0/src/kerf/models.py +40 -0
- kerf-0.1.0/src/kerf/prompts.py +35 -0
- kerf-0.1.0/src/kerf/scaffold/__init__.py +106 -0
- kerf-0.1.0/src/kerf/scaffold/example_classify.json +13 -0
- kerf-0.1.0/src/kerf/scaffold/example_clean.json +8 -0
- kerf-0.1.0/src/kerf/scaffold/example_extract.json +13 -0
- kerf-0.1.0/src/kerf/scaffold/example_workflow.json +10 -0
- kerf-0.1.0/src/kerf/scaffold/mcp_config_template.json +5 -0
- kerf-0.1.0/src/kerf/scaffold/tool_template.py +11 -0
- kerf-0.1.0/src/kerf/scaffold/workflow_template.json +6 -0
- kerf-0.1.0/src/kerf/server.py +39 -0
- kerf-0.1.0/src/kerf/stats.py +54 -0
- kerf-0.1.0/src/kerf/tools.py +82 -0
- kerf-0.1.0/tests/__init__.py +0 -0
- kerf-0.1.0/tests/test_builtins.py +221 -0
- kerf-0.1.0/tests/test_cli.py +69 -0
- kerf-0.1.0/tests/test_config.py +65 -0
- kerf-0.1.0/tests/test_engine.py +208 -0
- kerf-0.1.0/tests/test_gar.py +88 -0
- kerf-0.1.0/tests/test_models.py +73 -0
- kerf-0.1.0/tests/test_prompts.py +32 -0
- kerf-0.1.0/tests/test_scaffold.py +121 -0
- kerf-0.1.0/tests/test_stats.py +117 -0
- kerf-0.1.0/tests/test_tools.py +109 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: Deploy docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
pages: write
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: pages
|
|
14
|
+
cancel-in-progress: false
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
deploy:
|
|
18
|
+
environment:
|
|
19
|
+
name: github-pages
|
|
20
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
- uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.12"
|
|
27
|
+
- run: pip install mkdocs-material
|
|
28
|
+
- run: mkdocs build
|
|
29
|
+
- uses: actions/upload-pages-artifact@v3
|
|
30
|
+
with:
|
|
31
|
+
path: site/
|
|
32
|
+
- id: deployment
|
|
33
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
id-token: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
publish:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
environment:
|
|
15
|
+
name: pypi
|
|
16
|
+
url: https://pypi.org/p/kerf
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
- run: pip install build
|
|
23
|
+
- run: python -m build
|
|
24
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: ${{ matrix.python-version }}
|
|
19
|
+
- run: pip install -e ".[dev]"
|
|
20
|
+
- run: pytest
|
kerf-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
|
|
8
|
+
# Virtual environments
|
|
9
|
+
.venv/
|
|
10
|
+
|
|
11
|
+
# uv
|
|
12
|
+
uv.lock
|
|
13
|
+
|
|
14
|
+
# OS
|
|
15
|
+
.DS_Store
|
|
16
|
+
|
|
17
|
+
# IDE
|
|
18
|
+
.vscode/
|
|
19
|
+
.idea/
|
|
20
|
+
|
|
21
|
+
# Testing
|
|
22
|
+
.pytest_cache/
|
|
23
|
+
.coverage
|
|
24
|
+
htmlcov/
|
|
25
|
+
|
|
26
|
+
# Kerf project artifacts (for testing)
|
|
27
|
+
logs/
|
|
28
|
+
.kerf
|
kerf-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kerf
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Declarative workflow engine where the LLM is a pluggable, disposable step
|
|
5
|
+
Project-URL: Homepage, https://github.com/derek-yn-zhang/kerf
|
|
6
|
+
Project-URL: Documentation, https://derek-yn-zhang.github.io/kerf/
|
|
7
|
+
Project-URL: Repository, https://github.com/derek-yn-zhang/kerf
|
|
8
|
+
Project-URL: Issues, https://github.com/derek-yn-zhang/kerf/issues
|
|
9
|
+
Author: Derek Zhang
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: click>=8.1
|
|
20
|
+
Requires-Dist: fastapi>=0.100
|
|
21
|
+
Requires-Dist: pydantic>=2.0
|
|
22
|
+
Requires-Dist: tomli>=2.0; python_version < '3.11'
|
|
23
|
+
Requires-Dist: uvicorn>=0.23
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: httpx>=0.24; extra == 'dev'
|
|
26
|
+
Requires-Dist: mkdocs-material>=9.5; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
<p align="center">
|
|
31
|
+
<strong>Kerf</strong><br>
|
|
32
|
+
Declarative workflow engine for Claude CLI
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
Kerf runs deterministic tools first, calls the LLM only when you need reasoning, and logs every result. Pipelines are defined as JSON — no Python required to configure a workflow.
|
|
38
|
+
|
|
39
|
+
- **Deterministic-first** — preprocessing runs without the LLM until you actually need it
|
|
40
|
+
- **JSON workflows** — define tool chains, prompt templates, and fallback policies as config
|
|
41
|
+
- **Per-workflow fallback** — `retry` the LLM, degrade to `deterministic` output, or `flag` for review
|
|
42
|
+
- **Full execution logging** — every run gets a UUID-stamped log you can audit and learn from
|
|
43
|
+
- **Auto-discovered tools** — drop a Python file in `tools/`, it gets picked up
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
uv tool install kerf
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Requires Python 3.10+ and Claude CLI (`claude login`).
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
kerf init
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Kerf project initialized.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
kerf run summarize "Kerf is a workflow engine that wraps Claude CLI..."
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"summary": "Kerf is a declarative workflow engine that wraps Claude CLI for structured, deterministic text processing."
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
A workflow is a JSON file in `workflows/`:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"task_type": "summarization",
|
|
78
|
+
"tool_chain": [{ "tool": "normalize_text", "condition": "always_true" }],
|
|
79
|
+
"fallback": "retry"
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`tool_chain` runs deterministic preprocessing. `task_type` sends the result to Claude. `fallback` controls what happens when the LLM fails.
|
|
84
|
+
|
|
85
|
+
Custom tools go in `tools/` as Python files with a `register(manager)` function:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
# tools/uppercase.py
|
|
89
|
+
def uppercase(input_data, params):
|
|
90
|
+
return input_data.upper()
|
|
91
|
+
|
|
92
|
+
def register(manager):
|
|
93
|
+
manager.register_tool("uppercase", uppercase)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Documentation
|
|
97
|
+
|
|
98
|
+
Full docs at [derek-yn-zhang.github.io/kerf](https://derek-yn-zhang.github.io/kerf/).
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
MIT
|
kerf-0.1.0/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<strong>Kerf</strong><br>
|
|
3
|
+
Declarative workflow engine for Claude CLI
|
|
4
|
+
</p>
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Kerf runs deterministic tools first, calls the LLM only when you need reasoning, and logs every result. Pipelines are defined as JSON — no Python required to configure a workflow.
|
|
9
|
+
|
|
10
|
+
- **Deterministic-first** — preprocessing runs without the LLM until you actually need it
|
|
11
|
+
- **JSON workflows** — define tool chains, prompt templates, and fallback policies as config
|
|
12
|
+
- **Per-workflow fallback** — `retry` the LLM, degrade to `deterministic` output, or `flag` for review
|
|
13
|
+
- **Full execution logging** — every run gets a UUID-stamped log you can audit and learn from
|
|
14
|
+
- **Auto-discovered tools** — drop a Python file in `tools/`, it gets picked up
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
uv tool install kerf
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Requires Python 3.10+ and Claude CLI (`claude login`).
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
kerf init
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
Kerf project initialized.
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
kerf run summarize "Kerf is a workflow engine that wraps Claude CLI..."
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"summary": "Kerf is a declarative workflow engine that wraps Claude CLI for structured, deterministic text processing."
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
A workflow is a JSON file in `workflows/`:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"task_type": "summarization",
|
|
49
|
+
"tool_chain": [{ "tool": "normalize_text", "condition": "always_true" }],
|
|
50
|
+
"fallback": "retry"
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`tool_chain` runs deterministic preprocessing. `task_type` sends the result to Claude. `fallback` controls what happens when the LLM fails.
|
|
55
|
+
|
|
56
|
+
Custom tools go in `tools/` as Python files with a `register(manager)` function:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
# tools/uppercase.py
|
|
60
|
+
def uppercase(input_data, params):
|
|
61
|
+
return input_data.upper()
|
|
62
|
+
|
|
63
|
+
def register(manager):
|
|
64
|
+
manager.register_tool("uppercase", uppercase)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Documentation
|
|
68
|
+
|
|
69
|
+
Full docs at [derek-yn-zhang.github.io/kerf](https://derek-yn-zhang.github.io/kerf/).
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
MIT
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Design Decisions
|
|
2
|
+
|
|
3
|
+
## Why subprocess, not SDK?
|
|
4
|
+
|
|
5
|
+
Kerf shells out to the Claude CLI (`claude -p`) rather than using Anthropic's Python SDK. This means:
|
|
6
|
+
|
|
7
|
+
- It works with whatever authentication the CLI provides, including Max Plan
|
|
8
|
+
- No API keys to manage
|
|
9
|
+
- No dependency on Anthropic's SDK versioning
|
|
10
|
+
- The CLI handles model selection, rate limiting, and context management
|
|
11
|
+
|
|
12
|
+
The tradeoff is latency — spawning a subprocess is slower than an HTTP call. But the LLM call itself dominates the total time, so the subprocess overhead is negligible.
|
|
13
|
+
|
|
14
|
+
## Why sync, not async?
|
|
15
|
+
|
|
16
|
+
The engine is synchronous. `subprocess.run` and file I/O are blocking operations. There's no benefit to async here — the bottleneck is the LLM call, and you can't parallelize a single CLI invocation.
|
|
17
|
+
|
|
18
|
+
The FastAPI server handles concurrency at the request level. When you define the endpoint as a regular `def` (not `async def`), FastAPI runs each request in a thread pool automatically.
|
|
19
|
+
|
|
20
|
+
## Why named conditions instead of expressions?
|
|
21
|
+
|
|
22
|
+
Workflow files are JSON. If conditions were inline expressions like `"len(input) > 500"`, you'd need either an expression parser or `eval()`. Both are worse than a simple name-to-function registry:
|
|
23
|
+
|
|
24
|
+
- `eval()` is a security risk
|
|
25
|
+
- Expression parsers add complexity for marginal benefit
|
|
26
|
+
- Named conditions are explicit, debuggable, and inspectable
|
|
27
|
+
- You can set breakpoints in condition functions
|
|
28
|
+
|
|
29
|
+
The cost is that you have to write a Python function and register it. The benefit is that your workflow files stay data — no code in config.
|
|
30
|
+
|
|
31
|
+
## Why JSON workflows, not Python?
|
|
32
|
+
|
|
33
|
+
Python workflow definitions would be more expressive, but JSON workflows are:
|
|
34
|
+
|
|
35
|
+
- Editable by anyone, even people who don't write Python
|
|
36
|
+
- Serializable and transferable — you can store them in a database, send them over HTTP, version them in git
|
|
37
|
+
- Inspectable — `kerf list` can read them without importing any code
|
|
38
|
+
- Constrained — they can't do anything surprising
|
|
39
|
+
|
|
40
|
+
The tool chain is where Python lives. The workflow file is where configuration lives. Keeping them separate means you can change pipeline behavior without touching code.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# How the Engine Works
|
|
2
|
+
|
|
3
|
+
Kerf is a thin orchestration layer over the Claude CLI. It doesn't embed a model, manage API keys, or do anything clever with tokens. It wraps `claude -p --output-format json` in a structured pipeline and adds the scaffolding to make LLM calls reproducible, validatable, and replaceable.
|
|
4
|
+
|
|
5
|
+
## Pipeline
|
|
6
|
+
|
|
7
|
+
Every workflow execution follows the same sequence:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
input_data
|
|
11
|
+
|
|
|
12
|
+
v
|
|
13
|
+
[tool_chain: deterministic preprocessing]
|
|
14
|
+
|
|
|
15
|
+
v
|
|
16
|
+
[LLM call via Claude CLI (optional)]
|
|
17
|
+
|
|
|
18
|
+
v
|
|
19
|
+
[schema validation → fallback if needed]
|
|
20
|
+
|
|
|
21
|
+
v
|
|
22
|
+
result (LLM output or tool output)
|
|
23
|
+
|
|
|
24
|
+
v
|
|
25
|
+
[logged to logs/<uuid>.json]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
1. Load workflow config from `workflows/<name>.json`
|
|
29
|
+
2. Set up the tool manager — register builtins, then load user tools from `tools/`
|
|
30
|
+
3. Run the deterministic tool chain on the input
|
|
31
|
+
4. If `task_type` is set, construct a prompt and call the LLM via Claude CLI
|
|
32
|
+
5. If a `schema_path` is set, validate the LLM output — check that all required keys are present
|
|
33
|
+
6. On validation failure, apply the fallback policy
|
|
34
|
+
7. Log the full result to `logs/<uuid>.json`
|
|
35
|
+
|
|
36
|
+
## Components
|
|
37
|
+
|
|
38
|
+
**GARInterface** wraps the Claude CLI's headless mode (GAR = Generate, Analyze, Return). It checks that `claude` is on your PATH, calls `claude -p <prompt> --output-format json`, and parses the JSON response. Claude CLI handles its own authentication — Kerf doesn't manage credentials.
|
|
39
|
+
|
|
40
|
+
**LocalToolManager** is a registry for deterministic tools and named conditions. Tools and conditions are registered by name (strings), not as lambdas. The workflow JSON references these names, and the manager resolves them at runtime. This is what keeps workflows fully serializable.
|
|
41
|
+
|
|
42
|
+
**Engine** is the `execute_workflow()` function that ties it together. Both `kerf run` and `POST /execute` call the same function — there's no separate CLI vs server path.
|
|
43
|
+
|
|
44
|
+
## Tool resolution order
|
|
45
|
+
|
|
46
|
+
1. Built-in tools and conditions register first (`normalize_text`, `route_by_length`, `always_true`)
|
|
47
|
+
2. User tools from `tools/` register second
|
|
48
|
+
3. User tools can override builtins by registering the same name
|
|
49
|
+
|
|
50
|
+
## Project detection
|
|
51
|
+
|
|
52
|
+
Kerf walks up from the current working directory looking for a `.kerf` marker file, the same way git looks for `.git/`. This means you can run `kerf run` from any subdirectory of your project.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Fallback Policies
|
|
2
|
+
|
|
3
|
+
Each workflow declares how much it trusts the LLM. The `fallback` field controls what happens when the LLM call fails or returns output that doesn't match the schema.
|
|
4
|
+
|
|
5
|
+
## Policies
|
|
6
|
+
|
|
7
|
+
| Policy | What happens | When to use it |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| `retry` | Call the LLM again | Tasks like summarization where there's no good deterministic alternative — just try again |
|
|
10
|
+
| `deterministic` | Skip the LLM, return the preprocessed output | Tasks like classification where the LLM is flaky — fall back to whatever the tool chain produced |
|
|
11
|
+
| `flag` | Return the error in the output | Ambiguous cases — log the failure, deal with it later |
|
|
12
|
+
|
|
13
|
+
## When fallback triggers
|
|
14
|
+
|
|
15
|
+
Fallback triggers in two situations:
|
|
16
|
+
|
|
17
|
+
1. **The LLM call fails** — Claude CLI returns a non-zero exit code, or the output isn't valid JSON
|
|
18
|
+
2. **Schema validation fails** — the LLM returned JSON, but it's missing required keys defined in `schema_path`
|
|
19
|
+
|
|
20
|
+
The schema check is the confidence gate. If you asked the LLM to return `{"category": "..."}` and it returned `{"label": "..."}`, it didn't follow instructions. The fallback kicks in.
|
|
21
|
+
|
|
22
|
+
## Choosing a policy
|
|
23
|
+
|
|
24
|
+
The right policy depends on whether a deterministic alternative exists:
|
|
25
|
+
|
|
26
|
+
- **Summarization** has no good deterministic fallback. If the LLM fails, `retry` is the best option.
|
|
27
|
+
- **Classification** often has a rules-based fallback. Use `deterministic` to degrade gracefully.
|
|
28
|
+
- **Ambiguous extractions** where you're not sure what the right answer is — use `flag` to log the failure and review manually.
|
|
29
|
+
|
|
30
|
+
The policy is per-workflow, so you tune trust on a per-task basis. A workflow that's been running reliably for weeks might use `retry`. A new workflow you're still tuning might use `flag` until you've seen enough logs to trust it.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Installation
|
|
2
|
+
|
|
3
|
+
## Prerequisites
|
|
4
|
+
|
|
5
|
+
- Python 3.10+
|
|
6
|
+
- [Claude CLI](https://docs.anthropic.com/en/docs/claude-code) — run `claude login` to authenticate
|
|
7
|
+
- [uv](https://docs.astral.sh/uv/) (recommended) or pipx
|
|
8
|
+
|
|
9
|
+
Kerf calls Claude CLI under the hood. If you see `"Claude CLI not found on PATH"`, install [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and run `claude login` to authenticate.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uv tool install kerf
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or with pipx:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pipx install kerf
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or from source:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
git clone https://github.com/yourusername/kerf.git
|
|
27
|
+
cd kerf
|
|
28
|
+
uv tool install .
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Verify the installation:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
kerf --help
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
Usage: kerf [OPTIONS] COMMAND [ARGS]...
|
|
39
|
+
|
|
40
|
+
Kerf — declarative workflow engine where the LLM is a pluggable,
|
|
41
|
+
disposable step.
|
|
42
|
+
|
|
43
|
+
Commands:
|
|
44
|
+
add Add a new workflow, tool, or MCP config.
|
|
45
|
+
init Scaffold a new kerf project in the current directory.
|
|
46
|
+
list List available workflows and tools.
|
|
47
|
+
logs View recent execution logs.
|
|
48
|
+
run Execute a workflow.
|
|
49
|
+
serve Start the Kerf API server.
|
|
50
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Project Structure
|
|
2
|
+
|
|
3
|
+
After running `kerf init`, your project looks like this:
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
my-pipeline/
|
|
7
|
+
.kerf # project marker
|
|
8
|
+
workflows/
|
|
9
|
+
summarize.json # summarization example
|
|
10
|
+
classify.json # classification example
|
|
11
|
+
extract.json # structured extraction example
|
|
12
|
+
schemas/
|
|
13
|
+
tools/ # your custom tool files go here
|
|
14
|
+
logs/
|
|
15
|
+
kerf.toml # project config
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Directories
|
|
19
|
+
|
|
20
|
+
**`workflows/`** — JSON files that define pipelines. Each file is a workflow you can run by name. See [Workflow Format](../reference/workflow-format.md).
|
|
21
|
+
|
|
22
|
+
**`tools/`** — Python files with deterministic tool functions. Any `.py` file that exports a `register(manager)` function gets auto-loaded. See [Writing Tools](../guides/tools.md).
|
|
23
|
+
|
|
24
|
+
**`schemas/`** — JSON schema files for validating LLM output. Referenced by `schema_path` in workflow configs.
|
|
25
|
+
|
|
26
|
+
**`logs/`** — Execution logs. Each run creates a UUID-stamped JSON file with the full input/output record.
|
|
27
|
+
|
|
28
|
+
## Files
|
|
29
|
+
|
|
30
|
+
**`.kerf`** — Marker file that identifies the project root. Kerf walks up from your current directory looking for this file (like `.git`), so you can run commands from subdirectories.
|
|
31
|
+
|
|
32
|
+
**`kerf.toml`** — Optional project-level configuration:
|
|
33
|
+
|
|
34
|
+
```toml
|
|
35
|
+
# [server]
|
|
36
|
+
# host = "0.0.0.0"
|
|
37
|
+
# port = 8000
|
|
38
|
+
|
|
39
|
+
# [defaults]
|
|
40
|
+
# fallback = "retry"
|
|
41
|
+
```
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Quickstart
|
|
2
|
+
|
|
3
|
+
This walks through scaffolding a project, running a workflow, and reading the output. Takes about 2 minutes.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
Kerf calls [Claude Code](https://docs.anthropic.com/en/docs/claude-code) under the hood. Make sure it's installed and authenticated:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
claude --version
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
If that fails, [install Claude Code](https://docs.anthropic.com/en/docs/claude-code) first. Then authenticate:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
claude login
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
If `kerf run` fails with `"Claude CLI not found on PATH"`, you need to install Claude Code first.
|
|
20
|
+
|
|
21
|
+
## Create a project
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
mkdir my-pipeline && cd my-pipeline
|
|
25
|
+
kerf init
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This creates the standard project structure with three example workflows. See [Project Structure](project-structure.md) for details.
|
|
29
|
+
|
|
30
|
+
## Run the example workflows
|
|
31
|
+
|
|
32
|
+
The scaffolded project includes `summarize`, `classify`, and `extract` workflows:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
kerf run summarize "The quarterly earnings report showed revenue growth of 15%, driven by enterprise expansion and strong retention."
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"summary": "Quarterly revenue grew 15% YoY, driven by enterprise expansion and strong retention."
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
kerf run classify "The login page crashes when I enter my email with a + sign"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"category": "bug",
|
|
51
|
+
"confidence": "high"
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
kerf run extract "Hi, I'm Sarah Chen (sarah@acme.co), VP of Engineering at Acme Corp."
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"name": "Sarah Chen",
|
|
62
|
+
"email": "sarah@acme.co",
|
|
63
|
+
"company": "Acme Corp",
|
|
64
|
+
"role": "VP of Engineering"
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
You can also pipe input from stdin:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
cat article.txt | kerf run summarize
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Check the logs
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
kerf logs --last 1
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"workflow": "summarize",
|
|
83
|
+
"timestamp": "2025-01-15T14:32:01+00:00",
|
|
84
|
+
"input_preview": "The quarterly earnings report showed...",
|
|
85
|
+
"task_type": "summarization",
|
|
86
|
+
"tool_chain": ["normalize_text"],
|
|
87
|
+
"fallback_policy": "retry",
|
|
88
|
+
"fallback_triggered": false,
|
|
89
|
+
"preprocessed": "the quarterly earnings report showed...",
|
|
90
|
+
"result": { "summary": "..." }
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Every execution is logged with a UUID filename in `logs/`. The user-facing output is just the `result` — the log captures the full pipeline breakdown for debugging and pattern extraction.
|
|
95
|
+
|
|
96
|
+
## What's next
|
|
97
|
+
|
|
98
|
+
- [Writing Workflows](../guides/workflows.md) — create your own pipelines
|
|
99
|
+
- [Writing Tools](../guides/tools.md) — add custom preprocessing steps
|
|
100
|
+
- [Reading Logs](../guides/logs.md) — audit execution results and extract patterns
|
|
101
|
+
- [Using the API Server](../guides/server.md) — run workflows over HTTP
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Reading Logs
|
|
2
|
+
|
|
3
|
+
Every workflow execution creates a log file in `logs/`. Each file is named with a UUID and contains the full execution record.
|
|
4
|
+
|
|
5
|
+
## View recent logs
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
kerf logs
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"workflow": "summarize",
|
|
14
|
+
"timestamp": "2025-01-15T14:32:01+00:00",
|
|
15
|
+
"input_preview": "The quarterly earnings report showed...",
|
|
16
|
+
"task_type": "summarization",
|
|
17
|
+
"tool_chain": ["normalize_text"],
|
|
18
|
+
"fallback_policy": "retry",
|
|
19
|
+
"fallback_triggered": false,
|
|
20
|
+
"preprocessed": "the quarterly earnings report showed...",
|
|
21
|
+
"result": { "summary": "..." }
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Filter and limit
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
kerf logs --last 5 # show 5 most recent
|
|
29
|
+
kerf logs --workflow summarize # filter by workflow name
|
|
30
|
+
kerf logs --last 3 --workflow classify
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Log format
|
|
34
|
+
|
|
35
|
+
Each log file is a JSON object:
|
|
36
|
+
|
|
37
|
+
| Field | Description |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `workflow` | Name of the workflow that ran |
|
|
40
|
+
| `timestamp` | ISO 8601 UTC timestamp |
|
|
41
|
+
| `input_preview` | First 200 characters of the raw input |
|
|
42
|
+
| `task_type` | Prompt template used (or `null` for tool-only workflows) |
|
|
43
|
+
| `tool_chain` | List of tool names that ran in the preprocessing step |
|
|
44
|
+
| `fallback_policy` | Which fallback policy was configured |
|
|
45
|
+
| `fallback_triggered` | `true` if the LLM call failed and fallback was used |
|
|
46
|
+
| `preprocessed` | Output after the tool chain ran (before LLM) |
|
|
47
|
+
| `result` | The final result returned to the user |
|
|
48
|
+
|
|
49
|
+
## Why logging matters
|
|
50
|
+
|
|
51
|
+
Logs are how you move away from LLM dependence. The workflow:
|
|
52
|
+
|
|
53
|
+
1. Run a workflow against real inputs
|
|
54
|
+
2. Read the logs — look at what the LLM actually returned
|
|
55
|
+
3. Spot the pattern — does it always do the same transformation?
|
|
56
|
+
4. Write a tool that does the same thing deterministically
|
|
57
|
+
5. Remove the `task_type` from the workflow — no more LLM call
|
|
58
|
+
|
|
59
|
+
The LLM is scaffolding. The logs are how you learn to remove it.
|