pedalpoint 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 (32) hide show
  1. pedalpoint-0.1.0/.github/workflows/ci.yml +98 -0
  2. pedalpoint-0.1.0/.github/workflows/release.yml +75 -0
  3. pedalpoint-0.1.0/.gitignore +14 -0
  4. pedalpoint-0.1.0/CLAUDE.md +83 -0
  5. pedalpoint-0.1.0/PKG-INFO +107 -0
  6. pedalpoint-0.1.0/README.md +91 -0
  7. pedalpoint-0.1.0/docs/superpowers/plans/2026-05-08-pedalpoint.md +2076 -0
  8. pedalpoint-0.1.0/docs/superpowers/specs/2026-05-08-pedalpoint-design.md +496 -0
  9. pedalpoint-0.1.0/install.sh +173 -0
  10. pedalpoint-0.1.0/pyproject.toml +50 -0
  11. pedalpoint-0.1.0/skills/route-tasks.md +177 -0
  12. pedalpoint-0.1.0/src/pedalpoint/__init__.py +0 -0
  13. pedalpoint-0.1.0/src/pedalpoint/circuit_breaker.py +74 -0
  14. pedalpoint-0.1.0/src/pedalpoint/config.py +27 -0
  15. pedalpoint-0.1.0/src/pedalpoint/error_classifier.py +16 -0
  16. pedalpoint-0.1.0/src/pedalpoint/server.py +72 -0
  17. pedalpoint-0.1.0/tests/__init__.py +0 -0
  18. pedalpoint-0.1.0/tests/install/test_install.bats +228 -0
  19. pedalpoint-0.1.0/tests/integration/__init__.py +0 -0
  20. pedalpoint-0.1.0/tests/integration/test_ollama.py +31 -0
  21. pedalpoint-0.1.0/tests/skill/__init__.py +0 -0
  22. pedalpoint-0.1.0/tests/skill/scenarios/__init__.py +0 -0
  23. pedalpoint-0.1.0/tests/skill/scenarios/fallback_trigger.md +27 -0
  24. pedalpoint-0.1.0/tests/skill/scenarios/judgment_routing.md +18 -0
  25. pedalpoint-0.1.0/tests/skill/scenarios/mechanical_routing.md +24 -0
  26. pedalpoint-0.1.0/tests/skill/scenarios/probe_failure.md +22 -0
  27. pedalpoint-0.1.0/tests/skill/scenarios/probe_success.md +16 -0
  28. pedalpoint-0.1.0/tests/unit/__init__.py +0 -0
  29. pedalpoint-0.1.0/tests/unit/test_circuit_breaker.py +185 -0
  30. pedalpoint-0.1.0/tests/unit/test_config.py +67 -0
  31. pedalpoint-0.1.0/tests/unit/test_error_classifier.py +48 -0
  32. pedalpoint-0.1.0/tests/unit/test_server.py +116 -0
