Skip to content

ArtemisAI/strip-gemma-4

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

strip-gemma banner

strip-gemma

She's small. She thinks out loud. Just strip her and get the job done.

A tiny reverse proxy that strips Gemma 4's thinking habits and makes her output client-appropriate. What happens in <|channel>thought stays in reasoning_content.

gemma undressed thinking stripped 5.6MB binary sub-ms overhead license

The Problem

Gemma 4 has a thinking problem. She always thinks out loud — even when you ask her not to. With llama-server's --reasoning-format none (the only option that doesn't leave content empty), every response arrives fully exposed:

{
  "content": "<|channel>thought\nOk let me think about this very carefully...\n2+2... carry the nothing... equals 4!\n<channel|>4"
}

Your clients see everything. Your chatbot shows the inner monologue. Your agent tries to parse channel tags. Your users see way more than they signed up for.

The Fix

Put strip-gemma between your client and llama-server. She handles the wardrobe change:

Client --> strip-gemma :8081 --> llama-server :8080
                  |
          "keep it classy"

Now your responses come out properly dressed:

{
  "content": "4",
  "reasoning_content": "Ok let me think about this very carefully...\n2+2... carry the nothing... equals 4!"
}

Clean content for the audience. Thinking tucked away in reasoning_content for those who want a peek behind the curtain.

Quick Start

Binary (the fastest way to undress her output)

curl -fsSL https://github.com/ArtemisAI/strip-gemma/releases/latest/download/strip-gemma-linux-amd64 -o strip-gemma
chmod +x strip-gemma
./strip-gemma -upstream http://localhost:8080

Docker

docker run --network host ghcr.io/artemisai/strip-gemma -upstream http://localhost:8080

Build from source

go install github.com/ArtemisAI/strip-gemma@latest

Usage

strip-gemma [flags]

Flags:
  -listen string    Address to listen on (default ":8081")
  -upstream string  Upstream llama-server URL (default "http://localhost:8080")
  -mode string      'split' (default) or 'strip'
  -version          Print version and exit

Modes

Mode What the client sees What happens to thinking Vibe
split (default) Clean answer Preserved in reasoning_content Tasteful
strip Clean answer Gone forever Full censorship

How She Works

Gemma 4 wraps her thoughts in channel tags:

<|channel>thought
[internal monologue about life, the universe, and 2+2]
<channel|>[the actual answer]

Non-streaming: strip-gemma reads the full response, separates thinking from answer, and rewrites the JSON. One and done.

Streaming: A three-state machine processes SSE chunks token by token:

  1. State 0Buffering: accumulates tokens looking for the opening tag
  2. State 1Thinking: emits tokens as reasoning_content (split mode) or suppresses them (strip mode)
  3. State 2Presenting: passes answer tokens through as content with zero added latency

No buffering delay once thinking ends. Answer tokens stream the instant <channel|> is seen.

Edge cases? She handles those too

Scenario Behavior
Thinking cut off by max_tokens Thinking emitted, content empty
No thinking tags at all Passed through unchanged
Empty thinking (thought\n<channel|>) Content extracted cleanly
Non-chat endpoints (/health, /metrics) Passed through, not touched

Deploy as systemd sidecar

sudo cp strip-gemma /usr/local/bin/

sudo tee /etc/systemd/system/strip-gemma.service << 'EOF'
[Unit]
Description=strip-gemma thinking proxy
After=llama-server.service
Requires=llama-server.service

[Service]
Type=simple
ExecStart=/usr/local/bin/strip-gemma -listen :8081 -upstream http://localhost:8080
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable --now strip-gemma

Then point your load balancer at :8081 instead of :8080. She'll take it from there.

Why not --reasoning-format deepseek?

Because llama-server's deepseek mode puts everything into reasoning_content and leaves content completely empty. The model's thoughts and answer get tangled together in one field. Known issue with Gemma 4's chat template.

--reasoning-format none + strip-gemma = the only combo that actually works.

Performance

GPU Setup Quant Speed Proxy overhead
RTX 3090 + RTX 3060 Q6_K ~19 t/s < 1ms
2x RTX 3060 Q4_K_M ~16.5 t/s < 1ms

5.6MB static binary. ~2MB RAM. Zero dependencies. She's low maintenance.

FAQ

Q: Does this work with models other than Gemma 4? A: If your model uses <|channel>thought...<channel|> tags, yes. Otherwise she'll just pass everything through untouched.

Q: Does this disable thinking? A: No. Gemma still thinks. strip-gemma just makes sure the audience doesn't see the rehearsal.

Q: Is this name appropriate? A: We're stripping tags from Gemma's output. What were you thinking?

Related

License

MIT - do whatever you want with her (the code).

About

She's small, but she thinks out loud, just strip that thinking out and get the job done. A reverse proxy that turns Gemma 4's inline thinking into proper reasoning_content fields.

Topics

Resources

License

Stars

1 star

Watchers

1 watching

Forks

Packages

 
 
 

Contributors