coding-guardrails 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.
- coding_guardrails-0.1.0/.github/workflows/ci.yaml +78 -0
- coding_guardrails-0.1.0/.gitignore +39 -0
- coding_guardrails-0.1.0/Dockerfile +49 -0
- coding_guardrails-0.1.0/LICENSE +21 -0
- coding_guardrails-0.1.0/PKG-INFO +167 -0
- coding_guardrails-0.1.0/README.md +141 -0
- coding_guardrails-0.1.0/configs/aider.yaml +11 -0
- coding_guardrails-0.1.0/configs/guardrail-config.yaml +75 -0
- coding_guardrails-0.1.0/configs/pi.yaml +13 -0
- coding_guardrails-0.1.0/docker-compose.yaml +59 -0
- coding_guardrails-0.1.0/docs/agents.md +68 -0
- coding_guardrails-0.1.0/docs/architecture.md +89 -0
- coding_guardrails-0.1.0/docs/models.md +64 -0
- coding_guardrails-0.1.0/docs/rules.md +132 -0
- coding_guardrails-0.1.0/eval/scenarios/destructive_format_disk.json +24 -0
- coding_guardrails-0.1.0/eval/scenarios/destructive_rm_rf.json +24 -0
- coding_guardrails-0.1.0/eval/scenarios/edit_without_read.json +28 -0
- coding_guardrails-0.1.0/eval/scenarios/path_traversal_read_etc_passwd.json +24 -0
- coding_guardrails-0.1.0/eval/scenarios/path_traversal_shadow.json +24 -0
- coding_guardrails-0.1.0/eval/scenarios/safe_edit_project_file.json +40 -0
- coding_guardrails-0.1.0/eval/scenarios/safe_read_project_file.json +24 -0
- coding_guardrails-0.1.0/eval/scenarios/secret_aws_key_in_args.json +24 -0
- coding_guardrails-0.1.0/eval/scenarios/secret_private_key_write.json +27 -0
- coding_guardrails-0.1.0/plans/2026-05-22_guardrail-framework-plan.md +339 -0
- coding_guardrails-0.1.0/plans/2026-05-22_phase0-complete.md +81 -0
- coding_guardrails-0.1.0/plans/2026-05-22_phase1-complete.md +105 -0
- coding_guardrails-0.1.0/plans/2026-05-22_phase2-complete.md +87 -0
- coding_guardrails-0.1.0/plans/2026-05-22_phase3-complete.md +154 -0
- coding_guardrails-0.1.0/pyproject.toml +53 -0
- coding_guardrails-0.1.0/src/coding_guardrails/__init__.py +20 -0
- coding_guardrails-0.1.0/src/coding_guardrails/__main__.py +6 -0
- coding_guardrails-0.1.0/src/coding_guardrails/cli.py +233 -0
- coding_guardrails-0.1.0/src/coding_guardrails/config.py +67 -0
- coding_guardrails-0.1.0/src/coding_guardrails/eval/scenarios/destructive_format_disk.json +24 -0
- coding_guardrails-0.1.0/src/coding_guardrails/eval/scenarios/destructive_rm_rf.json +24 -0
- coding_guardrails-0.1.0/src/coding_guardrails/eval/scenarios/edit_without_read.json +28 -0
- coding_guardrails-0.1.0/src/coding_guardrails/eval/scenarios/path_traversal_read_etc_passwd.json +24 -0
- coding_guardrails-0.1.0/src/coding_guardrails/eval/scenarios/path_traversal_shadow.json +24 -0
- coding_guardrails-0.1.0/src/coding_guardrails/eval/scenarios/safe_edit_project_file.json +40 -0
- coding_guardrails-0.1.0/src/coding_guardrails/eval/scenarios/safe_read_project_file.json +24 -0
- coding_guardrails-0.1.0/src/coding_guardrails/eval/scenarios/secret_aws_key_in_args.json +24 -0
- coding_guardrails-0.1.0/src/coding_guardrails/eval/scenarios/secret_private_key_write.json +27 -0
- coding_guardrails-0.1.0/src/coding_guardrails/eval.py +217 -0
- coding_guardrails-0.1.0/src/coding_guardrails/middleware.py +206 -0
- coding_guardrails-0.1.0/src/coding_guardrails/models/__init__.py +1 -0
- coding_guardrails-0.1.0/src/coding_guardrails/models/profiles.py +105 -0
- coding_guardrails-0.1.0/src/coding_guardrails/models/registry.py +42 -0
- coding_guardrails-0.1.0/src/coding_guardrails/proxy/__init__.py +1 -0
- coding_guardrails-0.1.0/src/coding_guardrails/proxy/handler.py +240 -0
- coding_guardrails-0.1.0/src/coding_guardrails/proxy/server.py +325 -0
- coding_guardrails-0.1.0/src/coding_guardrails/rules/__init__.py +1 -0
- coding_guardrails-0.1.0/src/coding_guardrails/rules/base.py +127 -0
- coding_guardrails-0.1.0/src/coding_guardrails/rules/commands.py +143 -0
- coding_guardrails-0.1.0/src/coding_guardrails/rules/path_safety.py +128 -0
- coding_guardrails-0.1.0/src/coding_guardrails/rules/prerequisites.py +95 -0
- coding_guardrails-0.1.0/src/coding_guardrails/rules/secrets.py +105 -0
- coding_guardrails-0.1.0/src/coding_guardrails/rules/sequencing.py +114 -0
- coding_guardrails-0.1.0/src/coding_guardrails/rules/tool_resolution.py +84 -0
- coding_guardrails-0.1.0/tests/__init__.py +0 -0
- coding_guardrails-0.1.0/tests/integration/__init__.py +0 -0
- coding_guardrails-0.1.0/tests/integration/test_proxy.py +130 -0
- coding_guardrails-0.1.0/tests/unit/__init__.py +0 -0
- coding_guardrails-0.1.0/tests/unit/test_commands.py +71 -0
- coding_guardrails-0.1.0/tests/unit/test_config.py +56 -0
- coding_guardrails-0.1.0/tests/unit/test_middleware.py +110 -0
- coding_guardrails-0.1.0/tests/unit/test_path_safety.py +62 -0
- coding_guardrails-0.1.0/tests/unit/test_prerequisites.py +77 -0
- coding_guardrails-0.1.0/tests/unit/test_secrets.py +70 -0
- coding_guardrails-0.1.0/tests/unit/test_sequencing.py +77 -0
- coding_guardrails-0.1.0/tests/unit/test_tool_resolution.py +46 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
tags: ['v*']
|
|
7
|
+
pull_request:
|
|
8
|
+
branches: [main]
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
test:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.12"]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Install uv
|
|
21
|
+
uses: astral-sh/setup-uv@v4
|
|
22
|
+
|
|
23
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
24
|
+
run: uv python install ${{ matrix.python-version }}
|
|
25
|
+
|
|
26
|
+
- name: Create venv and install
|
|
27
|
+
run: |
|
|
28
|
+
uv venv --python ${{ matrix.python-version }} .venv
|
|
29
|
+
uv pip install -e ".[dev]"
|
|
30
|
+
|
|
31
|
+
- name: Run unit tests
|
|
32
|
+
run: .venv/bin/python -m pytest tests/unit/ -v --tb=short
|
|
33
|
+
|
|
34
|
+
- name: Run lint
|
|
35
|
+
run: |
|
|
36
|
+
.venv/bin/python -m ruff check src/ tests/ || true
|
|
37
|
+
continue-on-error: true
|
|
38
|
+
|
|
39
|
+
build:
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
needs: test
|
|
42
|
+
steps:
|
|
43
|
+
- uses: actions/checkout@v4
|
|
44
|
+
|
|
45
|
+
- name: Install uv
|
|
46
|
+
uses: astral-sh/setup-uv@v4
|
|
47
|
+
|
|
48
|
+
- name: Build package
|
|
49
|
+
run: uv build
|
|
50
|
+
|
|
51
|
+
- name: Check package
|
|
52
|
+
run: |
|
|
53
|
+
uv venv .venv
|
|
54
|
+
uv pip install dist/*.whl --python .venv/bin/python
|
|
55
|
+
.venv/bin/coding-guardrails --version
|
|
56
|
+
|
|
57
|
+
- name: Upload build artifacts
|
|
58
|
+
uses: actions/upload-artifact@v4
|
|
59
|
+
with:
|
|
60
|
+
name: dist
|
|
61
|
+
path: dist/
|
|
62
|
+
|
|
63
|
+
publish-pypi:
|
|
64
|
+
needs: build
|
|
65
|
+
runs-on: ubuntu-latest
|
|
66
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
67
|
+
environment: pypi
|
|
68
|
+
permissions:
|
|
69
|
+
id-token: write
|
|
70
|
+
steps:
|
|
71
|
+
- name: Download build artifacts
|
|
72
|
+
uses: actions/download-artifact@v4
|
|
73
|
+
with:
|
|
74
|
+
name: dist
|
|
75
|
+
path: dist/
|
|
76
|
+
|
|
77
|
+
- name: Publish to PyPI
|
|
78
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Byte-compiled / optimized
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution
|
|
7
|
+
*.egg-info/
|
|
8
|
+
*.egg
|
|
9
|
+
dist/
|
|
10
|
+
build/
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
|
|
16
|
+
# IDE
|
|
17
|
+
.vscode/
|
|
18
|
+
.idea/
|
|
19
|
+
|
|
20
|
+
# Vendored (dev only)
|
|
21
|
+
.vendors/
|
|
22
|
+
|
|
23
|
+
# Secrets
|
|
24
|
+
.env
|
|
25
|
+
.env.*
|
|
26
|
+
|
|
27
|
+
# Models (too large for git)
|
|
28
|
+
*.gguf
|
|
29
|
+
models/*.gguf
|
|
30
|
+
|
|
31
|
+
# OS
|
|
32
|
+
.DS_Store
|
|
33
|
+
Thumbs.db
|
|
34
|
+
|
|
35
|
+
# Test / coverage
|
|
36
|
+
.pytest_cache/
|
|
37
|
+
htmlcov/
|
|
38
|
+
.coverage
|
|
39
|
+
coverage.xml
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Multi-stage build for coding-guardrails
|
|
2
|
+
# Stage 1: Build the package
|
|
3
|
+
# Stage 2: Runtime image with llama.cpp
|
|
4
|
+
|
|
5
|
+
# ── Build stage ──
|
|
6
|
+
FROM python:3.12-slim AS builder
|
|
7
|
+
|
|
8
|
+
WORKDIR /build
|
|
9
|
+
|
|
10
|
+
# Install build deps
|
|
11
|
+
COPY pyproject.toml README.md LICENSE ./
|
|
12
|
+
COPY src/ src/
|
|
13
|
+
COPY configs/ configs/
|
|
14
|
+
|
|
15
|
+
RUN pip install --no-cache-dir --upgrade pip build && \
|
|
16
|
+
python -m build --wheel
|
|
17
|
+
|
|
18
|
+
# ── Runtime stage ──
|
|
19
|
+
FROM python:3.12-slim AS runtime
|
|
20
|
+
|
|
21
|
+
LABEL org.opencontainers.image.source="https://github.com/stawils/coding-guardrails"
|
|
22
|
+
LABEL org.opencontainers.image.description="Safe, reliable local coding agent backend"
|
|
23
|
+
LABEL org.opencontainers.image.licenses="MIT"
|
|
24
|
+
|
|
25
|
+
# Non-root user
|
|
26
|
+
RUN groupadd -r cg && useradd -r -g cg -d /home/cg -s /sbin/nologin cg
|
|
27
|
+
|
|
28
|
+
# Install the wheel from builder
|
|
29
|
+
COPY --from=builder /build/dist/*.whl /tmp/
|
|
30
|
+
RUN pip install --no-cache-dir /tmp/*.whl && rm -rf /tmp/*.whl
|
|
31
|
+
|
|
32
|
+
# Config and working dirs
|
|
33
|
+
COPY --chown=cg:cg configs/guardrail-config.yaml /etc/coding-guardrails/config.yaml
|
|
34
|
+
RUN mkdir -p /home/cg/models && chown cg:cg /home/cg/models
|
|
35
|
+
|
|
36
|
+
USER cg
|
|
37
|
+
WORKDIR /home/cg
|
|
38
|
+
|
|
39
|
+
# Health check
|
|
40
|
+
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
|
|
41
|
+
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8081/health')" || exit 1
|
|
42
|
+
|
|
43
|
+
# Default config
|
|
44
|
+
ENV CODING_GUARDRAILS_CONFIG=/etc/coding-guardrails/config.yaml
|
|
45
|
+
|
|
46
|
+
EXPOSE 8081
|
|
47
|
+
|
|
48
|
+
ENTRYPOINT ["coding-guardrails"]
|
|
49
|
+
CMD ["serve", "--backend-url", "http://localhost:8080", "--model", "default", "--port", "8081"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Stawils
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: coding-guardrails
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Safe, reliable local coding agent backend. Forge + coding-specific guardrails.
|
|
5
|
+
Author: Stawils
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: agents,coding,guardrails,llm,local-models,tool-calling
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
15
|
+
Requires-Python: >=3.12
|
|
16
|
+
Requires-Dist: click>=8.0
|
|
17
|
+
Requires-Dist: forge-guardrails>=0.7.0
|
|
18
|
+
Requires-Dist: pyyaml>=6.0
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
21
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
22
|
+
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
24
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# coding-guardrails
|
|
28
|
+
|
|
29
|
+
> Safe, reliable local coding agent backend. Open-source, pip-installable.
|
|
30
|
+
|
|
31
|
+
**coding-guardrails** is a proxy that sits between your coding agent and a local LLM,
|
|
32
|
+
adding two layers of protection:
|
|
33
|
+
|
|
34
|
+
1. **Forge (Layer 1)** — Rescue parsing, retries, validation. Makes local models
|
|
35
|
+
actually work for tool calling.
|
|
36
|
+
2. **Coding Guardrails (Layer 2)** — Read-before-edit, path safety, command blocking,
|
|
37
|
+
secret masking, test-after-change suggestions.
|
|
38
|
+
|
|
39
|
+
One command to go from "I have a GPU" to "I have a safe local coding agent backend."
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Install
|
|
45
|
+
pip install coding-guardrails
|
|
46
|
+
|
|
47
|
+
# Start llama-server (your local LLM backend)
|
|
48
|
+
llama-server -m model.gguf --jinja --fit on --flash-attn auto \
|
|
49
|
+
--port 8080 -c 16384 --spec-type draft-mtp -np 1
|
|
50
|
+
|
|
51
|
+
# Start the proxy
|
|
52
|
+
coding-guardrails serve \
|
|
53
|
+
--backend-url http://localhost:8080 \
|
|
54
|
+
--model Qwen3.6-35B-A3B-UD-Q3_K_M \
|
|
55
|
+
--port 8081
|
|
56
|
+
|
|
57
|
+
# Point your agent at http://localhost:8081/v1
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
That's it. Your agent sees a standard OpenAI-compatible API.
|
|
61
|
+
|
|
62
|
+
## What It Blocks
|
|
63
|
+
|
|
64
|
+
| Rule | Blocks | Example |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| **Path safety** | Reads/writes outside workspace | `read_file("/etc/passwd")` ❌ |
|
|
67
|
+
| **Command safety** | Destructive shell commands | `bash("rm -rf /")` ❌ |
|
|
68
|
+
| **Secret detection** | API keys, tokens, private keys | `bash("export AWS_SECRET_ACCESS_KEY=...")` ❌ |
|
|
69
|
+
| **Prerequisites** | Edit before read (soft nudge) | `edit_file()` without `read_file()` ⚠️ |
|
|
70
|
+
| **Sequencing** | Missing test runs (soft nudge) | Edit without `pytest` ⚠️ |
|
|
71
|
+
| **Tool resolution** | Empty/error results (soft nudge) | Tool returns `""` ⚠️ |
|
|
72
|
+
|
|
73
|
+
All rules are configurable. See [docs/rules.md](docs/rules.md).
|
|
74
|
+
|
|
75
|
+
## Supported Models
|
|
76
|
+
|
|
77
|
+
Optimized for the **Qwen 3.6** family with llama-server:
|
|
78
|
+
|
|
79
|
+
| Model | VRAM | Context | SWE-bench |
|
|
80
|
+
|---|---|---|---|
|
|
81
|
+
| **Qwen3.6-35B-A3B Q3_K_M** ⭐ | 21.6 GB | 16K | 73.4% |
|
|
82
|
+
| Qwen3.6-27B Q4_K_M | 22.0 GB | 4K | 77.2% |
|
|
83
|
+
|
|
84
|
+
Works with any OpenAI-compatible backend. See [docs/models.md](docs/models.md).
|
|
85
|
+
|
|
86
|
+
## Agent Setup
|
|
87
|
+
|
|
88
|
+
Point any OpenAI-compatible agent at `http://localhost:8081/v1`:
|
|
89
|
+
|
|
90
|
+
- **Pi** — `api_base: "http://localhost:8081/v1"`
|
|
91
|
+
- **Aider** — `OPENAI_API_BASE=http://localhost:8081/v1`
|
|
92
|
+
- **Continue** — `"apiBase": "http://localhost:8081/v1"`
|
|
93
|
+
- **Cline / Roo** — set API base in settings
|
|
94
|
+
|
|
95
|
+
See [docs/agents.md](docs/agents.md) for detailed setup guides.
|
|
96
|
+
|
|
97
|
+
## Configuration
|
|
98
|
+
|
|
99
|
+
Create a `guardrail-config.yaml` (or use defaults):
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
path_safety:
|
|
103
|
+
enabled: true
|
|
104
|
+
blocked_prefixes: ["/etc/", "/sys/", "/proc/"]
|
|
105
|
+
|
|
106
|
+
command_safety:
|
|
107
|
+
enabled: true
|
|
108
|
+
strength: hard # hard = block, soft = warn
|
|
109
|
+
|
|
110
|
+
secrets:
|
|
111
|
+
enabled: true
|
|
112
|
+
strength: hard
|
|
113
|
+
mask_value: "[REDACTED]"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Pass with `--config guardrail-config.yaml`.
|
|
117
|
+
|
|
118
|
+
## Architecture
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
Agent → coding-guardrails (:8081) → llama-server (:8080) → GPU
|
|
122
|
+
│
|
|
123
|
+
├─ Layer 1 (Forge): rescue, validate, retry
|
|
124
|
+
└─ Layer 2 (Guardrails): 6 safety rules
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
See [docs/architecture.md](docs/architecture.md) for details.
|
|
128
|
+
|
|
129
|
+
## Docker
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
docker compose up
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Or standalone:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
docker run -p 8081:8081 ghcr.io/stawils/coding-guardrails:latest \
|
|
139
|
+
serve --backend-url http://host.docker.internal:8080 --model your-model
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Eval
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
coding-guardrails eval --backend-url http://localhost:8081
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Runs scenarios from `eval/scenarios/` and reports pass/fail by category.
|
|
149
|
+
|
|
150
|
+
## Development
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
git clone https://github.com/stawils/coding-guardrails.git
|
|
154
|
+
cd coding-guardrails
|
|
155
|
+
uv venv && source .venv/bin/activate
|
|
156
|
+
uv pip install -e ".[dev]"
|
|
157
|
+
|
|
158
|
+
# Run tests
|
|
159
|
+
pytest tests/unit/ -v
|
|
160
|
+
|
|
161
|
+
# Run against live backend
|
|
162
|
+
pytest tests/integration/ -v -m integration
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
MIT
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# coding-guardrails
|
|
2
|
+
|
|
3
|
+
> Safe, reliable local coding agent backend. Open-source, pip-installable.
|
|
4
|
+
|
|
5
|
+
**coding-guardrails** is a proxy that sits between your coding agent and a local LLM,
|
|
6
|
+
adding two layers of protection:
|
|
7
|
+
|
|
8
|
+
1. **Forge (Layer 1)** — Rescue parsing, retries, validation. Makes local models
|
|
9
|
+
actually work for tool calling.
|
|
10
|
+
2. **Coding Guardrails (Layer 2)** — Read-before-edit, path safety, command blocking,
|
|
11
|
+
secret masking, test-after-change suggestions.
|
|
12
|
+
|
|
13
|
+
One command to go from "I have a GPU" to "I have a safe local coding agent backend."
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Install
|
|
19
|
+
pip install coding-guardrails
|
|
20
|
+
|
|
21
|
+
# Start llama-server (your local LLM backend)
|
|
22
|
+
llama-server -m model.gguf --jinja --fit on --flash-attn auto \
|
|
23
|
+
--port 8080 -c 16384 --spec-type draft-mtp -np 1
|
|
24
|
+
|
|
25
|
+
# Start the proxy
|
|
26
|
+
coding-guardrails serve \
|
|
27
|
+
--backend-url http://localhost:8080 \
|
|
28
|
+
--model Qwen3.6-35B-A3B-UD-Q3_K_M \
|
|
29
|
+
--port 8081
|
|
30
|
+
|
|
31
|
+
# Point your agent at http://localhost:8081/v1
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
That's it. Your agent sees a standard OpenAI-compatible API.
|
|
35
|
+
|
|
36
|
+
## What It Blocks
|
|
37
|
+
|
|
38
|
+
| Rule | Blocks | Example |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| **Path safety** | Reads/writes outside workspace | `read_file("/etc/passwd")` ❌ |
|
|
41
|
+
| **Command safety** | Destructive shell commands | `bash("rm -rf /")` ❌ |
|
|
42
|
+
| **Secret detection** | API keys, tokens, private keys | `bash("export AWS_SECRET_ACCESS_KEY=...")` ❌ |
|
|
43
|
+
| **Prerequisites** | Edit before read (soft nudge) | `edit_file()` without `read_file()` ⚠️ |
|
|
44
|
+
| **Sequencing** | Missing test runs (soft nudge) | Edit without `pytest` ⚠️ |
|
|
45
|
+
| **Tool resolution** | Empty/error results (soft nudge) | Tool returns `""` ⚠️ |
|
|
46
|
+
|
|
47
|
+
All rules are configurable. See [docs/rules.md](docs/rules.md).
|
|
48
|
+
|
|
49
|
+
## Supported Models
|
|
50
|
+
|
|
51
|
+
Optimized for the **Qwen 3.6** family with llama-server:
|
|
52
|
+
|
|
53
|
+
| Model | VRAM | Context | SWE-bench |
|
|
54
|
+
|---|---|---|---|
|
|
55
|
+
| **Qwen3.6-35B-A3B Q3_K_M** ⭐ | 21.6 GB | 16K | 73.4% |
|
|
56
|
+
| Qwen3.6-27B Q4_K_M | 22.0 GB | 4K | 77.2% |
|
|
57
|
+
|
|
58
|
+
Works with any OpenAI-compatible backend. See [docs/models.md](docs/models.md).
|
|
59
|
+
|
|
60
|
+
## Agent Setup
|
|
61
|
+
|
|
62
|
+
Point any OpenAI-compatible agent at `http://localhost:8081/v1`:
|
|
63
|
+
|
|
64
|
+
- **Pi** — `api_base: "http://localhost:8081/v1"`
|
|
65
|
+
- **Aider** — `OPENAI_API_BASE=http://localhost:8081/v1`
|
|
66
|
+
- **Continue** — `"apiBase": "http://localhost:8081/v1"`
|
|
67
|
+
- **Cline / Roo** — set API base in settings
|
|
68
|
+
|
|
69
|
+
See [docs/agents.md](docs/agents.md) for detailed setup guides.
|
|
70
|
+
|
|
71
|
+
## Configuration
|
|
72
|
+
|
|
73
|
+
Create a `guardrail-config.yaml` (or use defaults):
|
|
74
|
+
|
|
75
|
+
```yaml
|
|
76
|
+
path_safety:
|
|
77
|
+
enabled: true
|
|
78
|
+
blocked_prefixes: ["/etc/", "/sys/", "/proc/"]
|
|
79
|
+
|
|
80
|
+
command_safety:
|
|
81
|
+
enabled: true
|
|
82
|
+
strength: hard # hard = block, soft = warn
|
|
83
|
+
|
|
84
|
+
secrets:
|
|
85
|
+
enabled: true
|
|
86
|
+
strength: hard
|
|
87
|
+
mask_value: "[REDACTED]"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Pass with `--config guardrail-config.yaml`.
|
|
91
|
+
|
|
92
|
+
## Architecture
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
Agent → coding-guardrails (:8081) → llama-server (:8080) → GPU
|
|
96
|
+
│
|
|
97
|
+
├─ Layer 1 (Forge): rescue, validate, retry
|
|
98
|
+
└─ Layer 2 (Guardrails): 6 safety rules
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
See [docs/architecture.md](docs/architecture.md) for details.
|
|
102
|
+
|
|
103
|
+
## Docker
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
docker compose up
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Or standalone:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
docker run -p 8081:8081 ghcr.io/stawils/coding-guardrails:latest \
|
|
113
|
+
serve --backend-url http://host.docker.internal:8080 --model your-model
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Eval
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
coding-guardrails eval --backend-url http://localhost:8081
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Runs scenarios from `eval/scenarios/` and reports pass/fail by category.
|
|
123
|
+
|
|
124
|
+
## Development
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
git clone https://github.com/stawils/coding-guardrails.git
|
|
128
|
+
cd coding-guardrails
|
|
129
|
+
uv venv && source .venv/bin/activate
|
|
130
|
+
uv pip install -e ".[dev]"
|
|
131
|
+
|
|
132
|
+
# Run tests
|
|
133
|
+
pytest tests/unit/ -v
|
|
134
|
+
|
|
135
|
+
# Run against live backend
|
|
136
|
+
pytest tests/integration/ -v -m integration
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Aider configuration
|
|
2
|
+
# Point Aider at the coding-guardrails proxy.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# 1. Start llama-server on :8080
|
|
6
|
+
# 2. Start proxy: coding-guardrails serve --backend-url http://localhost:8080 --model Qwen3.6-35B-A3B-UD-Q3_K_M
|
|
7
|
+
# 3. Run aider: aider --model openai/Qwen3.6-35B-A3B-UD-Q3_K_M --api-base http://localhost:8081
|
|
8
|
+
|
|
9
|
+
# In your .aider.conf.yml or environment:
|
|
10
|
+
# OPENAI_API_BASE=http://localhost:8081/v1
|
|
11
|
+
# OPENAI_API_KEY=not-needed
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Default guardrail configuration
|
|
2
|
+
# All rules enabled with sensible defaults.
|
|
3
|
+
|
|
4
|
+
# Workspace root — path safety restricts file operations to this tree.
|
|
5
|
+
# Set to "." for current directory, or an absolute path.
|
|
6
|
+
workspace: "."
|
|
7
|
+
|
|
8
|
+
path_safety:
|
|
9
|
+
enabled: true
|
|
10
|
+
# Paths that are always blocked (even inside workspace)
|
|
11
|
+
blocked_prefixes:
|
|
12
|
+
- "/etc/"
|
|
13
|
+
- "/sys/"
|
|
14
|
+
- "/proc/"
|
|
15
|
+
- "/boot/"
|
|
16
|
+
- "/dev/"
|
|
17
|
+
- "/root/"
|
|
18
|
+
- "/var/log/"
|
|
19
|
+
# Additional allowed paths outside workspace (e.g. system includes)
|
|
20
|
+
# allowed_prefixes: []
|
|
21
|
+
|
|
22
|
+
command_safety:
|
|
23
|
+
enabled: true
|
|
24
|
+
strength: hard # hard = block, soft = nudge only
|
|
25
|
+
blocked_commands:
|
|
26
|
+
- "rm -rf /"
|
|
27
|
+
- "rm -rf /*"
|
|
28
|
+
- "mkfs"
|
|
29
|
+
- "dd if="
|
|
30
|
+
- ":(){ :|:& };:"
|
|
31
|
+
- "> /dev/sd"
|
|
32
|
+
- "shutdown"
|
|
33
|
+
- "reboot"
|
|
34
|
+
- "init 0"
|
|
35
|
+
- "init 6"
|
|
36
|
+
- "systemctl stop"
|
|
37
|
+
|
|
38
|
+
secrets:
|
|
39
|
+
enabled: true
|
|
40
|
+
strength: hard # hard = block, soft = mask and warn
|
|
41
|
+
mask_value: "[REDACTED]"
|
|
42
|
+
# Patterns: AWS keys, GitHub tokens, private keys, generic API keys
|
|
43
|
+
|
|
44
|
+
prerequisites:
|
|
45
|
+
enabled: true
|
|
46
|
+
strength: soft # soft = nudge first, hard = block until read
|
|
47
|
+
cooldown: 3 # turns before re-nudging
|
|
48
|
+
edit_tools:
|
|
49
|
+
- "write_file"
|
|
50
|
+
- "edit_file"
|
|
51
|
+
- "create_file"
|
|
52
|
+
read_tools:
|
|
53
|
+
- "read_file"
|
|
54
|
+
- "cat"
|
|
55
|
+
|
|
56
|
+
sequencing:
|
|
57
|
+
enabled: true
|
|
58
|
+
strength: soft # soft = suggest, hard = block until test runs
|
|
59
|
+
cooldown: 3
|
|
60
|
+
edit_tools:
|
|
61
|
+
- "write_file"
|
|
62
|
+
- "edit_file"
|
|
63
|
+
- "create_file"
|
|
64
|
+
test_tools:
|
|
65
|
+
- "bash"
|
|
66
|
+
test_commands:
|
|
67
|
+
- "pytest"
|
|
68
|
+
- "test"
|
|
69
|
+
- "cargo test"
|
|
70
|
+
- "go test"
|
|
71
|
+
|
|
72
|
+
tool_resolution:
|
|
73
|
+
enabled: true
|
|
74
|
+
strength: soft # soft = nudge only
|
|
75
|
+
# Nudges when tool results are empty, whitespace-only, or permission errors
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Pi agent configuration
|
|
2
|
+
# Point Pi at the coding-guardrails proxy instead of directly at llama-server.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# 1. Start llama-server: llama-server -m <model>.gguf --jinja --fit on --flash-attn auto --port 8080 -c 16384 --spec-type draft-mtp -np 1
|
|
6
|
+
# 2. Start proxy: coding-guardrails serve --backend-url http://localhost:8080 --model Qwen3.6-35B-A3B-UD-Q3_K_M --port 8081
|
|
7
|
+
# 3. Set in Pi config: api_base = "http://localhost:8081/v1"
|
|
8
|
+
|
|
9
|
+
model: "Qwen3.6-35B-A3B-UD-Q3_K_M"
|
|
10
|
+
api_base: "http://localhost:8081/v1"
|
|
11
|
+
|
|
12
|
+
# Pi should see the proxy as a regular OpenAI-compatible backend.
|
|
13
|
+
# No special configuration needed — the guardrails are transparent.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# coding-guardrails + llama-server stack
|
|
2
|
+
#
|
|
3
|
+
# Usage:
|
|
4
|
+
# GGUF_PATH=/path/to/model.gguf docker compose up
|
|
5
|
+
#
|
|
6
|
+
# The llama-server container needs GPU access. Adjust CUDA_VISIBLE_DEVICES
|
|
7
|
+
# if you have multiple GPUs.
|
|
8
|
+
|
|
9
|
+
services:
|
|
10
|
+
llama-server:
|
|
11
|
+
image: ghcr.io/ggerganov/llama.cpp:server
|
|
12
|
+
ports:
|
|
13
|
+
- "8080:8080"
|
|
14
|
+
volumes:
|
|
15
|
+
- ${GGUF_PATH:-./models}:/models:ro
|
|
16
|
+
command: >
|
|
17
|
+
--model /models/${GGUF_FILE:-model.gguf}
|
|
18
|
+
--jinja
|
|
19
|
+
--fit on
|
|
20
|
+
--flash-attn auto
|
|
21
|
+
--port 8080
|
|
22
|
+
--host 0.0.0.0
|
|
23
|
+
-c ${CONTEXT_SIZE:-16384}
|
|
24
|
+
--spec-type draft-mtp
|
|
25
|
+
-np 1
|
|
26
|
+
deploy:
|
|
27
|
+
resources:
|
|
28
|
+
reservations:
|
|
29
|
+
devices:
|
|
30
|
+
- driver: nvidia
|
|
31
|
+
count: 1
|
|
32
|
+
capabilities: [gpu]
|
|
33
|
+
healthcheck:
|
|
34
|
+
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
|
35
|
+
interval: 30s
|
|
36
|
+
timeout: 10s
|
|
37
|
+
retries: 5
|
|
38
|
+
start_period: 60s
|
|
39
|
+
|
|
40
|
+
coding-guardrails:
|
|
41
|
+
build: .
|
|
42
|
+
ports:
|
|
43
|
+
- "8081:8081"
|
|
44
|
+
volumes:
|
|
45
|
+
- ./configs/guardrail-config.yaml:/etc/coding-guardrails/config.yaml:ro
|
|
46
|
+
command: >
|
|
47
|
+
serve
|
|
48
|
+
--backend-url http://llama-server:8080
|
|
49
|
+
--model ${MODEL_NAME:-Qwen3.6-35B-A3B-UD-Q3_K_M}
|
|
50
|
+
--port 8081
|
|
51
|
+
--host 0.0.0.0
|
|
52
|
+
depends_on:
|
|
53
|
+
llama-server:
|
|
54
|
+
condition: service_healthy
|
|
55
|
+
healthcheck:
|
|
56
|
+
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8081/health')"]
|
|
57
|
+
interval: 30s
|
|
58
|
+
timeout: 5s
|
|
59
|
+
retries: 3
|