Rules
Garm rules
Every rule Garm runs, what triggers it, and the exact text it shows. Source: SPEC §5 (v6.7 FINAL + v6.8 notes). Garm has no LLM and no score: the same post with the same data gives the same output on every install.
Colours. Grey is a fact. Amber is a tell. Red is a clear mismatch. Garm never shows green. Pills, chips and stamps state facts about posts, coins and wallets and never accuse a named person.
What hides a post. Only post rules (§5.1) fold a post. Coin rules warn and never hide a post. A fold shows one bar: Hidden · <reason ≤80 chars> · Show · Not spam. Show brings the post back; Not spam keeps it shown; "Always show @handle" (on this device) means that account is never folded.
Guards that always win. A WARNING post ("fake CA", "scammers", "wrong ca", "is this legit"…) never trips a lure, link, dup or burst rule. Allowlisted official and news accounts are never folded. Accounts you always show are never folded. One post never trips a burst rule. Text rules match case-insensitively; base58 addresses are compared exactly.
CAs. A candidate is any base58 string of 32–44 characters that decodes to 32 bytes. It counts as a CA only once it resolves to a mint (DEX Screener tokens, then pairs, then getAccountInfo). Wallets, token accounts and unknown accounts are dropped. While a candidate is resolving, anything that depends on it is grey "can't confirm", never red.
Order. Every step runs for every post: guards → fold rules → local pills → ring step → server facts → claimed-vs-live → R10 → hijack tell → render. Nothing earlier skips anything later.
1. Fold rules (post level; these are the only rules that hide a post)
| Rule id | Trigger | Shows |
|---|---|---|
dup | Not a WARNING post, author under 20k followers, ≥3 posts with the same text key in 24 h, ≥2 distinct authors in that set posted this post's exact CA, and ≥1 of them has a funnel (in that post or their own posts within 10 min) or is a ring member / linked to a ring | Fold: "same text from N accounts on this CA" |
dup (grey) | ≥3 posts with the same key but the conditions above don't all hold (one author reposting a template, or matching text with no funnel or ring link) | Grey: "repeated caller template (N posts)" (never folds) |
same_ | A reply; the same author and CA in ≥3 distinct conversations within 60 min (own-timeline posts never count) | Fold: "same CA in N other replies" |
same_ (slow) | A reply, author under 20k followers; the same author and CA in ≥4 distinct conversations in the 24 h before this reply, counting only other accounts' conversations (not the author's own thread, and not a conversation whose root is the coin's own account: an account whose posts or bio seen on this device carry this CA, or a listed project account) | Fold: "same CA in N other replies today" |
bare_ | A reply of ≤6 words with a $TICKER and no CA; the same author and ticker in ≥3 conversations in 60 min, or ≥5 accounts in ≥5 threads; checked for every ticker in the reply | Fold: "$X dropped in N unrelated threads" |
caller_ | A gain brag (a ≥10x multiplier with a gain word within 25 characters, a CA or "mc"; an emoji counts as one character; or a K→M arrow) and a funnel (alpha/VIP/TG group, t.me link, "link in bio", "join … tg", "on my tg group", a referral link on a terminal or bot host) in the same post, or brag and funnel in two posts by the same author within 10 min (decided from earlier posts already seen). Scanner report lines, hashtags and tracker lines from bot-like authors are removed before the brag test | Fold: "caller ad: gain brag + TG funnel" |
caller_ (later funnel) | A funnel post arrives after the brag; the brag is re-folded when it is rendered again | Fold: "caller ad (funnel posted N min later)" |
caller_ (one key) | Only a brag or only a funnel | Grey: "caller-style post (gain brag)" or "caller-style post (TG funnel)" (never folds) |
recovery | Phrases recover your/lost/my, recover(ed) your/my funds/crypto/assets, recovery agent/expert/service, assess potential recovery, anti-fraud investigation, or contact/reach out to/DM @x … recover/hack/trace | Fold: "recovery-scam reply" |
promo | "new listing on dexvra", "new/express listing", "diamond tier", "#bbvipks4", "trending now", "the right push", "let's get in touch/connect/collaborate", "reach out so we can", "explore a collaboration", "DMs (are) open", "promotional ideas/services" | Fold: "paid listing / caller promo" |
ring_ | A stock shill line: "is pumping over $", "mogs $", or a line that starts "thank you dev" | Fold: "copy-paste shill line" |
farmed | A farmed hype template: "$1 sign-up bonus", "check out $X @y, a next-level", "agentdojo" | Fold: "farmed hype template" |
campaign | ≥5 accounts post generic praise under posts tagging the same handle within 2 min | Fold: "campaign replies" |
paragraph | The same text key from ≥10 accounts in 24 h with a $ticker or CA | Dim: "promoted: copy-paste campaign" |
bounty | A dup cluster where the coin's linked account posts a pay-per-post offer | Warn: "paid posts (disclosed bounty)" (never folds) |
lure | Not a WARNING post; anywhere in the text, any case: "check eligib…" or "check your eligib…", "may/might/could/can be eligible", "allocation scan", "scan wallet" or "scan your wallet", "claim up to", "of supply distribut…" (with or without "the" and "is being"), "memepage", "airdrop page", or "explore", "discover", "meet" or "take a closer look at" followed by "airdrop" within 50 characters; or the rules_v2 lure phrases ("see if you're eligible", "eligible for … airdrop … check/here/link", "of the supply will be distributed", "airdrop is worth a look", "learn about … airdrop", "airdrop … explore/learn about/take a closer look"); or a weak claim phrase ("claim your/now", "see what you can claim") from an account under 50k followers | Fold: airdrop lure ("<matched phrase>"), e.g. airdrop lure ("memepage") |
lure (memory) | An author with ≥2 lures in view in 24 h; their other posts with "airdrop", "eligib" or "claim" that nothing else folds | Fold: "airdrop lure (account posted N lures)" |
link_ | Not a WARNING post; an account with ≥3 link-only posts (links and no words) in view in 24 h | Fold: "link-only posts from this account" |
lookalike_ | Handle within edit distance 2 of an allowlisted project handle and ≥3 link-only posts in view | Fold: "lookalike of @handle (N link-only posts)" |
placeholder | [Add …], [Insert …] or [Your …] in a coin post | Amber: "unfilled template" (never folds on its own) |
Strictness. Relaxed / Balanced (default) / Strict. Strict turns on the Communities safe/strict preset. Raw view shows X exactly as it is. Local-only mode makes no network calls at all.
2. Link rules (expanded link in the post; never fetched)
| Rule id | Trigger | Shows |
|---|---|---|
link_ | A free-host page (netlify.app, vercel.app, pages.dev, workers.dev, github.io, web.app, firebaseapp.com, onrender.com, glitch.me, replit.app, repl.co, surge.sh, herokuapp.com, framer.website, framer.app, webflow.io, wixsite.com, carrd.co, weebly.com, 000webhostapp.com, fly.dev) with a base58 address (32–44 characters) in the path or query | Red: "free-host page carrying a mint" |
link_ | A free host whose subdomain has claim, airdrop, drop, reward, eligib, allocation, bonus, giveaway or redeem (and no address in the link) | Red: "claim page on a free host" |
link_ | A host ending in .memepage.io other than www.memepage.io | Red: "MemePage claim subdomain" |
link_ | The site's registered domain is within edit distance 2 of a protected brand (after homoglyph and punycode), and isn't the brand | Red: "lookalike of <brand>" |
link_ | A protected brand's name in a subdomain or path label of an unrelated site (brands named by a common word never fire; profile paths on x.com, t.me, YouTube, GitHub and other social sites are skipped) | Red: "<brand> name on an unrelated site" |
| MetaMask list | A match on the bundled MetaMask phishing list | Adds to a reason, never alone |
3. Local pills (no API)
| Rule id | Trigger | Shows |
|---|---|---|
thread_ | A reply has CA c with $T; the root post of the same conversation by @A has CA r with the same $T; c ≠ r. Never on @A's own replies or WARNING posts | Red: "different CA from the one @A posted in this thread" |
two_ | One author posts ≥2 different CAs for the same $T in 24 h | Amber: "posted 2 CAs for $T" |
major | A major ticker ($BTC, $ETH, $SOL, $WBTC, … from config/majors.json) called next to a Solana mint that isn't in that ticker's canonical list. A chain ticker that only names the chain or quote ("$PUMP on $SOL") is skipped | Red: "not the real $T (real: <first4>…<last4>)" |
evm_ | A 0x address given for a Solana ticker | Amber: "EVM address for a Solana ticker" |
evm_ (context) | A 0x address with no ticker in a post with Solana context (a mint, a "solana:"/"sol:" label, a pump.fun, Solscan or Jupiter link). No pill when the 0x address carries a non-Solana chain prefix, unless "CA", "contract", "official", "token address" or "mint" is just before it | Amber: "EVM address beside a Solana coin" |
r11 (local) | The coin's linked X post (from token metadata or the DEX Screener profile) is ≥10 min older than the mint and its text doesn't name the coin's name, ticker or CA. Skipped when the linked author is the coin's own pinned account | Amber: "linked post is {age} older than this coin and doesn't name it" ({age} = "N days", "N hours" or "N minutes"; never "0 days") |
dev_ | Not a WARNING post, one CA with a known deployer D; the author posted ≥3 coins from D in 14 days, ≥30% of their coins with a known deployer, each pushed within 24 h of its creation; author isn't a bot/tracker/scanner or allowlisted; D is an on-curve key | Amber: "@{A} has posted {N} coins from one deployer wallet in 14 days ({D first4}…{D last4})" |
4. Ring memory (local, per device)
| Rule id | Trigger | Shows |
|---|---|---|
ring | The post's author is a member of a ring this device has seen: ≥3 accounts, each with shared 10-minute gain-line bursts on ≥2 distinct CAs. Members drop out after 14 days with no new edge | Amber: "pushed by a known ring · N accts · ring's coins: X down ≥90% from peak, Y holding". The record counts the ring's coins from the last 30 days: "down ≥90%" means the market cap now is at most 10% of the highest reserve-backed market cap Garm has seen for that coin; "holding" means it is above that and pool reserves back today's cap. Other coins are left out; with none known the chip ends at "N accts" |
ring_ | A post by a non-member carries a CA a known ring pushed | Grey: "coin pushed by a known ring (N accts)" |
ring_ | An account shares ≥2 windows with a ring's members on 1 CA but fails the 2-CA rule | Grey: "linked to ring R (1 coin)" (never a member, never red; decays in 14 d) |
Lure posts, WARNING posts, disclosed bounties, reposts and fans repeating a CA on their own timeline never form ring edges. Ring handles stay on your device.
5. Coin rules (server facts; warn only, never hide a post)
| Rule id | Trigger | Shows |
|---|---|---|
family | Exact name/ticker matches for $T across Jupiter and DEX Screener searches | Grey: "1 of M+ mints called $T · oldest ≠ deepest" ("M+" when a search hit its cap) |
family (stamp) | No confirmed real mint (the day-one default) | Grey: "no confirmed real mint · 1 of M+ called $T" |
deployer | Deployer launch facts (no colour, no score, no verdict) | "deployer: {n} launches · {g} graduated ({source})" |
name_ | The coin's normalised name or ticker exactly matches a curated brand | Red: "name-bait: not made by <brand>" |
template13 | Top 3 non-pool, non-locker holders at 13.0–14.6%, ~0.24% and ~0.05% (skipped under 30 holders) | Red: "dump template (13-14% wallet)" |
buyout | (pumpdata on only, off by default) the first-10 s buyers fit the linked-factory pattern at ≈79.31% | Amber: "curve bought by 1 wallet / linked factory" |
fake_ | A fund-style name ("national/american/federal/global … oil/dividend/reserve/trust … fund/reserve") | Red: "fake fund name: no real fund issues this" |
r11 (server) | The linked X post predates the mint by ≥10 min (date test only; the local pill replaces it when the post text is known) | Amber: "linked post predates this coin" |
r12 | One non-pool, non-locker wallet holds ≥90% of supply, or two hold ≥49% each | Red: "one wallet holds N%: market cap is not real" |
r12 (pre-filter) | GeckoTerminal says the top 10 hold under 90% | Grey: "holders: top 10 hold N% (GeckoTerminal, hh:mm)" |
r12 (unchecked) | The holder read was rate-limited | Grey: "holders: unchecked" |
r4 | The coin's normalised name or ticker equals a trending coin's, it isn't that mint, and one wallet holds ≥90% | Red: "copy of <trending> · one wallet holds N%" |
r13 | Off in this build until its live check passes: no pill, and no lookup is sent. When on: the coin's own metadata links an @handle (not the coin's own account) and your browser hasn't seen a post by @handle with this mint. Clicking the pill asks our API for that link again (the coin's address only, at most once a day per coin unless a read failed, never in Local-only): if it links no X account any more the pill goes, and another handle is checked the same way | Grey: "named after @handle · no post from @handle with this mint seen" |
r4b | A top-5 wallet (≥1%, on the ed25519 curve, not on the non-holder list) was also a top wallet of earlier coins that are all down ≥90% from a reserve-backed peak | Red: "same top wallet as <symbol> (<w4>…), down N% from peak" · Why: "in K earlier coins, all down ≥90%" |
r4b (operator) | The same wallet also holds a live earlier coin (≥1%, under 90% down, ≥24 h old) | Why note only: "top wallet also holds <symbol> (N%)" |
reserves (quote token) | Liquidity, always from the pool's actual reserves read at check time (never assumed from "migrated" or "graduated"); the pool's quote mint is read first. A non-SOL quote with an unknown price | Grey: "pool holds N SOL (US$…)", "pool drained", or "liquidity unknown" (never "$0") |
Wallets held through a program, like a multisig vault, aren't matched.
6. Coin rules computed on your device
| Rule id | Trigger | Shows |
|---|---|---|
r10 | ≥5 posts about the coin in view and in cache, every one from an account with a post-rule hit (a §1–2 fold other than lookalike_handle, or the copy-paste-campaign dim, whatever your strictness setting; a disclosed bounty alone doesn't count; an allowlisted official account always counts as organic, while an account you always show still counts by its post rules), so no organic posts | "· risky: attention is paid callers only" |
r10_ | The first post about the coin came after it first reached a US$500k market cap, and there are no organic posts | "· attention arrived after the pump" |
claimed_ | A post claims a market cap; Garm compares it with a reading at or before the post's time (on-chain reserves or the post-time 5-min candle) | "claimed $X · at post $Y ({onchain|candle}, hh:mm AWST)"; amber only when the claim is ≥2× or ≤0.5× the reading |
claimed_ (no reading) | No reading at or before the post | Grey: "claim $X · no pre-post reading" |
claimed_ (reserves) | The cap isn't backed by pool reserves | Grey: "cap not backed by pool reserves"; "pool drained" when the quote side is under 1 SOL (or US$150) |
facts | Our server hasn't answered yet for this mint, or it couldn't check it (RPC or DEX Screener down after retries) | Grey "checking…" until the answer lands; grey "unverified" if it never does. Never red, never green |
hijack | A post with a CA from an account seen ≥20 times with no CA before | Amber: "first CA seen from @h in N posts" (+ "· profile changed since {date}" when the bio or location changed within 72 h) |
7. Coin-page guard (badge, side panel, notification; never on the terminal's page)
Garm reads only the address (URL) of the coin page you open from an X post, never the page itself.
| Rule id | Trigger | Shows |
|---|---|---|
guard_ (post/thread) | The page you land on resolves to a different mint from the CA the post (or its thread) wrote | Red "!" badge; notification "⚠ This link opens a different coin from the CA written in the {post|thread} (@{author}, {age})"; panel "written: abcd…wxyz · opened: efgh…stuv ($SYM)" |
guard_ (major) | The post named a major ticker and the page is not its real mint | "⚠ This link opens a coin that isn't the real $T (real: abcd…wxyz)" |
guard_ (ticker) | The post named $T and the page is a different symbol | "⚠ This link opens $SYM, not the $T the post names" |
guard_ | Same mint | Badge clear; panel "matches the post you came from" |
guard_ / guard_ | Still checking / can't resolve | Grey "…" / grey "can't confirm mint" (never red) |
Clicking the notification opens the side panel for that tab and switches to it. The panel also shows the grey family line for the opened coin ("1 of M+ mints called $T") when that family has more than one mint; for it, our API gets the opened coin's mint (never in Local-only mode).
8. Led you here (opt-in; your public wallet address only; on your device only)
| Rule id | Trigger | Shows |
|---|---|---|
lyh | ≥1 buy of a coin you opened from an account's post | Grey chip: "led you here N× · {±X.X SOL} · {k} of N held 24h" (amber only when the result is below 0 and there are ≥2 buys); Why: "{j} fell 80% within 1h of your buy" |
lyh (unchecked) | The RPC was busy | Grey: "led you here: unchecked (RPC busy)" |
Tracking from today. Nothing leaves your browser.
Turning it on asks Chrome for permission to read public Solana data. If that is denied, the toggle switches back off with "Led you here needs permission to read public Solana data."
9. Trade on Axiom chip (hand-off only)
| Rule id | Trigger | Shows |
|---|---|---|
trade_ | An unfolded post with exactly one resolved mint and no red pill or red guard; the options toggle is on | "Trade on Axiom" chip opening axiom.trade/meme/{pair}?chain=sol for that mint (no referral or tracking parameter); no chip while the coin is still being checked (the row's one grey "checking…" says so) or when it ends unverified; no chip on folded posts |