Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HuskGuard 🐺

A concurrent moderation swarm for hasky.chat, a Nostr relay with an intentionally open write policy. Built on Mozaik (@mozaik-ai/core 4.x) for the JigJoy AI Hackathon, 5–6 September 2026.

The idea

Most relay moderation is one filter running in sequence. HuskGuard runs three specialist agents at the same time on every incoming note, plus a Judge that rules the instant the last vote lands — whichever order they arrive in.

wss://hasky.chat ──► RelayFeed ──► relay.event ──┬──► SpamWatcher ──────────┐
                                                 ├──► NipComplianceWatcher ─┼──► model.answer ──► Judge ──► moderation.verdict
                                                 └──► PolicyWatcher ────────┘
                                                                              Transcript observes everything
Participant Kind Reacts to Does
RelayFeed producer websocket turns every kind-1 note into a relay.event
SpamWatcher agent relay.event promo, bait, link-stuffing, bot patterns
NipComplianceWatcher agent relay.event tag shape, hex ids, plausible timestamps
PolicyWatcher agent relay.event genuinely disallowed content only — open relay, so strict about allowing
Judge participant model.answer from a watcher tallies votes per event, rules when all three are in
Transcript observer everything the demo log, with ms offsets

How the concurrency works (for judges)

  • Each watcher registers a SituationHandler on relay.event. Mozaik fans events out to every participant without awaiting any processor.
  • Each watcher's processor calls runLoop() — fire-and-forget — with a fresh ModelContext per event, so the three loops run in parallel and never share a cursor.
  • Watchers answer via structured output ({ eventId, verdict, reason, confidence }), which is how the Judge knows which note a vote belongs to when answers arrive out of order.
  • The Judge is a reaction on model.answer, filtered by producerId. It doesn't poll, doesn't wait, doesn't know the order — it just rules when the third vote for an event shows up.

The proof is in the transcript: three verdicts for the same note land within ~100–250 ms of each other, in a different order every time.

📨 3d095f48  FREE AIRDROP!!! Click here https://x.yz/free ...
   +  90ms  ⚠️  NipComplianceWatcher ...
   + 136ms  ⚠️  SpamWatcher          ...
   + 234ms  ⚠️  PolicyWatcher        ...
   + 234ms  ⚖️  JUDGE → FLAG  (3 votes in 234ms)

Run it

npm install
cp .env.example .env     # set MODEL + the matching provider key
npm run dev              # watch hasky.chat live

In a second terminal, give it something to judge:

npm run inject           # publishes 4 test notes: clean, spammy, malformed tags, garbage

No API key handy? Prove the plumbing with the built-in fake model — real relay, real websocket, instant verdicts:

npm run demo:fake

Layout

src/
  index.ts          boot: runtime → transcript → judge → 3 watchers → relay
  runtime.ts        defineRuntime<HuskState>() + FakeInferenceRunner
  state.ts          HuskState (votes, timings, decisions) + shared types
  relay.ts          RelayFeed participant (nostr-tools)
  agents/
    watchers.ts     the three specialist agents + their instructions
    judge.ts        vote tally + decision rule
    transcript.ts   the log you see
scripts/
  inject.ts         test-note publisher (throwaway key)

Decision rule

reject if any watcher rejects with confidence ≥ 0.7 · flag if any watcher is not allow · otherwise allow. Deliberately simple — the point is the swarm, not the rule.

License

MIT

About

Concurrent Nostr relay moderation swarm on Mozaik — 3 watchers, 1 Judge, live on hasky.chat.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages