From agent-almanac
Classifies gate call variants in a minified JS bundle — identifies reader variants, default values, conjunctions, and kill-switch inversion for feature flags.
How this skill is triggered — by the user, by Claude, or both
Slash command
/agent-almanac:decode-minified-js-gatesThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Read the call-site context around a flag string in a minified JavaScript bundle and produce a gate-mechanics record: which reader variant, what default, what conjunction, what role. Where `probe-feature-flag-state` answers "is this gate on or off?", this skill answers the prerequisite question — "what does this gate actually do?"
Read the call-site context around a flag string in a minified JavaScript bundle and produce a gate-mechanics record: which reader variant, what default, what conjunction, what role. Where probe-feature-flag-state answers "is this gate on or off?", this skill answers the prerequisite question — "what does this gate actually do?"
sweep-flag-namespace cannot be classified from its name alone.{}, null, a numeric literal) and you need to decode the actual reader variant.&& and you need to enumerate the co-gates before probing any of them..js, .mjs, .bun).Locate the flag string and capture an asymmetric window around each occurrence. The pre-context (before the flag) is where the reader function name lives; the post-context (after) is where the default value and conjunction live.
BUNDLE=/path/to/cli/bundle.js
FLAG=acme_widget_v3 # synthetic placeholder
PRE=300
POST=200
# All byte offsets where the flag string occurs
grep -boE "\"${FLAG}\"" "$BUNDLE" | cut -d: -f1 > /tmp/decode-offsets.txt
wc -l /tmp/decode-offsets.txt
# Capture an asymmetric window per occurrence
while read -r offset; do
start=$((offset - PRE))
[ "$start" -lt 0 ] && start=0
length=$((PRE + POST))
echo "=== offset $offset ==="
dd if="$BUNDLE" bs=1 skip="$start" count="$length" 2>/dev/null
echo
done < /tmp/decode-offsets.txt > /tmp/decode-windows.txt
less /tmp/decode-windows.txt
For a fast first pass, grep -oE with negative lookbehind via Perl-compatible regex catches the same windows in one pipe.
Expected: one or more context windows per flag occurrence, each ~500 chars. Multiple occurrences typically share the same reader function but may differ in default or conjunction — inspect each independently.
On failure: if the bundle is too large for dd-per-occurrence (binary > 100MB or many occurrences), use rg -B 5 -A 3 "$FLAG" "$BUNDLE" for a structured-output approximation. If the windows look corrupted, the bundle may be UTF-16 or have non-ASCII delimiters; use iconv or treat as binary.
Minified gate libraries commonly expose 4–6 reader variants with different semantics. The reader function name is the first cue; the call signature is the verifier.
The variant taxonomy (synthetic names — substitute the actual minified identifiers from your bundle):
| Variant | Synthetic shape | Returns | Common usage |
|---|---|---|---|
| Sync boolean | gate("flag", false) or gate("flag", true) | boolean | Standard on/off feature switches |
| Sync config-object | fvReader("flag", {key: value}) | JSON object | Structured config (delays, allowlists, model names) |
| Bootstrap-aware TTL | ttlReader("flag", default, ttlMs) | boolean (cached) | Startup-path gates before remote config arrives |
| Truthy-only | truthyReader("flag") | truthy/falsy | Quick checks; no explicit default |
| Async bootstrap | asyncReader("flag") | Promise<boolean> | Gates resolved post-bootstrap |
| Async bridge | bridgeReader("flag") | Promise<boolean> | Bridge/relay-channel gates with separate evaluation path |
Match each context window against the variant patterns:
# Test for variant patterns. Replace the synthetic reader names with the
# actual minified identifiers found in the bundle.
grep -oE '\b(gate|fvReader|ttlReader|truthyReader|asyncReader|bridgeReader)\("acme_widget_v3"' /tmp/decode-windows.txt | sort | uniq -c
If multiple variants appear for the same flag (rare but real — a flag read both sync at startup and async post-bootstrap), record each occurrence's variant separately. Probe results may differ.
Expected: every gate-call occurrence is tagged with one variant. Variant counts across the whole sweep produce a binary-level distribution (e.g., "60% sync boolean, 30% config-object, 10% TTL").
On failure: if a context window contains no recognizable reader pattern, the flag may not actually be gate-called — recheck the call-site classification from sweep-flag-namespace Step 2. If a window contains a reader name not in this taxonomy, document it as a new variant in your research artifacts and decide whether it warrants a separate handling path.
The default is the second positional argument to the reader (or absent for truthy-only / async variants). Capture the exact literal — false, true, null, 0, a string, or a JSON config object.
# Boolean default extraction (sync boolean and TTL variants)
grep -oE '\b(gate|ttlReader)\("acme_widget_v3",\s*(true|false)' /tmp/decode-windows.txt
# Config-object default — match the opening brace and capture until the
# matching brace at the same nesting depth. For minified bundles this is
# usually safe with a non-greedy match because objects rarely span lines.
grep -oE 'fvReader\("acme_widget_v3",\s*\{[^}]*\}' /tmp/decode-windows.txt
# Numeric default (rare but real for TTL or threshold gates)
grep -oE '\b(gate|ttlReader)\("acme_widget_v3",\s*[0-9]+' /tmp/decode-windows.txt
For config-object defaults, inspect the JSON structure — keys often hint at the gate's purpose (e.g., {maxRetries: 3, timeoutMs: 5000} is a retry-policy config, not a feature toggle).
Expected: an exact literal default per occurrence. Booleans are unambiguous; config-objects need a manual read of the structure.
On failure: if a config-object's matching brace falls outside the context window, increase the post-context size in Step 1. If a default appears to be a variable reference (e.g., gate("flag", x)), the default is computed at runtime — note this as DYNAMIC and probe the actual returned value via probe-feature-flag-state.
Many gates participate in compound predicates. Conjunctions (&&) and inversions (!) change the gate's effective role.
# Conjunction detection: gate-call followed by `&&` and another gate-call
# within the same predicate window
grep -oE '(gate|fvReader|ttlReader|truthyReader|asyncReader|bridgeReader)\("acme_widget_v3"[^)]*\)\s*&&\s*(gate|fvReader|ttlReader|truthyReader|asyncReader|bridgeReader)\("acme_[a-zA-Z0-9_]+"' /tmp/decode-windows.txt
# Kill-switch detection: leading `!` before the gate-call
grep -oE '!\s*(gate|fvReader|ttlReader|truthyReader|asyncReader|bridgeReader)\("acme_widget_v3"' /tmp/decode-windows.txt
For each detected conjunction, list the co-gate flag names. They are now part of the probe scope — if the target flag's evaluation depends on co-gates, probing the target alone produces incomplete state.
For each detected inversion, mark the flag as a kill switch in the gate-mechanics record. Kill switches flip the meaning of the default: a kill switch with default=false is "feature on by default" (because !false === true), while a normal gate with default=false is "feature off by default."
Expected: a conjunction list (possibly empty) and an inversion flag (boolean) per occurrence.
On failure: if a conjunction includes more than 2 co-gates, the predicate is complex enough that the regex misses the structure. Read the context window manually and document the predicate shape verbatim in the gate-mechanics record.
Synthesize Steps 2–4 into a role classification. Roles drive different probe strategies and different integration risk.
| Role | Signature | Implication |
|---|---|---|
| Feature switch | sync boolean, no inversion, no conjunction | Standard on/off; probe directly |
| Config provider | sync config-object (fvReader) | Read returned object; default-empty {} ≠ feature off |
| Lifecycle guard | bootstrap-aware TTL or async bootstrap | State depends on bootstrap timing; probe at multiple points |
| Kill switch | inverted gate, default-false | Feature on for users by default; flag flips it OFF |
| Conjunction member | any variant with && co-gate | Cannot evaluate alone; co-gates are part of the probe scope |
| Bridge gate | async bridge variant | Probe must occur over the bridge channel, not the main path |
Expected: every gate-call occurrence has exactly one primary role. Some flags appear in multiple roles across occurrences (e.g., a feature switch in one call site, a conjunction member in another) — record each role independently.
On failure: if a role does not fit the table, the binary is using a gate library not yet documented in this skill. Add a row with synthetic identifiers and contribute the variant back to the skill (or a project-specific extension) for future investigators.
Combine the per-flag findings into a structured record. JSONL is convenient because each flag becomes one line, easy to merge with sweep-flag-namespace inventory.
{"flag":"acme_widget_v3","variant":"sync_boolean","default":false,"role":"feature_switch","conjunctions":[],"inverted":false,"occurrences":3}
{"flag":"acme_retry_policy","variant":"sync_config_object","default":{"maxRetries":3,"timeoutMs":5000},"role":"config_provider","conjunctions":[],"inverted":false,"occurrences":1}
{"flag":"acme_legacy_path","variant":"sync_boolean","default":false,"role":"kill_switch","conjunctions":[],"inverted":true,"occurrences":2}
{"flag":"acme_beta_feature","variant":"sync_boolean","default":false,"role":"conjunction_member","conjunctions":["acme_beta_program_active"],"inverted":false,"occurrences":1}
The gate-mechanics record feeds probe-feature-flag-state Step 2 (gate-vs-event disambiguation): the variant + role + conjunction list determines what observations count as evidence of LIVE / DARK / INDETERMINATE state.
Expected: one JSONL record per flag (or per flag-occurrence if a single flag has multiple distinct mechanics). The record is reproducible — running the procedure again against the same binary produces the same record.
On failure: if records vary across runs, an upstream step is non-deterministic. Most often this is the regex in Step 1 missing or over-matching occurrences. Lock the regexes for the duration of a campaign.
acme_*, gate, fvReader, etc.) — no real flag names, real reader names, or real config-object schemasprobe-feature-flag-state (same flag identifiers, compatible field names)default=true is on by default in this binary, but server-side overrides may flip it. The default tells you the baseline; the runtime probe (probe-feature-flag-state) tells you the state.fvReader("flag", {}) returns an empty object as the default — but the flag is on (the gate evaluates to truthy). Treating {} as "off" misclassifies config-providers as feature switches.! before the gate-call inverts the meaning. Skipping Step 4 produces a record that says "default=false, feature off by default" when the truth is "default=false, feature ON by default because of the inversion."acme_widget_v3 && acme_user_in_cohort is the predicate, probing only acme_widget_v3 and finding it LIVE does not mean the feature is live — the conjunction may still gate it off via the cohort flag.a, b, Yc1) and feel safe to paste verbatim. They are still findings — substitute synthetic placeholders before publishing the methodology.probe-feature-flag-state — uses the gate-mechanics record to interpret runtime observationssweep-flag-namespace — produces the candidate flag set this skill decodesmonitor-binary-version-baselines — tracks reader-name changes across binary versions; re-derive Step 2 patterns when baselines flipredact-for-public-disclosure — how to publish gate-decoding methodology without exposing real reader names or schemasconduct-empirical-wire-capture — validates the gate-mechanics record against runtime behaviornpx claudepluginhub pjt222/agent-almanacExtracts all candidate feature flags from a binary namespace, disambiguates gate vs telemetry calls, and tracks completeness against a documented set until undocumented flags reach zero.
Manages feature flag lifecycle: detect flags in codebases, classify categories, and design rollout strategies with naming conventions. For auditing stale flags or planning new flag architecture.
Performs depth-first reverse engineering on Ghidra binaries, answering questions like function behavior, crypto usage, or C2 addresses via iterative analysis and database improvements.