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.
Files changed (56) hide show
  1. kerf-0.1.0/.github/workflows/docs.yml +33 -0
  2. kerf-0.1.0/.github/workflows/publish.yml +24 -0
  3. kerf-0.1.0/.github/workflows/tests.yml +20 -0
  4. kerf-0.1.0/.gitignore +28 -0
  5. kerf-0.1.0/PKG-INFO +102 -0
  6. kerf-0.1.0/README.md +73 -0
  7. kerf-0.1.0/docs/concepts/design-decisions.md +40 -0
  8. kerf-0.1.0/docs/concepts/engine.md +52 -0
  9. kerf-0.1.0/docs/concepts/fallback-policies.md +30 -0
  10. kerf-0.1.0/docs/getting-started/installation.md +50 -0
  11. kerf-0.1.0/docs/getting-started/project-structure.md +41 -0
  12. kerf-0.1.0/docs/getting-started/quickstart.md +101 -0
  13. kerf-0.1.0/docs/guides/logs.md +59 -0
  14. kerf-0.1.0/docs/guides/mcp.md +55 -0
  15. kerf-0.1.0/docs/guides/server.md +59 -0
  16. kerf-0.1.0/docs/guides/tools.md +101 -0
  17. kerf-0.1.0/docs/guides/workflows.md +101 -0
  18. kerf-0.1.0/docs/index.md +37 -0
  19. kerf-0.1.0/docs/reference/builtins.md +136 -0
  20. kerf-0.1.0/docs/reference/cli.md +145 -0
  21. kerf-0.1.0/docs/reference/configuration.md +56 -0
  22. kerf-0.1.0/docs/reference/server-api.md +49 -0
  23. kerf-0.1.0/docs/reference/tool-api.md +65 -0
  24. kerf-0.1.0/docs/reference/workflow-format.md +87 -0
  25. kerf-0.1.0/mkdocs.yml +56 -0
  26. kerf-0.1.0/pyproject.toml +56 -0
  27. kerf-0.1.0/src/kerf/__init__.py +3 -0
  28. kerf-0.1.0/src/kerf/builtins.py +136 -0
  29. kerf-0.1.0/src/kerf/cli.py +259 -0
  30. kerf-0.1.0/src/kerf/config.py +60 -0
  31. kerf-0.1.0/src/kerf/engine.py +127 -0
  32. kerf-0.1.0/src/kerf/gar.py +93 -0
  33. kerf-0.1.0/src/kerf/models.py +40 -0
  34. kerf-0.1.0/src/kerf/prompts.py +35 -0
  35. kerf-0.1.0/src/kerf/scaffold/__init__.py +106 -0
  36. kerf-0.1.0/src/kerf/scaffold/example_classify.json +13 -0
  37. kerf-0.1.0/src/kerf/scaffold/example_clean.json +8 -0
  38. kerf-0.1.0/src/kerf/scaffold/example_extract.json +13 -0
  39. kerf-0.1.0/src/kerf/scaffold/example_workflow.json +10 -0
  40. kerf-0.1.0/src/kerf/scaffold/mcp_config_template.json +5 -0
  41. kerf-0.1.0/src/kerf/scaffold/tool_template.py +11 -0
  42. kerf-0.1.0/src/kerf/scaffold/workflow_template.json +6 -0
  43. kerf-0.1.0/src/kerf/server.py +39 -0
  44. kerf-0.1.0/src/kerf/stats.py +54 -0
  45. kerf-0.1.0/src/kerf/tools.py +82 -0
  46. kerf-0.1.0/tests/__init__.py +0 -0
  47. kerf-0.1.0/tests/test_builtins.py +221 -0
  48. kerf-0.1.0/tests/test_cli.py +69 -0
  49. kerf-0.1.0/tests/test_config.py +65 -0
  50. kerf-0.1.0/tests/test_engine.py +208 -0
  51. kerf-0.1.0/tests/test_gar.py +88 -0
  52. kerf-0.1.0/tests/test_models.py +73 -0
  53. kerf-0.1.0/tests/test_prompts.py +32 -0
  54. kerf-0.1.0/tests/test_scaffold.py +121 -0
  55. kerf-0.1.0/tests/test_stats.py +117 -0
  56. 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.