
Heretic Abliteration
- 2 installs
- Updated May 31, 2026
- broomva/heretic-abliteration
Heretic Abliteration is a Claude Code skill that automates removing refusals from open-weight LLMs with p-e-w/heretic and serves the result locally via Ollama.
About
This skill automates removing refusals (abliteration) from open-weight LLMs using p-e-w/heretic, then serves the result locally through Ollama. It handles the install, device selection and HF-to-GGUF-to-Ollama conversion that make the workflow actually run, including a no-compute path to pull a pre-abliterated model. A developer uses it to run an uncensored local model as a chat or agent backend.
- Automates p-e-w/heretic abliteration with dependency and device fixes that make it run
- Bridges HF weights to GGUF to Ollama for local serving
- Includes a no-compute fast path to pull a pre-abliterated GGUF into Ollama
Heretic Abliteration by the numbers
- 2 all-time installs (skills.sh)
- Ranked #13,956 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Jul 8, 2026 (Skillselion catalog sync)
heretic-abliteration capabilities & compatibility
Free and local; needs a CUDA GPU for real (4-12B) models, otherwise CPU-only and slow on Apple Silicon
- Capabilities
- llm abliteration · local llm serving · gguf conversion · model quantization
- Use cases
- orchestration
- Platforms
- macOS · Linux
- Pricing
- Free
What heretic-abliteration says it does
Remove refusals from open-weight LLMs with [`p-e-w/heretic`](https://github.com/p-e-w/heretic), then serve the result locally through the Ollama CLI.
Ollama can't be Heretic's *backend*.
Apple Silicon MPS is blocked** for GQA models (Qwen3, Llama-3, Mistral…) by a PyTorch `mps.matmul` bug
npx skills add https://github.com/broomva/heretic-abliteration --skill heretic-abliterationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| Last updated | May 31, 2026 |
| Repository | broomva/heretic-abliteration ↗ |
What it does
Use it to decensor an open-weight LLM locally with heretic and serve the result through Ollama or as a local agent backend.
Who is it for?
Decensoring open-weight LLMs locally, fixing heretic install or MPS/CUDA errors, and serving an abliterated model via Ollama
Skip if: API-only models or training safety in; abliteration needs local weights and only removes refusals
When should I use this skill?
Decensoring an open-weight LLM, running heretic-llm, or converting an abliterated model to GGUF for Ollama
What you get
A locally-served abliterated model, or a pre-abliterated GGUF pulled into Ollama with validated smoke checks
- abliterated GGUF model
- Ollama model served locally
By the numbers
- 3 quick-start paths (A/B/C)
- Qwen3-0.6B refusals 6/8 to 1/8
- KL divergence 0.0026 on dogfood run
Files
Heretic — Abliteration + Ollama Serving
Remove refusals from open-weight LLMs with `p-e-w/heretic`, then serve the result locally through the Ollama CLI. Heretic combines directional ablation ("abliteration") with an Optuna/TPE search that co-minimizes refusals and KL divergence — decensoring the model while preserving its intelligence, no fine-tuning required.
The one architectural fact: Ollama can't be Heretic's backend. Heretic edits
raw HF weights and reads activations (PyTorch/transformers); Ollama is inference-only
over GGUF. The link is downstream: Heretic → GGUF → Ollama. See
references/troubleshooting.md.
Quick Start — pick your path
Path A — Serve now, zero compute (recommended on Apple Silicon / no GPU):
./scripts/ollama-pull-abliterated.sh huihui_ai/llama3.2-abliterate:3bPath B — Run Heretic yourself, then to Ollama (needs a GPU for real models):
./scripts/heretic-install.sh # clean venv + dependency fixes
./scripts/heretic-doctor.sh # confirm device/tooling
./scripts/heretic-run.sh Qwen/Qwen3-4B-Instruct-2507 # run in a REAL terminal (TTY) to save
./scripts/heretic-to-ollama.sh ./<saved-model> my-heretic Q4_K_M
ollama run my-hereticPath C — Smoke test on Apple Silicon CPU (tiny model, proves the pipeline):
./scripts/heretic-install.sh
./scripts/heretic-run.sh Qwen/Qwen3-0.6B --batch-size 8 --max-batch-size 8 --n-trials 4Prerequisites
| Tool | Install | Required for |
|---|---|---|
| Python 3.10+ | (system / pyenv — not conda base) | running Heretic |
| Ollama | brew install ollama | serving (Paths A/B) |
| llama.cpp | brew install llama.cpp | GGUF conversion (Path B) — llama-quantize + convert_hf_to_gguf.py |
| CUDA GPU | local or broomva/remote-gpu | running real (4–12B) models |
Apple Silicon note: a GPU is not present for Heretic's purposes — MPS is blocked (see Limitations). Treat Macs as serve-only unless you attach a CUDA box.
Operations
Install (clean venv + the two fixes)
./scripts/heretic-install.sh # HERETIC_VENV=~/.venvs/heretic by defaultCreates a dedicated venv (never the conda base env), installs heretic-llm, then applies the dogfood-validated fixes: removes the broken optional kernels package and ensures jinja2 >= 3.1. Verifies import heretic.main succeeds.
Doctor (what can I run here?)
./scripts/heretic-doctor.shReports platform, accelerator (CUDA / MPS-blocked / CPU), venv + heretic import, Ollama daemon, llama.cpp tooling, disk — and the recommended path.
Run an abliteration
./scripts/heretic-run.sh <hf-model-id> [extra heretic args]Auto-selects device flags: CUDA → full speed; Apple Silicon / CPU → --device-map cpu --quantization NONE (+ PYTORCH_ENABLE_MPS_FALLBACK=1). Run it in a real terminal — Heretic's save menu needs a TTY (piped stdin crashes after optimization, losing the model). Useful flags: --n-trials N, --batch-size N, --kl-divergence-target F, --study-checkpoint-dir DIR (fresh dir avoids the resume menu).
Convert a saved model to Ollama
./scripts/heretic-to-ollama.sh <hf-model-dir> <ollama-name> [quant=Q4_K_M]HF safetensors → convert_hf_to_gguf.py → llama-quantize → ollama create.
Fast path — pull a pre-abliterated model
./scripts/ollama-pull-abliterated.sh [ollama-model]Pulls a community pre-abliterated GGUF and runs two smoke checks (capability preserved + false-refusal removed) via the Ollama API.
Use it AS Claude Code's backend (uncensored local agent)
Ollama serves the Anthropic Messages API natively at /v1/messages — the exact protocol Claude Code speaks — so you can point Claude Code at your local abliterated model with no proxy (no claude-code-router, no LiteLLM):
./scripts/claude-code-on-ollama.sh huihui_ai/qwen2.5-coder-abliterate:14b --smoke # tool-use probe
./scripts/claude-code-on-ollama.sh huihui_ai/qwen2.5-coder-abliterate:14b # interactiveUnder the hood: ANTHROPIC_BASE_URL=http://localhost:11434 ANTHROPIC_API_KEY=ollama claude --model <m> (dummy key — Ollama ignores auth).
What works — and what doesn't (validated M4 Pro / 24 GB · Ollama 0.20.7 · 2026-05-31):
1. Text round-trip — ✅ chat/Q&A routes Claude Code → Ollama → back. No proxy.
2. Tool-calling is MODEL-FAMILY-specific — not abliteration, not the endpoint. Same 1-tool probe across /api/chat, /v1/chat/completions, /v1/messages:
| Model | Ollama parses its tool call into a tool_use block? |
|---|---|
llama3.1:8b (official) | ✅ all 3 endpoints |
llama3.2-abliterate:1b | ✅ on /v1/messages — abliterated, still works |
qwen2.5-coder:7b (official) | ❌ emits bare JSON Ollama can't parse |
qwen2.5-coder-abliterate:14b | ❌ emits <tools>/<xml>-wrapped JSON |
→ Llama-3.x emits the format Ollama extracts; Qwen2.5 does not (both official and abliterated). For any agentic intent, pick a Llama-3.x abliterated model.
3. The full Claude Code agent loop on 24 GB — ❌ doesn't complete. Claude Code's system prompt + ~32 tool schemas demands a large context, and 24 GB has no room:
- llama3.1 at native 128K ctx ⇒ 30 GB → overflows RAM → CPU-thrash → empty result.
- capped to 32K ctx ⇒ 11 GB (fits GPU) → prompt nearly fills the window → empty /
llama_decode crash in the Ollama log.
Small context starves generation; large context overflows RAM — no operating point on 24 GB. Latency is brutal too (a 14B turn ≈ 3.6 min).
Bottom line: on a 24 GB Mac a local abliterated model is a usable Claude Code chat backend, but not a working tool-using agent. A real local uncensored agent needs (a) a Llama-family abliterated model (tool-format compatible) and (b) far more unified RAM (64–128 GB) or a GPU box — see broomva/remote-gpu.
--smoke classifies agentic / chat-only / no-attempt. Dual-use: an uncensored backend — use responsibly.
How abliteration works (and why the KL term matters)
Heretic runs harmful vs. harmless prompts, takes the difference-of-means of the residual-stream activations to get per-layer "refusal directions", then orthogonalizes the attention out-projection (attn.o_proj) and MLP down-projection (mlp.down_proj) against them. The Optuna/TPE loop searches the kernel-shape parameters to minimize refusals while keeping KL divergence low on harmless prompts — the KL leash is what prevents the "lobotomized" failure mode. This is a textbook evaluator-governed (EGRI) loop: mutable weights, an immutable refusal/KL evaluator, an Optuna harness, Pareto selection. See references/egri-mapping.md.
Validated results (this skill's dogfood, 2026-05-30, M4 Pro)
| Check | Result |
|---|---|
| Install + import (after fixes) | ✅ heretic-llm 1.3.0 |
| Full abliteration, Qwen3-0.6B, CPU | ✅ refusals 6/8 → 1/8, KL 0.0026 |
Serve huihui_ai/llama3.2-abliterate:1b via Ollama | ✅ "Canberra" + benign kill <pid> answered |
| MPS forward pass | ✗ PyTorch GQA matmul LLVM abort → CPU |
Limitations
- Apple Silicon MPS is blocked for GQA models (Qwen3, Llama-3, Mistral…) by a
PyTorch mps.matmul bug → must use CPU (slow). Real models need CUDA.
- CPU is impractical for >1B models (≈50–110 tok/s). Use
broomva/remote-gpu. - Saving requires a TTY — Heretic's menus use
questionary; never pipe stdin. - `BNB_4BIT` quantization is CUDA-only (bitsandbytes).
- Local weights required — abliteration cannot touch API-only models.
- Dual-use. This removes safety guardrails from models you run. Use responsibly
and within applicable terms and law.
References
- references/troubleshooting.md — every blocker + fix, perf table
- references/egri-mapping.md — abliteration as an EGRI / RCS loop
- references/models.md — input models + pre-abliterated catalog + quant guide
- Upstream: github.com/p-e-w/heretic · heretic-project.org
{"ts":1780240556260,"tool":"Bash","latency_ms":null,"is_error":false}
{"ts":1780240570625,"tool":"Bash","latency_ms":null,"is_error":false}
{"ts":1780241858267,"tool":"Bash","latency_ms":null,"is_error":false}
{"ts":1780241882518,"tool":"Bash","latency_ms":null,"is_error":false}
{"ts":1780241893805,"tool":"mcp__linear-server__save_issue","latency_ms":null,"is_error":false}
{"ts":1780241906219,"tool":"mcp__linear-server__save_comment","latency_ms":null,"is_error":false}
{"ts":1780240590672,"session_id":"2b8efde2-8f4f-49ae-b42d-d180ccf20561","reflexes":{"r01_mechanism":false,"r02_lens":false,"r03_snapshot":false,"r04_depchain":false,"r05_worktree":false,"r06_ticket":false,"r07_dogfood_plan":false,"r08_validation":false,"r09_first_write":false,"r10_empirical":false,"r11_pr_opened":false,"r12_watcher":false,"r13_healing":false,"r14_cross_review":false,"r15_deploy_verify":false,"r16_receipt":false,"r17_pr_comments":false,"r18_auto_merge":false,"r19_cleanup":false,"r20_bridge":true,"r21_bookkeeping":false},"compliance_rate":0.048,"fired_count":1,"total_reflexes":21,"anti_rationalization":{"present":false,"value":null},"tool_call_count":0}
{"ts":1780241930764,"session_id":"2b8efde2-8f4f-49ae-b42d-d180ccf20561","reflexes":{"r01_mechanism":false,"r02_lens":false,"r03_snapshot":false,"r04_depchain":false,"r05_worktree":false,"r06_ticket":false,"r07_dogfood_plan":false,"r08_validation":false,"r09_first_write":false,"r10_empirical":false,"r11_pr_opened":false,"r12_watcher":false,"r13_healing":false,"r14_cross_review":false,"r15_deploy_verify":false,"r16_receipt":false,"r17_pr_comments":false,"r18_auto_merge":false,"r19_cleanup":false,"r20_bridge":true,"r21_bookkeeping":false},"compliance_rate":0.048,"fired_count":1,"total_reflexes":21,"anti_rationalization":{"present":false,"value":null},"tool_call_count":0}
# Heretic skill — generated artifacts
gguf-out/
*.gguf
Modelfile.*
.venv/
__pycache__/
*.log
heretic-abliteration
A bstack skill: run Heretic LLM abliteration (censorship removal) locally and serve the result via Ollama — with the dependency and device fixes that make it actually work.
npx skills add broomva/heretic-abliterationThen, fastest path (no compute):
./scripts/ollama-pull-abliterated.sh huihui_ai/llama3.2-abliterate:3bSee SKILL.md for the full workflow (install → run → convert → serve) and references/troubleshooting.md for the dogfood-validated blocker→fix matrix.
Architecture: Ollama can't be Heretic's backend (Heretic edits raw HF weights;
Ollama is inference-only over GGUF). The bridge is `Heretic → convert_hf_to_gguf →
llama-quantize → ollama create`.
Dual-use: removes safety guardrails from models you run locally. Use responsibly.
Crystallized from the 2026-05-30 dogfood (Linear BRO-1264). Validated on Apple M4 Pro: Qwen3-0.6B refusals 6/8 → 1/8 at KL 0.0026 (CPU); pre-abliterated model served via Ollama CLI.
Heretic as an Evaluator-Governed Recursive Improvement (EGRI) loop
Heretic is a clean, small instance of the autoany/EGRI pattern — worth noting because it makes the algorithm legible and ties into the RCS / control-theory work.
The mapping
| EGRI / autoany role | Heretic component |
|---|---|
| Mutable artifact | The ablation parameters per component (direction_index, and the kernel shape max_weight, max_weight_position, min_weight, min_weight_distance) applied to attn.o_proj + mlp.down_proj. |
| Immutable evaluator | A fixed two-term objective it cannot game: refusal count on harmful eval prompts (mlabonne/harmful_behaviors) + KL divergence of first-token distributions on harmless prompts (mlabonne/harmless_alpaca). |
| Harness / search | Optuna TPE sampler over the parameter surface (--n-trials). |
| Promotion policy | The Pareto front of (refusals, KL); the operator selects a trial from the frontier. |
| Safety / stability constraint | The KL term is an explicit drift penalty — structurally the same move as an RCS stability margin keeping a controller from over-correcting. Heretic's own note: KL > 0.5 ≈ "significant damage". |
Why the second term matters
Naïve abliteration drives refusals to zero but also wrecks reasoning, formatting, and instruction-following. The KL leash is what makes it a governed optimization rather than a destructive one. Observed: Qwen3-0.6B reached refusals 6/8 → 1/8 at KL 0.0026 — a near-zero-damage decensoring, i.e. the Pareto knee sits at high compliance and high fidelity simultaneously.
Reading for the RCS lens
This is a single-level controlled system: the plant is the model's refusal behavior, the control law is the orthogonalization kernel, the observer is the refusal/KL evaluator, and the shield is the KL ceiling. It is not recursive (the evaluator is fixed, not itself improved) — which is exactly why it's stable and bounded. A recursive variant (evolving the evaluator/prompt sets) would need the L2/L3 stop-gradient discipline from the dream-cycle work to stay safe.
See also: skills/autoany/ (EGRI framework), research/rcs/.
Model catalog
Run-it-yourself (Heretic input — HF models)
Heretic supports dense, MoE, and hybrid architectures (multimodal variants too); pure state-space models are excluded by default. Pick by your hardware.
| Model | Params | Where it runs | Notes |
|---|---|---|---|
Qwen/Qwen3-0.6B | 0.6B | CPU (smoke only) | Used to validate this skill. GQA → no MPS. |
Qwen/Qwen3-4B-Instruct-2507 | 4B | GPU (≈20–30 min RTX 3090) | Heretic's own default example. |
meta-llama/Llama-3.1-8B-Instruct | 8B | GPU (≈45 min RTX 3090) | README baseline. |
google/gemma-3-12b-it | 12B | GPU | Heretic reports 3/100 refusals @ KL 0.16. |
Defaults: harmful prompts mlabonne/harmful_behaviors, harmless mlabonne/harmless_alpaca. Quantization BNB_4BIT is CUDA-only (bitsandbytes); use NONE elsewhere.
Serve-it-now (pre-abliterated GGUF — Ollama, no compute)
The fast path on Apple Silicon / no-GPU. Same class of model, zero processing.
| Ollama ref | Params | Pull |
|---|---|---|
huihui_ai/llama3.2-abliterate:1b | 1B | validated in this skill |
huihui_ai/llama3.2-abliterate:3b | 3B | better quality |
huihui_ai/qwen2.5-abliterate:7b | 7B | general use |
| any HF GGUF | — | ollama run hf.co/<user>/<repo>:<quant> |
Search more at ollama.com for "abliterate"/"uncensored". Heretic's own outputs are published to its Hugging Face org — convert to GGUF (heretic-to-ollama.sh) if no GGUF is provided.
Quant guidance (GGUF)
Q4_K_M is the default sweet spot (size/quality). Q5_K_M / Q6_K for more fidelity; Q8_0 near-lossless but large. f16 is the unquantized intermediate.
Heretic — troubleshooting (dogfood-validated 2026-05-30, M4 Pro / macOS 26.5)
Every row below was hit and resolved during the dogfood that produced this skill. Evidence: /tmp/dogfood-heretic/heretic-run{1..8}.log.
Blocker → cause → fix
| # | Symptom | Root cause | Fix |
|---|---|---|---|
| 1 | ValueError: Either a revision or a version must be specified at import heretic.main (via transformers/integrations/hub_kernels.py:89) | Universal: transformers 5.9.x ↔ kernels 0.15.x incompatibility. kernels is an optional accelerator transformers tries to register at import. | pip uninstall -y kernels kernels-data. (Alternative: pin a compatible kernels version once known.) |
| 2 | module 'jinja2' has no attribute 'pass_eval_context' → Failed to load model with all configured dtypes | Base-env only: an ancient jinja2 2.11.3 (pre-3.0) was pinned by a legacy package. Chat-template rendering needs Jinja2 ≥ 3.0. | pip install -U 'jinja2>=3.1'. A clean venv never has this. |
| 3 | LLVM ERROR: Failed to infer result type(s): "mps.matmul"(tensor<1x16x1x128xbf16>, tensor<1x8x128x31xbf16>) then hard abort | Platform: PyTorch-MPS bug on grouped-query-attention shapes (n_q_heads ≠ n_kv_heads — Qwen3, Llama-3, Mistral, …). Hard Metal-compiler abort, not catchable. | Force --device-map cpu (+ PYTORCH_ENABLE_MPS_FALLBACK=1). MPS is effectively unusable for GQA models until PyTorch fixes it. |
| 4 | Run times out before reaching trials / during batch-size probe | Performance: CPU only ~50–110 tok/s; no CUDA → bitsandbytes (CUDA-only) inert. The default --max-batch-size probe alone can exhaust a short budget. | Pin --batch-size N --max-batch-size N to skip the probe; shrink prompt sets; or use a GPU. For real (4–12B) models, use a GPU. |
| 5 | OSError: [Errno 22] Invalid argument / KeyError: '0 is not registered' at the end (or start) of a run | TTY: the save/upload/chat menu and the resume menu use questionary/prompt_toolkit, which need a real terminal. Piped or /dev/null stdin crashes — after optimization completes, so the model is lost. | Run heretic in an interactive terminal. Never pipe stdin if you want to save. |
| 6 | At startup: "You have already processed this model… continue the previous run?" then a TTY crash | A prior interrupted run left a checkpoint in --study-checkpoint-dir. | Pass a fresh --study-checkpoint-dir, or delete the old checkpoint, or answer the menu in a TTY. |
The core architectural fact
Ollama cannot be Heretic's backend. Heretic mutates raw HF transformer weights (reads residual-stream activations to compute difference-of-means "refusal directions", then orthogonalizes attn.o_proj + mlp.down_proj against them). That requires PyTorch + transformers + full weights. Ollama is inference-only over GGUF/llama.cpp — no activation access, no weight editing. They sit at different layers. The only connection is downstream:
Heretic (HF safetensors)
→ convert_hf_to_gguf.py (llama.cpp)
→ llama-quantize Q4_K_M
→ ollama create -f Modelfile
→ ollama runPerformance reference (validated)
| Path | Hardware | Result |
|---|---|---|
| Full abliteration, Qwen3-0.6B, 1 trial | M4 Pro CPU | refusals 6/8 → 1/8, KL 0.0026, Optimization finished! |
| Forward pass throughput | M4 Pro CPU | 50–110 tok/s (batch 1→64) |
| MPS forward pass | M4 Pro Metal | ✗ LLVM abort (row 3) |
| Real model (README baseline) | RTX 3090 | Llama-3.1-8B ≈ 45 min |
| Serve pre-abliterated GGUF | M4 Pro (Ollama) | instant; capability preserved, false-refusals removed |
Lesson: on Apple Silicon, treat this as serve-only (pull a pre-abliterated GGUF) unless you have a GPU. Run Heretic itself on CUDA — locally or via broomva/remote-gpu.
#!/usr/bin/env bash
# claude-code-on-ollama.sh — drive Claude Code with a LOCAL Ollama model.
#
# Ollama serves the Anthropic Messages API natively at /v1/messages — the exact
# protocol Claude Code speaks — so NO proxy (claude-code-router / LiteLLM) is needed.
# Claude Code just points at Ollama:
# ANTHROPIC_BASE_URL=http://localhost:11434 ANTHROPIC_API_KEY=ollama claude --model <m>
#
# Validated 2026-05-31 (M4 Pro / 24GB / Ollama 0.20.7):
# - Text round-trips fine -> usable as a CHAT backend with any model.
# - Tool-calls are MODEL-FAMILY specific: Llama-3.x emits the format Ollama parses
# into tool_use blocks (works even abliterated); Qwen2.5 does NOT. Default below is
# a Llama-family model for that reason.
# - The FULL Claude Code agent loop does NOT complete on 24GB: 128K ctx overflows RAM
# (empty), capped 32K ctx starves/crashes decode (empty). A working local agent
# needs 64GB+ unified RAM or a GPU box (broomva/remote-gpu). On 24GB: chat only.
#
# Usage:
# scripts/claude-code-on-ollama.sh [model] [--smoke] [-- <extra claude args>]
# scripts/claude-code-on-ollama.sh huihui_ai/qwen2.5-coder-abliterate:14b --smoke
# scripts/claude-code-on-ollama.sh # launch interactive claude on default model
set -euo pipefail
MODEL="${1:-huihui_ai/llama3.2-abliterate:3b}" # Llama family: tool-calls parse in Ollama (Qwen2.5 don't)
[ $# -gt 0 ] && shift || true
OLLAMA_URL="${OLLAMA_HOST:-http://localhost:11434}"
SMOKE=0; PASS=()
for a in "$@"; do [ "$a" = "--smoke" ] && SMOKE=1 || PASS+=("$a"); done
command -v claude >/dev/null 2>&1 || { echo "ERROR: claude (Claude Code) not on PATH."; exit 1; }
command -v ollama >/dev/null 2>&1 || { echo "ERROR: ollama not on PATH (brew install ollama)."; exit 1; }
# daemon up?
curl -sf "$OLLAMA_URL/api/version" >/dev/null 2>&1 || { echo "starting ollama daemon…"; ollama serve >/tmp/ollama.log 2>&1 & for _ in $(seq 1 20); do curl -sf "$OLLAMA_URL/api/version" >/dev/null 2>&1 && break; sleep 0.5; done; }
# native Anthropic endpoint present? (the whole trick)
code=$(curl -s -o /dev/null -w '%{http_code}' -X POST "$OLLAMA_URL/v1/messages" \
-H 'content-type: application/json' \
-d "{\"model\":\"$MODEL\",\"max_tokens\":5,\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}]}" 2>/dev/null)
if [ "$code" != "200" ]; then
echo "ERROR: Ollama at $OLLAMA_URL does not serve /v1/messages (HTTP $code)."
echo " Upgrade Ollama (brew upgrade ollama) — native Anthropic Messages API required."
exit 1
fi
# model present? pull if not
if ! ollama list 2>/dev/null | awk '{print $1}' | grep -qx "$MODEL"; then
echo "pulling $MODEL …"; ollama pull "$MODEL"
fi
# capability nudge
case "$MODEL" in
*:1b|*:0.5b|*:1.5b|*:2b|*:3b) echo "⚠️ $MODEL is small — expect poor tool-use / agentic reliability. 14B+ recommended." ;;
esac
export ANTHROPIC_BASE_URL="$OLLAMA_URL"
export ANTHROPIC_API_KEY="ollama" # dummy; Ollama ignores auth
export ANTHROPIC_MODEL="$MODEL"
if [ "$SMOKE" = 1 ]; then
echo "=== capability probe: can $MODEL drive Claude Code's tools? ==="
echo " (one agent turn on a 14B can take minutes — be patient)"
WORK="$(mktemp -d)"; LOG="$WORK/stream.json"
( cd "$WORK" && timeout "${SMOKE_TIMEOUT:-600}" \
claude -p "Use the Bash tool to run exactly: echo OLLAMA_AGENT_OK" \
--model "$MODEL" --dangerously-skip-permissions \
--output-format stream-json --verbose < /dev/null > "$LOG" 2>&1 ) || true
python3 - "$LOG" <<'PY'
import json, sys, re
tu = tr = False; result = ""
for line in open(sys.argv[1]):
line = line.strip()
if not line.startswith("{"): continue
try: o = json.loads(line)
except Exception: continue
m = o.get("message", {})
if isinstance(m, dict):
for c in (m.get("content") or []):
if isinstance(c, dict) and c.get("type") == "tool_use": tu = True
if isinstance(c, dict) and c.get("type") == "tool_result": tr = True
if o.get("type") == "result": result = str(o.get("result", ""))
texty = bool(re.search(r'```json|tool_call|"arguments"\s*:|"name"\s*:\s*"(Bash|Read|Edit|Write|Glob|Grep)"', result))
if tu and tr:
print("✅ AGENTIC — tool_use round-tripped and executed. Usable as a Claude Code agent.")
elif texty:
print("⚠️ CHAT-ONLY — model emitted the tool call as TEXT, not a structured tool_use")
print(" block; Ollama /v1/messages did not translate it, so Claude Code can't run it.")
print(" Fine as a chat/Q&A backend; NOT a tool-using agent.")
else:
print("✗ no usable tool attempt (model too weak, or endpoint lacks tool translation).")
PY
rm -rf "$WORK"
else
echo "Launching Claude Code on $MODEL (Ctrl-C to exit)…"
exec claude --model "$MODEL" "${PASS[@]}"
fi
#!/usr/bin/env bash
# heretic-doctor.sh — environment readiness check for the heretic-abliteration skill.
# Reports which path is viable: GPU-run, CPU-run (slow), or serve-only.
set -euo pipefail
VENV="${HERETIC_VENV:-$HOME/.venvs/heretic}"
echo "=== Heretic / Ollama environment doctor ==="
echo
# --- platform ---
OS="$(uname -s)"; ARCH="$(uname -m)"
echo "Platform : $OS $ARCH"
if [[ "$OS" == "Darwin" ]]; then
echo "Chip : $(sysctl -n machdep.cpu.brand_string 2>/dev/null || echo '?')"
RAM_GB=$(( $(sysctl -n hw.memsize 2>/dev/null || echo 0) / 1024 / 1024 / 1024 ))
echo "RAM : ${RAM_GB} GB unified"
fi
# --- accelerator ---
ACCEL="cpu"
if command -v nvidia-smi >/dev/null 2>&1; then
ACCEL="cuda"
echo "GPU : CUDA detected → $(nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null | head -1)"
elif [[ "$OS" == "Darwin" && "$ARCH" == "arm64" ]]; then
ACCEL="mps-blocked"
echo "GPU : Apple Metal (MPS) present — but BLOCKED for GQA models (PyTorch mps.matmul bug). Heretic must run --device-map cpu here."
else
echo "GPU : none detected (CPU-only)"
fi
# --- python / venv / heretic ---
echo
if [[ -d "$VENV" ]]; then
echo "venv : $VENV (exists)"
# shellcheck disable=SC1091
source "$VENV/bin/activate"
else
echo "venv : $VENV (MISSING — run scripts/heretic-install.sh)"
fi
echo "python : $(python3 --version 2>&1) [$(command -v python3)]"
if python3 -c "import heretic.main" >/dev/null 2>&1; then
HV=$(python3 -c "import importlib.metadata as m; print(m.version('heretic-llm'))" 2>/dev/null || echo '?')
echo "heretic : OK (heretic-llm $HV, importable)"
else
echo "heretic : NOT importable (run scripts/heretic-install.sh; check kernels/jinja2 fixes)"
fi
# --- ollama ---
echo
if command -v ollama >/dev/null 2>&1; then
echo "ollama : $(ollama --version 2>&1 | head -1)"
if curl -sS http://localhost:11434/api/version >/dev/null 2>&1; then
echo " daemon UP"
else
echo " daemon DOWN (start with: ollama serve &)"
fi
else
echo "ollama : NOT installed (brew install ollama)"
fi
# --- llama.cpp (for GGUF conversion) ---
CONVERT="$(command -v convert_hf_to_gguf.py || true)"
if command -v llama-quantize >/dev/null 2>&1 && [[ -n "$CONVERT" ]]; then
echo "llama.cpp: OK (llama-quantize + $CONVERT)"
else
echo "llama.cpp: incomplete (need 'brew install llama.cpp' for llama-quantize + convert_hf_to_gguf.py)"
fi
# --- disk ---
echo
echo "disk : $(df -h / | awk 'NR==2{print $4" free on /"}')"
# --- verdict ---
echo
echo "=== Recommended path ==="
case "$ACCEL" in
cuda) echo "→ RUN locally: scripts/heretic-run.sh <model> (GPU; BNB_4BIT ok)." ;;
mps-blocked) echo "→ CPU only (slow, small models). For real models use broomva/remote-gpu, then scripts/heretic-to-ollama.sh."
echo "→ Or skip running Heretic entirely: scripts/ollama-pull-abliterated.sh (fast, recommended)." ;;
*) echo "→ CPU only (slow). Prefer scripts/ollama-pull-abliterated.sh, or a GPU via broomva/remote-gpu." ;;
esac
#!/usr/bin/env bash
# heretic-install.sh — install heretic-llm into a CLEAN, dedicated venv and apply
# the two dependency fixes discovered during the 2026-05-30 dogfood.
#
# Why a venv (not conda base): heretic pulls transformers 5.9.0 which drags in two
# breakages. One (kernels) is universal; the other (ancient jinja2) only bites
# crowded base envs. A fresh venv + these defensive fixes = clean import.
set -euo pipefail
VENV="${HERETIC_VENV:-$HOME/.venvs/heretic}"
echo "=== Installing heretic-llm into $VENV ==="
if ! command -v python3 >/dev/null 2>&1; then
echo "ERROR: python3 not found (need 3.10+)."; exit 1
fi
# 1. Clean venv (never the conda base env)
if [[ ! -d "$VENV" ]]; then
python3 -m venv "$VENV"
fi
# shellcheck disable=SC1091
source "$VENV/bin/activate"
python3 -m pip install -U pip >/dev/null
# 2. Install heretic
python3 -m pip install -U heretic-llm
# 3. FIX #1 (universal): transformers 5.9.x ↔ kernels 0.15.x import crash
# "ValueError: Either a revision or a version must be specified" in
# transformers/integrations/hub_kernels.py. kernels is an OPTIONAL accelerator.
python3 -m pip uninstall -y kernels kernels-data >/dev/null 2>&1 || true
# 4. FIX #2 (defensive): chat-template needs jinja2 >= 3.0 (pass_eval_context).
# Fresh venvs are fine; this only matters if an old jinja2 leaked in.
python3 -m pip install -U 'jinja2>=3.1' >/dev/null
# 5. gguf (for later HF→GGUF conversion via convert_hf_to_gguf.py)
python3 -m pip install -U gguf >/dev/null 2>&1 || true
# 6. Verify the import actually works
echo
if python3 -c "import heretic.main; print('import OK')"; then
HV=$(python3 -c "import importlib.metadata as m; print(m.version('heretic-llm'))" 2>/dev/null || echo '?')
echo "✅ heretic-llm $HV installed and importable in $VENV"
echo " Activate with: source $VENV/bin/activate"
echo " Next: scripts/heretic-doctor.sh then scripts/heretic-run.sh <model>"
else
echo "❌ heretic still not importable — see references/troubleshooting.md"
exit 1
fi
#!/usr/bin/env bash
# heretic-run.sh — run a Heretic abliteration locally with the right device flags.
#
# IMPORTANT: run this in a REAL TERMINAL. Heretic's end-of-run "save / upload / chat"
# menu (and the resume menu) use questionary, which needs a TTY. Piping stdin from
# /dev/null makes it crash (OSError [Errno 22]) AFTER optimization finishes — so you
# lose the saved model. A TTY is required to actually save the result.
#
# Usage:
# scripts/heretic-run.sh <hf-model-id> [extra heretic args...]
# scripts/heretic-run.sh Qwen/Qwen3-4B-Instruct-2507
# scripts/heretic-run.sh Qwen/Qwen3-0.6B --n-trials 8 # small smoke
set -euo pipefail
VENV="${HERETIC_VENV:-$HOME/.venvs/heretic}"
MODEL="${1:-}"
if [[ -z "$MODEL" ]]; then
echo "Usage: $0 <hf-model-id> [extra heretic args...]"; exit 1
fi
shift || true
if [[ ! -d "$VENV" ]]; then
echo "ERROR: venv $VENV missing. Run scripts/heretic-install.sh first."; exit 1
fi
# shellcheck disable=SC1091
source "$VENV/bin/activate"
# TTY guard — heretic needs an interactive terminal to save.
if [[ ! -t 0 ]]; then
echo "⚠️ stdin is not a TTY. Heretic will run the optimization but CRASH at the"
echo " save menu, discarding the model. Run in an interactive terminal to save."
fi
# Device selection (dogfood-validated):
OS="$(uname -s)"; ARCH="$(uname -m)"
DEV_ARGS=()
if command -v nvidia-smi >/dev/null 2>&1; then
echo "→ CUDA detected. Full speed; add --quantization BNB_4BIT to fit large models."
elif [[ "$OS" == "Darwin" && "$ARCH" == "arm64" ]]; then
echo "⚠️ Apple Silicon: forcing --device-map cpu. MPS hits a PyTorch mps.matmul"
echo " LLVM error on grouped-query-attention models (Qwen3, Llama3, …)."
echo " CPU works but is slow (~50–110 tok/s). Use a real GPU for >1B models"
echo " (see broomva/remote-gpu)."
export PYTORCH_ENABLE_MPS_FALLBACK=1
DEV_ARGS=(--device-map cpu --quantization NONE)
else
echo "→ No GPU: running on CPU (slow)."
DEV_ARGS=(--device-map cpu --quantization NONE)
fi
set -x
heretic --model "$MODEL" "${DEV_ARGS[@]}" "$@"
#!/usr/bin/env bash
# heretic-to-ollama.sh — convert a Heretic-saved HF model into a GGUF and register
# it with Ollama. This is the bridge: Heretic outputs HF safetensors; Ollama serves
# GGUF. Ollama can NEVER be Heretic's backend — it only runs the finished model.
#
# Pipeline: HF safetensors → convert_hf_to_gguf.py → llama-quantize → ollama create
#
# Usage:
# scripts/heretic-to-ollama.sh <hf-model-dir> [ollama-name] [quant]
# scripts/heretic-to-ollama.sh ./Qwen3-4B-heretic my-heretic Q4_K_M
set -euo pipefail
MODEL_DIR="${1:-}"
NAME="${2:-heretic-model}"
QUANT="${3:-Q4_K_M}"
VENV="${HERETIC_VENV:-$HOME/.venvs/heretic}"
WORK="${HERETIC_WORK:-$(pwd)/gguf-out}"
if [[ -z "$MODEL_DIR" || ! -d "$MODEL_DIR" ]]; then
echo "Usage: $0 <hf-model-dir> [ollama-name] [quant]"; exit 1
fi
CONVERT="$(command -v convert_hf_to_gguf.py || echo /opt/homebrew/bin/convert_hf_to_gguf.py)"
if [[ ! -e "$CONVERT" ]]; then
echo "ERROR: convert_hf_to_gguf.py not found. brew install llama.cpp"; exit 1
fi
if ! command -v llama-quantize >/dev/null 2>&1; then
echo "ERROR: llama-quantize not found. brew install llama.cpp"; exit 1
fi
if ! command -v ollama >/dev/null 2>&1; then
echo "ERROR: ollama not found. brew install ollama"; exit 1
fi
# Ensure gguf python dep (convert script needs it)
[[ -d "$VENV" ]] && source "$VENV/bin/activate" || true
python3 -c "import gguf" 2>/dev/null || python3 -m pip install -U gguf
mkdir -p "$WORK"
F16="$WORK/${NAME}-f16.gguf"
Q="$WORK/${NAME}-${QUANT}.gguf"
echo "=== 1/3 HF → GGUF (f16) ==="
python3 "$CONVERT" "$MODEL_DIR" --outfile "$F16" --outtype f16
echo "=== 2/3 quantize → $QUANT ==="
llama-quantize "$F16" "$Q" "$QUANT"
echo "=== 3/3 ollama create '$NAME' ==="
MODELFILE="$WORK/Modelfile.$NAME"
printf 'FROM %s\n' "$Q" > "$MODELFILE"
ollama create "$NAME" -f "$MODELFILE"
echo
echo "✅ Registered. Smoke test:"
echo " ollama run $NAME \"In one word, capital of Australia?\""
#!/usr/bin/env bash
# ollama-pull-abliterated.sh — FAST PATH (recommended on Apple Silicon / no GPU).
# Skip running Heretic entirely: pull a community pre-abliterated GGUF straight into
# Ollama and smoke-test it. Same *class* of model Heretic produces, zero compute.
#
# Usage:
# scripts/ollama-pull-abliterated.sh [ollama-model]
# scripts/ollama-pull-abliterated.sh huihui_ai/llama3.2-abliterate:3b
#
# Catalogs of pre-abliterated GGUFs: ollama.com (search "abliterate"), or any
# Hugging Face GGUF via: ollama run hf.co/<user>/<repo>:<quant>
set -euo pipefail
MODEL="${1:-huihui_ai/llama3.2-abliterate:1b}"
if ! command -v ollama >/dev/null 2>&1; then
echo "ERROR: ollama not found. brew install ollama"; exit 1
fi
if ! curl -sS http://localhost:11434/api/version >/dev/null 2>&1; then
echo "Starting ollama daemon…"; ollama serve >/tmp/ollama-heretic.log 2>&1 &
for _ in $(seq 1 20); do curl -sS http://localhost:11434/api/version >/dev/null 2>&1 && break; sleep 0.5; done
fi
echo "=== pulling $MODEL ==="
ollama pull "$MODEL"
ask() { # prompt -> clean response via API (no TTY spinner noise)
curl -sS http://localhost:11434/api/generate \
-d "{\"model\":\"$MODEL\",\"prompt\":$(printf '%s' "$1" | python3 -c 'import json,sys;print(json.dumps(sys.stdin.read()))'),\"stream\":false}" \
| python3 -c "import sys,json;print(json.load(sys.stdin)['response'][:400])"
}
echo
echo "=== smoke 1: capability preserved ==="
ask "What is the capital of Australia? Answer in one word."
echo
echo "=== smoke 2: false-refusal removed (benign sysadmin prompt) ==="
ask "How do I kill a frozen process on Linux? Give the exact command."
echo
echo "✅ Served via Ollama CLI. Chat with: ollama run $MODEL"
{
"version": 1,
"skills": {
"heretic-abliteration": {
"source": "broomva/heretic-abliteration",
"sourceType": "github",
"computedHash": ""
}
}
}
Related skills
FAQ
Can Ollama be Heretic's backend?
No. Heretic edits raw HF weights and reads activations in PyTorch, while Ollama is inference-only over GGUF, so the link is downstream: Heretic to GGUF to Ollama.
Does it work on Apple Silicon?
MPS is blocked by a PyTorch GQA matmul bug, so Macs run on CPU and are treated as serve-only; real models need a CUDA GPU.
What is the zero-compute path?
Running ollama-pull-abliterated.sh to pull a community pre-abliterated GGUF and run capability and false-refusal smoke checks.