Git Ollama Tools
Git Ollama Tools
Purpose
A custom webhook service that runs Ollama-backed automation agents against Gitea pushes. One shared pipeline (webhook → clone → analyze → open PR/issue) feeds five agents:
| Agent | Trigger | Action |
|---|---|---|
| Secret scanner | any changed file | regex-only, no Ollama call — opens an issue (bot:secrets) with masked values, never edits code |
| Lint & auto-fix | Python, PowerShell, JS, CSS, HTML, YAML | runs each language’s fixer, sends leftovers to Ollama, opens a PR (bot:lint) |
| Test coverage reviewer | changed .py files | ast-parses functions missing a test_<func>, drafts pytest stubs, opens a PR (bot:tests, needs-review) |
| Docstring/README updater | changed function signatures/bodies | regenerates docstrings, updates README if the public API changed, opens a PR (bot:docs) |
| Changelog | any push with ≥1 commit | one bullet per commit, appended under ## Unreleased in CHANGELOG.md, opens a PR (bot:changelog) |
Every code-modifying agent only ever opens a PR — never pushes to main, never auto-merges. The secret scanner is the one exception in the other direction: it never modifies code and never calls Ollama, since sending a matched secret to the model would leak it a second time.
Guardrails: pushes from the bot account or any bot/* branch are ignored outright (loop prevention); idempotency checks against open PRs/issues on Gitea skip repeat work, and a bot branch that exists without an open PR is deleted and retried rather than left stuck; a model fix must pass a parse/compile gate (py_compile, yaml.safe_load, Node’s vm.Script, PowerShell’s Language.Parser — all parse-only, nothing the model writes is ever executed) and show the checker’s error count actually went down before it’s kept.
Deployment
| Item | Value |
|---|---|
| Image | gitea.git.homelab.example/bjones/git_ollama_tools:0.1.190 (private registry) |
| Namespace | default |
| Replicas | 1 — the app runs a single in-process background worker thread (JobQueue), so extra replicas wouldn’t parallelize agent runs and risk concurrent writes to the same audit log |
| Node placement | x86 k3s LXC nodes (nodeSelector kubernetes.io/arch: amd64 + picluster/lxc: "true"); follows its local-zfs volume |
| Service type | LoadBalancer (MetalLB, 192.0.2.39), port 8020 |
| Storage | git-ollama-tools-data-zfs PVC, 1Gi, local-zfs storage class |
reloader.stakater.com/auto: "true" is set on the Deployment.
Configuration
Non-secret config (gitea.url, ollama.url/model, the repo allowlist, work-dir paths) comes from a mounted ConfigMap at /config/config.yaml. The Gitea bot token and webhook secret are injected as env vars (GITEA_BOT_TOKEN, WEBHOOK_SECRET) from a Secret — never stored in the ConfigMap.
Agents only touch repos explicitly listed in the ConfigMap’s allowlist. Updating the allowlist requires both re-applying the ConfigMap and a manual kubectl rollout restart — this Deployment has no Reloader annotation wired for the ConfigMap specifically, and the app only reads its config file once at startup.
Probes
The app exposes GET /healthz (returns {"status": "ok"}), so liveness and readiness probes hit that path on port 8020 rather than a plain TCP check.
Networking
Ollama backend: https://ollama.intel.homelab.example, model qwen2.5-coder:7b.
Exposed via a LoadBalancer Service (MetalLB pool first-pool, 192.0.2.30–192.0.2.40) rather than an Ingress — Gitea’s system webhook (instance-wide, fires on every push to every repo on the instance, not a per-repo webhook) targets the MetalLB-assigned IP directly on port
- The app’s own
allowlistconfig decides which repos it actually acts on; everything else is ignored on receipt, along with pushes from the bot account itself and anybot/*branch.
Resources
| Requests | Limits | |
|---|---|---|
| CPU | 100m | 1 |
| Memory | 256Mi | 1Gi |