@@ -0,0 +1,98 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: ["main", "feat/**", "fix/**", "chore/**", "test/**", "docs/**"]
6
+ pull_request:
7
+ branches: ["main"]
8
+
9
+ jobs:
10
+ unit-tests:
11
+ name: Unit Tests (Python ${{ matrix.python-version }})
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ python-version: ["3.11", "3.12"]
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Set up Python ${{ matrix.python-version }}
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+
25
+ - name: Install dependencies
26
+ run: pip install -e ".[dev]"
27
+
28
+ - name: Run unit tests with coverage
29
+ run: |
30
+ pytest tests/unit/ -v \
31
+ --cov=pedalpoint \
32
+ --cov-report=term-missing \
33
+ --cov-fail-under=90
34
+
35
+ integration-tests:
36
+ name: Integration Tests (Ollama)
37
+ runs-on: ubuntu-latest
38
+ needs: unit-tests
39
+
40
+ steps:
41
+ - uses: actions/checkout@v4
42
+
43
+ - name: Set up Python 3.11
44
+ uses: actions/setup-python@v5
45
+ with:
46
+ python-version: "3.11"
47
+
48
+ - name: Install Ollama
49
+ run: curl -fsSL https://ollama.ai/install.sh | sh
50
+
51
+ - name: Start Ollama and pull model
52
+ run: |
53
+ ollama serve &
54
+ timeout 30 bash -c 'until ollama list 2>/dev/null; do sleep 1; done'
55
+ ollama pull gemma4:e4b
56
+
57
+ - name: Install dependencies
58
+ run: pip install -e ".[dev]"
59
+
60
+ - name: Run integration tests
61
+ env:
62
+ PEDALPOINT_INTEGRATION: "true"
63
+ PEDALPOINT_MODEL: "gemma4:e4b"
64
+ run: pytest tests/integration/ -v
65
+
66
+ install-tests:
67
+ name: Install Script Tests
68
+ runs-on: ubuntu-latest
69
+
70
+ steps:
71
+ - uses: actions/checkout@v4
72
+
73
+ - name: Install bats
74
+ run: sudo apt-get install -y bats
75
+
76
+ - name: Run install script tests
77
+ run: bats tests/install/ -v
78
+
79
+ lint:
80
+ name: Lint
81
+ runs-on: ubuntu-latest
82
+
83
+ steps:
84
+ - uses: actions/checkout@v4
85
+
86
+ - name: Set up Python 3.11
87
+ uses: actions/setup-python@v5
88
+ with:
89
+ python-version: "3.11"
90
+
91
+ - name: Install ruff
92
+ run: pip install ruff
93
+
94
+ - name: Run ruff check
95
+ run: ruff check src/ tests/
96
+
97
+ - name: Run ruff format check
98
+ run: ruff format --check src/ tests/
@@ -0,0 +1,75 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*"
7
+
8
+ jobs:
9
+ build:
10
+ name: Build distribution
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ with:
16
+ persist-credentials: false
17
+
18
+ - name: Set up Python 3.11
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.11"
22
+
23
+ - name: Install build
24
+ run: pip install build
25
+
26
+ - name: Build sdist and wheel
27
+ run: python3 -m build
28
+
29
+ - name: Upload dist
30
+ uses: actions/upload-artifact@v4
31
+ with:
32
+ name: python-package-distributions
33
+ path: dist/
34
+
35
+ publish-to-testpypi:
36
+ name: Publish to TestPyPI
37
+ needs: build
38
+ runs-on: ubuntu-latest
39
+ environment:
40
+ name: testpypi
41
+ url: https://test.pypi.org/p/pedalpoint
42
+ permissions:
43
+ id-token: write
44
+
45
+ steps:
46
+ - name: Download dist
47
+ uses: actions/download-artifact@v4
48
+ with:
49
+ name: python-package-distributions
50
+ path: dist/
51
+
52
+ - name: Publish to TestPyPI
53
+ uses: pypa/gh-action-pypi-publish@release/v1
54
+ with:
55
+ repository-url: https://test.pypi.org/legacy/
56
+
57
+ publish-to-pypi:
58
+ name: Publish to PyPI
59
+ needs: publish-to-testpypi
60
+ runs-on: ubuntu-latest
61
+ environment:
62
+ name: pypi
63
+ url: https://pypi.org/p/pedalpoint
64
+ permissions:
65
+ id-token: write
66
+
67
+ steps:
68
+ - name: Download dist
69
+ uses: actions/download-artifact@v4
70
+ with:
71
+ name: python-package-distributions
72
+ path: dist/
73
+
74
+ - name: Publish to PyPI
75
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,14 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .venv/
7
+ venv/
8
+ .pytest_cache/
9
+ .coverage
10
+ htmlcov/
11
+ *.log
12
+ .env
13
+ .ruff_cache/
14
+ .DS_Store
@@ -0,0 +1,83 @@
1
+ # pedalpoint — Developer Guide
2
+
3
+ ## Project Overview
4
+
5
+ MCP server + companion superpowers skill. Two deliverables:
6
+ 1. `pedalpoint-server` — Python binary (FastMCP, httpx)
7
+ 2. `skills/route-tasks.md` — Markdown skill for Claude Code
8
+
9
+ ## Key Design Decisions
10
+
11
+ - **Thin server, smart skill:** Server is a pure HTTP proxy. All routing logic lives in the skill. Server never touches `~/.pedalpoint/state.json`.
12
+ - **No streaming:** `local_llm` returns full string. Simpler, sufficient for code gen.
13
+ - **Circuit breaker in skill:** Claude reads/writes state.json via Write tool. Python `circuit_breaker.py` module contains the pure functions that document and validate this logic.
14
+ - **Context Courier:** Skill MUST grep codebase before sending any task to local LLM. Empty grep result = escalate to Agent.
15
+
16
+ ## Branch Strategy
17
+
18
+ - `main` — always stable, PR only, squash merge
19
+ - `feat/<name>` — new functionality
20
+ - `fix/<name>` — bug fixes
21
+ - `chore/<name>` — tooling, config, deps
22
+ - `test/<name>` — test-only changes
23
+ - `docs/<name>` — documentation
24
+
25
+ Branch on everything, including README and CLAUDE.md changes.
26
+
27
+ ## TDD Workflow
28
+
29
+ 1. Write failing test
30
+ 2. Run to confirm failure
31
+ 3. Implement minimal code
32
+ 4. Run to confirm pass
33
+ 5. Commit
34
+
35
+ Coverage requirements: circuit_breaker.py = 100%, error_classifier.py = 100%, server.py ≥ 90%
36
+
37
+ ## Running Tests
38
+
39
+ ```sh
40
+ # Unit tests (fast, no Ollama needed)
41
+ pytest tests/unit/ -v --cov=pedalpoint --cov-report=term-missing
42
+
43
+ # Integration tests (requires Ollama running with gemma4:e4b pulled)
44
+ PEDALPOINT_INTEGRATION=true pytest tests/integration/ -v
45
+
46
+ # All unit tests with coverage check
47
+ pytest tests/unit/ --cov=pedalpoint --cov-fail-under=90
48
+ ```
49
+
50
+ ## File Responsibilities
51
+
52
+ | File | Responsibility |
53
+ |---|---|
54
+ | `src/pedalpoint/config.py` | Load env vars into frozen Config dataclass |
55
+ | `src/pedalpoint/error_classifier.py` | Regex classify error strings → error type |
56
+ | `src/pedalpoint/circuit_breaker.py` | Pure fns for state transitions, expiry, backoff |
57
+ | `src/pedalpoint/server.py` | FastMCP app, lifespan, `local_llm` tool, `_call_local_llm` |
58
+ | `skills/route-tasks.md` | Claude instructions: routing, Context Courier, circuit breaker |
59
+ | `install.sh` | Install pkg, pull model, register MCP config, copy skill |
60
+
61
+ ## State File Format
62
+
63
+ `~/.pedalpoint/state.json`:
64
+ ```json
65
+ {
66
+ "circuit": "open",
67
+ "reason": "402_quota",
68
+ "opened_at": "2026-05-08T15:30:00+00:00",
69
+ "expires": "2026-05-08T16:30:00+00:00",
70
+ "failure_count": 1,
71
+ "fallback_duration_minutes": 60,
72
+ "tasks_rerouted": 3
73
+ }
74
+ ```
75
+
76
+ CLOSED state: `{"circuit": "closed"}` or file absent.
77
+
78
+ ## Common Gotchas
79
+
80
+ - `get_config()` uses `lru_cache`. Tests must call `get_config.cache_clear()` before and after monkeypatching env vars.
81
+ - `_call_local_llm` is the testable core; `local_llm` (the MCP tool) just unwraps ctx and delegates to it.
82
+ - 402 errors trigger permanent fallback. 429 errors trigger retry-with-backoff only. Do not conflate them.
83
+ - The companion skill has no Python backing. Skill tests are manual scenarios in `tests/skill/scenarios/`.
@@ -0,0 +1,107 @@
1
+ Metadata-Version: 2.4
2
+ Name: pedalpoint
3
+ Version: 0.1.0
4
+ Summary: MCP server that routes mechanical dev tasks to a local LLM
5
+ License: MIT
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: httpx>=0.27.0
8
+ Requires-Dist: mcp>=1.0.0
9
+ Provides-Extra: dev
10
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
11
+ Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
12
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
13
+ Requires-Dist: respx>=0.21.0; extra == 'dev'
14
+ Requires-Dist: ruff>=0.4.0; extra == 'dev'
15
+ Description-Content-Type: text/markdown
16
+
17
+ # pedalpoint
18
+
19
+ Route mechanical development tasks to a local LLM (Ollama, LM Studio, Jan) via Claude Code. Automatically falls back to local-only mode when Claude quota is exhausted.
20
+
21
+ ## What it does
22
+
23
+ - **Hybrid routing:** Claude classifies each task. Mechanical work (scaffolding, CRUD, test stubs) goes to your local LLM. Judgment work (architecture, debugging, integration) stays with Claude.
24
+ - **Quota fallback:** When Claude returns a quota error, pedalpoint automatically switches to local-only mode and continues working. Switches back when quota restores.
25
+ - **Context Courier:** Before sending any task to the local LLM, pedalpoint greps your codebase for existing patterns and injects them into the prompt. Local LLMs only get tasks they have templates for.
26
+ - **Single install:** One script installs the MCP server, pulls the default model, and registers the companion skill.
27
+
28
+ ## Requirements
29
+
30
+ - Claude Code
31
+ - Python 3.11+
32
+ - [Ollama](https://ollama.ai) (or any OpenAI-compatible inference server)
33
+
34
+ ## Install
35
+
36
+ ```sh
37
+ curl -fsSL https://raw.githubusercontent.com/EMSwank/pedalpoint/main/install.sh | sh
38
+ ```
39
+
40
+ With a custom model or endpoint:
41
+
42
+ ```sh
43
+ curl -fsSL https://raw.githubusercontent.com/EMSwank/pedalpoint/main/install.sh | \
44
+ sh -s -- --model llama3 --base-url http://localhost:11434/v1
45
+ ```
46
+
47
+ Restart Claude Code after install.
48
+
49
+ ## Usage
50
+
51
+ Instead of `superpowers:subagent-driven-development`, invoke:
52
+
53
+ ```
54
+ pedalpoint:route-tasks
55
+ ```
56
+
57
+ pedalpoint handles routing automatically. No manual flagging needed.
58
+
59
+ ## Modes
60
+
61
+ | Mode | Set via | Behavior |
62
+ |---|---|---|
63
+ | `hybrid` | default | Claude classifies each task |
64
+ | `local-only` | `PEDALPOINT_MODE=local-only` | All tasks → local LLM (use when quota exhausted preemptively) |
65
+ | `passthrough` | `PEDALPOINT_MODE=passthrough` | All tasks → Claude Agent (disables pedalpoint) |
66
+
67
+ ## Configuration
68
+
69
+ | Variable | Default | Description |
70
+ |---|---|---|
71
+ | `PEDALPOINT_BASE_URL` | `http://localhost:11434/v1` | OpenAI-compatible endpoint |
72
+ | `PEDALPOINT_MODEL` | `gemma4:e4b` | Default local model |
73
+ | `PEDALPOINT_MODE` | `hybrid` | Routing mode |
74
+ | `PEDALPOINT_TIMEOUT` | `120` | Read timeout in seconds |
75
+ | `PEDALPOINT_INITIAL_FALLBACK_MINUTES` | `60` | Initial circuit-open duration (doubles on each probe failure) |
76
+
77
+ ## Uninstall
78
+
79
+ ```sh
80
+ curl -fsSL https://raw.githubusercontent.com/EMSwank/pedalpoint/main/install.sh | sh -s -- --uninstall
81
+ ```
82
+
83
+ ## Development
84
+
85
+ ```sh
86
+ git clone https://github.com/EMSwank/pedalpoint
87
+ cd pedalpoint
88
+ pip install -e ".[dev]" # requires pip >= 21.3; run `pip install --upgrade pip` if needed
89
+ pytest tests/unit/ -v
90
+ ```
91
+
92
+ Integration tests (requires Ollama running):
93
+
94
+ ```sh
95
+ PEDALPOINT_INTEGRATION=true pytest tests/integration/ -v
96
+ ```
97
+
98
+ Install script tests (requires [bats-core](https://github.com/bats-core/bats-core)):
99
+
100
+ ```sh
101
+ brew install bats-core # macOS; use apt-get install bats on Linux
102
+ bats tests/install/
103
+ ```
104
+
105
+ ## License
106
+
107
+ MIT
@@ -0,0 +1,91 @@
1
+ # pedalpoint
2
+
3
+ Route mechanical development tasks to a local LLM (Ollama, LM Studio, Jan) via Claude Code. Automatically falls back to local-only mode when Claude quota is exhausted.
4
+
5
+ ## What it does
6
+
7
+ - **Hybrid routing:** Claude classifies each task. Mechanical work (scaffolding, CRUD, test stubs) goes to your local LLM. Judgment work (architecture, debugging, integration) stays with Claude.
8
+ - **Quota fallback:** When Claude returns a quota error, pedalpoint automatically switches to local-only mode and continues working. Switches back when quota restores.
9
+ - **Context Courier:** Before sending any task to the local LLM, pedalpoint greps your codebase for existing patterns and injects them into the prompt. Local LLMs only get tasks they have templates for.
10
+ - **Single install:** One script installs the MCP server, pulls the default model, and registers the companion skill.
11
+
12
+ ## Requirements
13
+
14
+ - Claude Code
15
+ - Python 3.11+
16
+ - [Ollama](https://ollama.ai) (or any OpenAI-compatible inference server)
17
+
18
+ ## Install
19
+
20
+ ```sh
21
+ curl -fsSL https://raw.githubusercontent.com/EMSwank/pedalpoint/main/install.sh | sh
22
+ ```
23
+
24
+ With a custom model or endpoint:
25
+
26
+ ```sh
27
+ curl -fsSL https://raw.githubusercontent.com/EMSwank/pedalpoint/main/install.sh | \
28
+ sh -s -- --model llama3 --base-url http://localhost:11434/v1
29
+ ```
30
+
31
+ Restart Claude Code after install.
32
+
33
+ ## Usage
34
+
35
+ Instead of `superpowers:subagent-driven-development`, invoke:
36
+
37
+ ```
38
+ pedalpoint:route-tasks
39
+ ```
40
+
41
+ pedalpoint handles routing automatically. No manual flagging needed.
42
+
43
+ ## Modes
44
+
45
+ | Mode | Set via | Behavior |
46
+ |---|---|---|
47
+ | `hybrid` | default | Claude classifies each task |
48
+ | `local-only` | `PEDALPOINT_MODE=local-only` | All tasks → local LLM (use when quota exhausted preemptively) |
49
+ | `passthrough` | `PEDALPOINT_MODE=passthrough` | All tasks → Claude Agent (disables pedalpoint) |
50
+
51
+ ## Configuration
52
+
53
+ | Variable | Default | Description |
54
+ |---|---|---|
55
+ | `PEDALPOINT_BASE_URL` | `http://localhost:11434/v1` | OpenAI-compatible endpoint |
56
+ | `PEDALPOINT_MODEL` | `gemma4:e4b` | Default local model |
57
+ | `PEDALPOINT_MODE` | `hybrid` | Routing mode |
58
+ | `PEDALPOINT_TIMEOUT` | `120` | Read timeout in seconds |
59
+ | `PEDALPOINT_INITIAL_FALLBACK_MINUTES` | `60` | Initial circuit-open duration (doubles on each probe failure) |
60
+
61
+ ## Uninstall
62
+
63
+ ```sh
64
+ curl -fsSL https://raw.githubusercontent.com/EMSwank/pedalpoint/main/install.sh | sh -s -- --uninstall
65
+ ```
66
+
67
+ ## Development
68
+
69
+ ```sh
70
+ git clone https://github.com/EMSwank/pedalpoint
71
+ cd pedalpoint
72
+ pip install -e ".[dev]" # requires pip >= 21.3; run `pip install --upgrade pip` if needed
73
+ pytest tests/unit/ -v
74
+ ```
75
+
76
+ Integration tests (requires Ollama running):
77
+
78
+ ```sh
79
+ PEDALPOINT_INTEGRATION=true pytest tests/integration/ -v
80
+ ```
81
+
82
+ Install script tests (requires [bats-core](https://github.com/bats-core/bats-core)):
83
+
84
+ ```sh
85
+ brew install bats-core # macOS; use apt-get install bats on Linux
86
+ bats tests/install/
87
+ ```
88
+
89
+ ## License
90
+
91
+ MIT