July 14, 20266 min read

Angry Bear: Enforcing the Skills Your Coding Agent Keeps Forgetting

Angry Bear is Bluebear's open-source pre-tool-use hook that blocks AI coding agents from editing files until the required skills are loaded, turning 'please follow the conventions' into a precondition. MIT, works with Claude Code and Cursor.

The Angry Bear logo

My new most hated two-word combination: “Compacting conversation.”

I don’t need a coding assistant. I need an autonomous engineer! (but like… governed.)

At Bluebear, we use coding agents by default. Not because it’s trendy - because we’re building the next generation of AI-agent security, and we need first-hand battle scars with these new, shiny, super-powerful tools. And as anyone working with coding agents knows: they can be a blessing and a curse at the same time - and one of the sharpest curses is a phrase you’ve almost certainly watched scroll by: “Compacting conversation.”

What “compacting conversation” actually is

Every coding agent runs inside a fixed context window. As a session goes long, that window fills up - so the agent compacts: it summarizes and drops older turns to make room. The catch is what gets dropped. The big-picture goal, the design decisions we agreed on three hours ago, the “never touch this file” rule - the very things that MUST stay in mind are the first to get squeezed out, precisely because they’re old. The agent keeps going as if it still remembers. It doesn’t. Anyone who has run a long agent session has felt this.

Those two words can mean the waste of a day, or more. It’s like the movie 50 First Dates. Supposedly the agent remembers what we spoke about, and at first glance it feels like it picks up exactly where we left off.

But very, very soon I realize it forgot the big picture and all the critical design choices we made over hours - sometimes days. Now I need to remind it of everything… only here there’s no “they lived happily ever after” at the end.

I tried many tricks: asking it to keep a progress log, creating markdown files at every step. It always works for a while, but as the context gets longer - and more of that “compacting conversation” happens - the more it forgets what really MUST stay in mind.

Like… we’re building coding-agent security and guardrails 😉. We know irony when we see it.

After some success with local progress and subtask files, I had a thought: what if I could force the agent to follow the tasks? To know where it is in the big picture, and not side-track? Basically: if what you’re about to do isn’t directly relevant to the task and the epic (think matryoshka doll) - STOP. Update the task, create a new one, or ask me to clarify. No ghost work.

And then it hit me. The solution isn’t “better reminders.” The solution is enforcement.

The Thanos moment: Skills + Hooks = Infinity Gauntlet 🟣🟦🟥🟩🟨

I realized I could combine the predictability of Hooks with Skills as policy context. The Skill is the policy doc - the rules plus the minimal context the agent must carry. The Hook is the bouncer at the door.

Version 1 was crude and ticket-shaped: every Write or Edit was blocked until the agent had run /ticket and attached a ticket ID. That alone was already magic - no more ghost commits, no more drift from spec.

But once the gate worked, the obvious next move was: why stop at ticket?

From a Linear gate to a generic policy engine

The hook didn’t actually care that the required skill was “linear.” It cared that the right skill was loaded before the right tool touched the right file. So we generalized it: a tiny rules engine keyed on (tool, path_glob, agent) → required_skill.

Now the same hook enforces:

  • Editing any *.go file? You must have loaded go-coding-standards first.
  • Touching anything under **/tests/**? Load testing-architect.
  • Editing database schema files? Load db-schema-standards. Field types are strict, and schema mismatches cause silent failures.
  • Anything, anywhere? Still need a ticket. That rule never went away; it just became one row in the table.

The config is intentionally boring - declarative JSON, no code:

{
  "version": 1,
  "tools": [
    { "tool": "Edit",  "path": "**",           "skill": "ticket-tracker",      "agent": "*" },
    { "tool": "Edit",  "path": "**/*.go",       "skill": "go-coding-standards", "agent": "*" },
    { "tool": "Write", "path": "stacks/**",     "skill": "sst-architect",       "agent": "*" },
    { "tool": "Edit",  "path": "**/tests/**",   "skill": "testing-architect",   "agent": "*" },
    { "tool": "Edit",  "path": "**/schema/**",  "skill": "db-schema-standards", "agent": "*" }
  ]
}

When the agent tries to edit a Go file without go-coding-standards loaded, the hook returns:

Blocked by angry-bear skill enforcement.
Required skills not loaded: "go-coding-standards".
Load them by running: /go-coding-standards

The agent reads the message, invokes the skill, and only then gets to write. The skill itself injects the conventions that file is supposed to follow, so the diff that comes out is already shaped right.

A blocked Edit, the agent loading the required skill, and the retry being allowed
A blocked Edit → the agent loads the required skill → the retry is allowed.

Open source: Angry Bear 🐻

The hook and rules engine are now their own project: Angry Bear - MIT, works with Claude Code and Cursor out of the box (anything else implements one adapter). Install it, declare your rules, and your agent inherits the same discipline. No vendor lock-in to Linear, to a specific agent, or to a specific skill set - bring your own.

View Angry Bear on GitHub
brew tap bluebear-io/angry-bear && brew trust bluebear-io/angry-bear && brew install angry-bear
cd your-project
angry-bear add go-coding-standards --tool Edit,Write --path "**/*.go"
# ✓ Hooks installed for claude
# ✓ Hooks installed for cursor

Rules can live per-machine or be committed to the repo (--repo) so the whole team gets the same gate on the same branch.

The angry-bear TUI dashboard showing skills, rules, and a live event log of every block, load, and allow
The angry-bear TUI dashboard - skills, rules, and a live event log of every block / load / allow.

What actually changed in output quality

This is the part I didn’t expect. Before, “follow the Go conventions” was a polite suggestion the agent obeyed for the first three files and forgot by the fourth. After:

  • Style drift dropped to ~zero. The skill is loaded at the moment of editing, not 40k tokens ago. Compaction can’t erase it, because the hook re-asks every time.
  • Tests stopped being an afterthought. testing-architect fires the moment a test file is touched, so the agent opens a test file first instead of bolting tests on at the end.
  • Subsystem foot-guns got blocked at the door. Editing OpenSearch mappings without opensearch-mapping loaded used to cost us reindexes. Now it’s mechanically impossible.
  • PR review time dropped. Most of what humans used to catch in review is caught before the diff exists.

The skill is the what and the why. The hook is the when. Together they turn “please follow the conventions” into a precondition.