[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-semgrep-install-mfw":3,"mdc--395aup-key":36,"related-repo-semgrep-install-mfw":1368,"related-org-semgrep-install-mfw":1378},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":25,"repoUrl":26,"updatedAt":27,"license":28,"forks":29,"topics":30,"repo":31,"sourceUrl":34,"mdContent":35},"install-mfw","install and configure Semgrep Malware Firewall","Install the mfw (Semgrep Malware Firewall) CLI via the curl|sh installer and walk the user through setup — trust store, PATH shims, shell integration, and the background daemon — asking questions at real decision points. Detects when the user's shell rc files are *managed* (symlinked into nix \u002F home-manager \u002F chezmoi \u002F GNU stow \u002F a dotfiles git repo) and, instead of clobbering them, adds mfw's source line to the right source-of-truth. Use when the user wants to install, set up, or onboard mfw on this machine.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"semgrep","Semgrep","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fsemgrep.png",[12,16,19,22],{"name":13,"slug":14,"type":15},"Security","security","tag",{"name":17,"slug":18,"type":15},"Onboarding","onboarding",{"name":20,"slug":21,"type":15},"CLI","cli",{"name":23,"slug":24,"type":15},"Deployment","deployment",9,"https:\u002F\u002Fgithub.com\u002Fsemgrep\u002Fguardian","2026-07-21T05:37:19.475723",null,5,[],{"repoUrl":26,"stars":25,"forks":29,"topics":32,"description":33},[],"Home for the Semgrep Claude Code Plugin.","https:\u002F\u002Fgithub.com\u002Fsemgrep\u002Fguardian\u002Ftree\u002FHEAD\u002Fplugin\u002Fskills\u002Finstall-mfw","---\nname: install-mfw\ndescription: Install the mfw (Semgrep Malware Firewall) CLI via the curl|sh installer and walk the user through setup — trust store, PATH shims, shell integration, and the background daemon — asking questions at real decision points. Detects when the user's shell rc files are *managed* (symlinked into nix \u002F home-manager \u002F chezmoi \u002F GNU stow \u002F a dotfiles git repo) and, instead of clobbering them, adds mfw's source line to the right source-of-truth. Use when the user wants to install, set up, or onboard mfw on this machine.\nallowed-tools:\n  - AskUserQuestion\n  - Read\n  - Edit\n  - Write\n  - Bash(uname:*)\n  - Bash(command -v *)\n  - Bash(sh ${CLAUDE_SKILL_DIR}\u002Fscripts\u002F*)\n  - Bash(${CLAUDE_SKILL_DIR}\u002Fscripts\u002F*)\n  - Bash(curl -fsSL https:\u002F\u002F*\u002Fdist\u002Fmfw\u002Finstall.sh | sh)\n  - Bash(mfw *)\n  - Bash(~\u002F.local\u002Fbin\u002Fmfw *)\n  - Bash(sudo mfw *)\n  - Bash(readlink *)\n  - Bash(realpath *)\n  - Bash(ls -l *)\n  - Bash(stat *)\n  - Bash(grep *)\n  - Bash(head *)\n  - Bash(home-manager *)\n  - Bash(darwin-rebuild *)\n  - Bash(nixos-rebuild *)\n  - Bash(chezmoi *)\n---\n\n# Install mfw\n\nInstall and set up the **mfw** client — Semgrep's Malware Firewall, a local MITM\nproxy that gates package-manager downloads (pip \u002F npm \u002F pnpm \u002F uv \u002F cargo \u002F maven\n\u002F gem \u002F nuget \u002F composer \u002F go) on Semgrep's backend before bytes hit disk.\n\n`$ARGUMENTS` may carry a backend\u002Fdist URL override (e.g. `https:\u002F\u002Fexample.semgrep.dev`)\nor `--store system`. Default backend is `https:\u002F\u002Fsemgrep.dev` (mfw is distributed\noff prod). If empty, use the defaults.\n\nYour job: drive the install end to end, **ask the user only at genuine decision\npoints** (via `AskUserQuestion`), and — the part that needs care — never edit a\n**managed** (symlinked) shell rc file in place. Work through the steps in order.\n\n## What fixup will do (state this to the user up front)\n\nThe installer downloads + checksum-verifies the binary to `~\u002F.local\u002Fbin\u002Fmfw`, then\n`mfw fixup`: ① generates a local CA and **adds it to the OS trust store** (plus, on\nmacOS with Homebrew present, into Homebrew's openssl trust dir), ② drops\npackage-manager **shim symlinks** in `~\u002F.semgrep\u002Fmfw\u002Fshims`, ③ writes\n`~\u002F.semgrep\u002Fmfw\u002Frc-setup.sh` (PATH + proxy\u002FCA env) and makes your **shell source\nit**, ④ installs a **background daemon** (launchd\u002Fsystemd\u002Fopenrc — skipped inside\ncontainers with no service manager) that runs the proxy and, via `mfw supervise`,\n**auto-updates** mfw on a schedule (on by default). Undo anytime with\n`mfw uninstall` (which also deletes the mfw binary). It is a real,\nsystem-modifying install — make sure the user is on\nboard before you run it (they invoked this skill, so a brief summary + proceeding\nis fine; only stop for the choices below).\n\n## Step 1 — Preconditions\n\n1. `uname -s` and `uname -m`. Supported: **Linux** `x86_64`\u002F`aarch64`, **macOS**\n   `arm64` (Apple silicon). If it's Windows, or Intel macOS, **stop**: there is no\n   published build — tell the user plainly.\n2. `command -v curl` (or `wget`). If neither, stop and say so.\n3. `command -v mfw` — if already installed, this is an idempotent re-run \u002F upgrade;\n   carry on (fixup self-heals).\n\n## Step 2 — Inspect the shell config BEFORE installing\n\nRun the inspector and parse it (do not dump it on the user):\n\n```\nsh ${CLAUDE_SKILL_DIR}\u002Fscripts\u002Finspect-shell-config.sh\n```\n\nFor the user's `login_shell`, look at its rc file(s): zsh → `~\u002F.zshrc`; bash →\n`~\u002F.bashrc` plus `~\u002F.bash_profile` or `~\u002F.profile`. Decide **managed vs plain**:\n\n- **Managed** = `symlink=yes` (any `class`: `nix`, `chezmoi`, `git-dotfiles`,\n  `unknown`) **or** `class=nix-generated` (a real file with a \"Generated by Home\n  Manager\u002FNix\" header). These are owned by a tool; editing the deployed file is\n  wrong — it's read-only (nix) or gets reverted on the next rebuild\u002Fapply.\n- **Plain** = a regular, writable file (or absent). Safe to edit directly.\n\n> **Why this gate exists:** `mfw fixup` writes its one-line hook with an atomic\n> `rename()` over the rc file, which **replaces a symlink with a regular file** —\n> clobbering a nix\u002Fhome-manager-managed rc. So managed rc files must never be\n> edited in place; mfw's one-line hook goes into the user's *source-of-truth*\n> instead.\n\nRemember the result; it decides Step 3 and Step 4.\n\n## Step 3 — Install\n\n**If the shell config is PLAIN** (and you don't otherwise need the managed path),\nuse the standard installer — it downloads, verifies, and runs `mfw fixup`, correctly\nediting the real rc file:\n\n```\ncurl -fsSL https:\u002F\u002Fsemgrep.dev\u002Fdist\u002Fmfw\u002Finstall.sh | sh\n```\n\n(Swap the host if `$ARGUMENTS`\u002Fenv gave an override: `…\u002F\u003Chost>\u002Fdist\u002Fmfw\u002Finstall.sh`.)\n\n`install.sh` reconnects a TTY (`mfw fixup \u003C\u002Fdev\u002Ftty`) so a human running it in a\nterminal gets the interactive prompts, and falls back to `mfw fixup --yes` when\nthere's no controlling terminal. When *you* run this line through the Bash tool\nthere's no TTY, so it takes the `--yes` path: fixup auto-accepts and edits the\nreal rc file at mfw's best-guess paths — exactly what we want for a plain config.\n\n**If the shell config is MANAGED**, do **not** run the bundled fixup (it would\nclobber the symlink). Install the binary only, then drive fixup with shell edits\nturned off:\n\n```\nsh ${CLAUDE_SKILL_DIR}\u002Fscripts\u002Finstall-binary.sh\n~\u002F.local\u002Fbin\u002Fmfw fixup --skip-login\n```\n\n`mfw fixup` here runs non-interactively (no TTY), so it writes\n`~\u002F.semgrep\u002Fmfw\u002Frc-setup.sh`, installs certs\u002Fshims\u002Fdaemon, and **prints** the\nshell lines instead of editing your rc — exactly what we want. We handle login in\nStep 6 and the shell hook in Step 4. (Pass an override URL with\n`--backend-url \u003Curl>` if one was given.)\n\nUse `~\u002F.local\u002Fbin\u002Fmfw` for subsequent calls in case `~\u002F.local\u002Fbin` isn't on PATH\nin this session yet.\n\n## Step 4 — Shell integration for managed configs\n\nSkip this whole step for plain configs (the installer already did it). For managed\nconfigs, the only thing the user's shell needs is this exact hook, which sources\nmfw's self-managed env file:\n\n```\n[ -r \"$HOME\u002F.semgrep\u002Fmfw\u002Frc-setup.sh\" ] && . \"$HOME\u002F.semgrep\u002Fmfw\u002Frc-setup.sh\"\n```\n\nThis single line is exactly what `mfw doctor` looks for (a trimmed line match — no\ncomment markers). Now find where it belongs and **ask the user** with `AskUserQuestion`,\noffering the `candidate=` paths the inspector found plus an \"Other\" path:\n\n- **nix \u002F home-manager** (`class=nix` or `nix-generated`): add the hook to the\n  shell-init attribute, e.g. `programs.zsh.initContent` (newer) or\n  `initExtra`\u002F`programs.bash.initExtra`\u002F`bashrcExtra`; on NixOS\n  `programs.zsh.interactiveShellInit`. If they instead manage the file wholesale\n  (`home.file.\".zshrc\".text = ''…''`), append the hook inside that string. A bare\n  `$HOME` is literal in nix strings (interpolation is `${…}`), so the line is safe\n  verbatim; if you're inside a `''…''` block and the linter complains about `${`,\n  there is none here, so no escaping is needed. After editing, tell the user to\n  rebuild: `home-manager switch` \u002F `darwin-rebuild switch` \u002F `sudo nixos-rebuild switch`.\n- **chezmoi** (`class=chezmoi`): edit the *source*, not the deployed file —\n  `chezmoi edit ~\u002F.zshrc` opens it, or edit the matching `dot_zshrc` in\n  `~\u002F.local\u002Fshare\u002Fchezmoi`; append the hook, then `chezmoi apply`.\n- **GNU stow \u002F dotfiles git repo** (`class=git-dotfiles`): the `resolved=` path IS\n  the real file in the repo (the symlink points straight at it). Append the hook\n  there with Edit, then remind the user to commit. No relink needed.\n- **unknown**: show the `link_target`\u002F`resolved` path, ask the user where the\n  source-of-truth is, and edit that.\n\nRead the target file first, then make a **minimal** Edit that inserts the hook in\nthe right place (inside the right nix attribute \u002F at the end of the rc source).\nConfirm the destination with the user before writing if there's any ambiguity.\n\n## Step 5 — Finish the trust store\n\n- **Linux:** the per-user pass usually can't establish trust (no per-user store).\n  Ask with `AskUserQuestion` whether to install the CA into the **system** store\n  (needs sudo): `sudo mfw install-certs --store system`. If they decline, note that\n  gated downloads will fail TLS verification until it's trusted.\n- **macOS:** adding the CA to the login keychain can pop a GUI \"allow\" \u002F password\n  prompt that you can't click. If the certs step didn't complete, tell the user to\n  run `mfw install-certs` themselves and approve the prompt. (Homebrew's openssl\n  trust is handled by fixup automatically when brew is present.)\n\n## Step 6 — Login (optional, browser)\n\nmfw runs without login — unauthenticated requests just follow the configured\nfail-open\u002Fclosed policy — but it can't actually scan until authenticated. Check\nthe login line in `mfw doctor` (Step 7). If not authenticated, ask whether to log\nin now. `mfw login` opens a browser OAuth flow you can't complete for them, so\nhave **them** run it in this session: suggest they type `! mfw login` (or set\n`SEMGREP_APP_TOKEN`). Don't block the rest of fixup on it.\n\n## Step 7 — Verify and hand off\n\n1. Run `mfw doctor` (use `~\u002F.local\u002Fbin\u002Fmfw doctor` if needed). Walk the user\n   through anything still ✗. For managed configs the shell line stays ✗ until they\n   restart their shell (and, for nix, rebuild first). Doctor also prints a few\n   **informational** lines that aren't failures: a version\u002Fupdate check\n   (`up to date` \u002F `update available … run mfw upgrade`), whether auto-update is\n   disabled, and whether the supervisor is running — don't treat those as ✗.\n2. Tell them to **restart their shell** — `exec \"$SHELL\" -l` or a new terminal —\n   then re-run `mfw doctor`; it should print the \"Semgrep mfw is protecting this\n   machine.\" banner (a green `○○○` logo + a little watching face whose eyes are\n   randomized each run). If\n   they're not logged in the headline is instead \"mfw can't scan anything until\n   you authenticate — run `mfw login`\" (see Step 6); other steps can still be ✓.\n   If they're signed in but their Semgrep deployment doesn't have the Semgrep\n   malware firewall enabled, the login line is ✗ and the headline is \"the Semgrep\n   malware firewall isn't enabled for your Semgrep deployment. Enable it in Semgrep\n   or ask your org admin.\" — that's a backend entitlement issue, not a fixup step,\n   so re-running `mfw fixup` won't fix it.\n3. Summarize what you did, where things live (`~\u002F.semgrep\u002Fmfw\u002F`, shims on PATH,\n   the managed daemon), and that `mfw uninstall` reverses everything (and deletes\n   the mfw binary). mfw keeps\n   itself updated via the supervisor (auto-update on by default); `mfw upgrade`\n   forces it now and `mfw restart` bounces the daemon.\n\n## Notes\n\n- Prefer the pre-approved commands above so the user isn't re-prompted. The\n  `curl … | install.sh | sh` line modifies the system — it's expected to need one\n  confirmation; let it.\n- **mfw's own rc-edit prompt** (only shown with a TTY — not when you drive it via\n  the Bash tool): for the shell step it batches into one question,\n  `Edit them all? [Y]es \u002F [n]o, show me the line to add myself \u002F [s]kip`, and\n  per-file it's `Apply to \u003Cpath>? [Y]es \u002F [n]o, I'll do it myself \u002F [s]kip`. The\n  default is **yes** (Enter applies the edit); `n` immediately prints the source\n  line to paste yourself, `s` skips.\n  Because your Bash-tool calls have no TTY, `mfw fixup` runs non-interactively: it\n  still writes `rc-setup.sh`, installs certs\u002Fshims\u002Fdaemon, and *prints* (never\n  edits) the rc lines — which is exactly why the managed-config path in Step 3 works.\n- Never put secrets\u002Ftokens in anything you write. The hook only sources a file.\n- If a step fails, report the actual error and what it means for protection\n  (e.g. \"certs not trusted → gated downloads fail TLS\"); don't paper over it.\n",{"data":37,"body":61},{"name":4,"description":6,"allowed-tools":38},[39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60],"AskUserQuestion","Read","Edit","Write","Bash(uname:*)","Bash(command -v *)","Bash(sh ${CLAUDE_SKILL_DIR}\u002Fscripts\u002F*)","Bash(${CLAUDE_SKILL_DIR}\u002Fscripts\u002F*)","Bash(curl -fsSL https:\u002F\u002F*\u002Fdist\u002Fmfw\u002Finstall.sh | sh)","Bash(mfw *)","Bash(~\u002F.local\u002Fbin\u002Fmfw *)","Bash(sudo mfw *)","Bash(readlink *)","Bash(realpath *)","Bash(ls -l *)","Bash(stat *)","Bash(grep *)","Bash(head *)","Bash(home-manager *)","Bash(darwin-rebuild *)","Bash(nixos-rebuild *)","Bash(chezmoi *)",{"type":62,"children":63},"root",[64,72,86,122,148,155,243,249,346,352,357,369,421,504,547,552,558,575,584,604,646,663,672,704,724,730,735,744,779,1011,1023,1029,1082,1088,1131,1137,1267,1273],{"type":65,"tag":66,"props":67,"children":68},"element","h1",{"id":4},[69],{"type":70,"value":71},"text","Install mfw",{"type":65,"tag":73,"props":74,"children":75},"p",{},[76,78,84],{"type":70,"value":77},"Install and set up the ",{"type":65,"tag":79,"props":80,"children":81},"strong",{},[82],{"type":70,"value":83},"mfw",{"type":70,"value":85}," client — Semgrep's Malware Firewall, a local MITM\nproxy that gates package-manager downloads (pip \u002F npm \u002F pnpm \u002F uv \u002F cargo \u002F maven\n\u002F gem \u002F nuget \u002F composer \u002F go) on Semgrep's backend before bytes hit disk.",{"type":65,"tag":73,"props":87,"children":88},{},[89,96,98,104,106,112,114,120],{"type":65,"tag":90,"props":91,"children":93},"code",{"className":92},[],[94],{"type":70,"value":95},"$ARGUMENTS",{"type":70,"value":97}," may carry a backend\u002Fdist URL override (e.g. ",{"type":65,"tag":90,"props":99,"children":101},{"className":100},[],[102],{"type":70,"value":103},"https:\u002F\u002Fexample.semgrep.dev",{"type":70,"value":105},")\nor ",{"type":65,"tag":90,"props":107,"children":109},{"className":108},[],[110],{"type":70,"value":111},"--store system",{"type":70,"value":113},". Default backend is ",{"type":65,"tag":90,"props":115,"children":117},{"className":116},[],[118],{"type":70,"value":119},"https:\u002F\u002Fsemgrep.dev",{"type":70,"value":121}," (mfw is distributed\noff prod). If empty, use the defaults.",{"type":65,"tag":73,"props":123,"children":124},{},[125,127,132,134,139,141,146],{"type":70,"value":126},"Your job: drive the install end to end, ",{"type":65,"tag":79,"props":128,"children":129},{},[130],{"type":70,"value":131},"ask the user only at genuine decision\npoints",{"type":70,"value":133}," (via ",{"type":65,"tag":90,"props":135,"children":137},{"className":136},[],[138],{"type":70,"value":39},{"type":70,"value":140},"), and — the part that needs care — never edit a\n",{"type":65,"tag":79,"props":142,"children":143},{},[144],{"type":70,"value":145},"managed",{"type":70,"value":147}," (symlinked) shell rc file in place. Work through the steps in order.",{"type":65,"tag":149,"props":150,"children":152},"h2",{"id":151},"what-fixup-will-do-state-this-to-the-user-up-front",[153],{"type":70,"value":154},"What fixup will do (state this to the user up front)",{"type":65,"tag":73,"props":156,"children":157},{},[158,160,166,168,174,176,181,183,188,190,196,198,204,206,211,213,218,220,226,228,233,235,241],{"type":70,"value":159},"The installer downloads + checksum-verifies the binary to ",{"type":65,"tag":90,"props":161,"children":163},{"className":162},[],[164],{"type":70,"value":165},"~\u002F.local\u002Fbin\u002Fmfw",{"type":70,"value":167},", then\n",{"type":65,"tag":90,"props":169,"children":171},{"className":170},[],[172],{"type":70,"value":173},"mfw fixup",{"type":70,"value":175},": ① generates a local CA and ",{"type":65,"tag":79,"props":177,"children":178},{},[179],{"type":70,"value":180},"adds it to the OS trust store",{"type":70,"value":182}," (plus, on\nmacOS with Homebrew present, into Homebrew's openssl trust dir), ② drops\npackage-manager ",{"type":65,"tag":79,"props":184,"children":185},{},[186],{"type":70,"value":187},"shim symlinks",{"type":70,"value":189}," in ",{"type":65,"tag":90,"props":191,"children":193},{"className":192},[],[194],{"type":70,"value":195},"~\u002F.semgrep\u002Fmfw\u002Fshims",{"type":70,"value":197},", ③ writes\n",{"type":65,"tag":90,"props":199,"children":201},{"className":200},[],[202],{"type":70,"value":203},"~\u002F.semgrep\u002Fmfw\u002Frc-setup.sh",{"type":70,"value":205}," (PATH + proxy\u002FCA env) and makes your ",{"type":65,"tag":79,"props":207,"children":208},{},[209],{"type":70,"value":210},"shell source\nit",{"type":70,"value":212},", ④ installs a ",{"type":65,"tag":79,"props":214,"children":215},{},[216],{"type":70,"value":217},"background daemon",{"type":70,"value":219}," (launchd\u002Fsystemd\u002Fopenrc — skipped inside\ncontainers with no service manager) that runs the proxy and, via ",{"type":65,"tag":90,"props":221,"children":223},{"className":222},[],[224],{"type":70,"value":225},"mfw supervise",{"type":70,"value":227},",\n",{"type":65,"tag":79,"props":229,"children":230},{},[231],{"type":70,"value":232},"auto-updates",{"type":70,"value":234}," mfw on a schedule (on by default). Undo anytime with\n",{"type":65,"tag":90,"props":236,"children":238},{"className":237},[],[239],{"type":70,"value":240},"mfw uninstall",{"type":70,"value":242}," (which also deletes the mfw binary). It is a real,\nsystem-modifying install — make sure the user is on\nboard before you run it (they invoked this skill, so a brief summary + proceeding\nis fine; only stop for the choices below).",{"type":65,"tag":149,"props":244,"children":246},{"id":245},"step-1-preconditions",[247],{"type":70,"value":248},"Step 1 — Preconditions",{"type":65,"tag":250,"props":251,"children":252},"ol",{},[253,316,335],{"type":65,"tag":254,"props":255,"children":256},"li",{},[257,263,265,271,273,278,280,286,288,294,296,301,307,309,314],{"type":65,"tag":90,"props":258,"children":260},{"className":259},[],[261],{"type":70,"value":262},"uname -s",{"type":70,"value":264}," and ",{"type":65,"tag":90,"props":266,"children":268},{"className":267},[],[269],{"type":70,"value":270},"uname -m",{"type":70,"value":272},". Supported: ",{"type":65,"tag":79,"props":274,"children":275},{},[276],{"type":70,"value":277},"Linux",{"type":70,"value":279}," ",{"type":65,"tag":90,"props":281,"children":283},{"className":282},[],[284],{"type":70,"value":285},"x86_64",{"type":70,"value":287},"\u002F",{"type":65,"tag":90,"props":289,"children":291},{"className":290},[],[292],{"type":70,"value":293},"aarch64",{"type":70,"value":295},", ",{"type":65,"tag":79,"props":297,"children":298},{},[299],{"type":70,"value":300},"macOS",{"type":65,"tag":90,"props":302,"children":304},{"className":303},[],[305],{"type":70,"value":306},"arm64",{"type":70,"value":308}," (Apple silicon). If it's Windows, or Intel macOS, ",{"type":65,"tag":79,"props":310,"children":311},{},[312],{"type":70,"value":313},"stop",{"type":70,"value":315},": there is no\npublished build — tell the user plainly.",{"type":65,"tag":254,"props":317,"children":318},{},[319,325,327,333],{"type":65,"tag":90,"props":320,"children":322},{"className":321},[],[323],{"type":70,"value":324},"command -v curl",{"type":70,"value":326}," (or ",{"type":65,"tag":90,"props":328,"children":330},{"className":329},[],[331],{"type":70,"value":332},"wget",{"type":70,"value":334},"). If neither, stop and say so.",{"type":65,"tag":254,"props":336,"children":337},{},[338,344],{"type":65,"tag":90,"props":339,"children":341},{"className":340},[],[342],{"type":70,"value":343},"command -v mfw",{"type":70,"value":345}," — if already installed, this is an idempotent re-run \u002F upgrade;\ncarry on (fixup self-heals).",{"type":65,"tag":149,"props":347,"children":349},{"id":348},"step-2-inspect-the-shell-config-before-installing",[350],{"type":70,"value":351},"Step 2 — Inspect the shell config BEFORE installing",{"type":65,"tag":73,"props":353,"children":354},{},[355],{"type":70,"value":356},"Run the inspector and parse it (do not dump it on the user):",{"type":65,"tag":358,"props":359,"children":363},"pre",{"className":360,"code":362,"language":70},[361],"language-text","sh ${CLAUDE_SKILL_DIR}\u002Fscripts\u002Finspect-shell-config.sh\n",[364],{"type":65,"tag":90,"props":365,"children":367},{"__ignoreMap":366},"",[368],{"type":70,"value":362},{"type":65,"tag":73,"props":370,"children":371},{},[372,374,380,382,388,390,396,398,404,406,412,414,419],{"type":70,"value":373},"For the user's ",{"type":65,"tag":90,"props":375,"children":377},{"className":376},[],[378],{"type":70,"value":379},"login_shell",{"type":70,"value":381},", look at its rc file(s): zsh → ",{"type":65,"tag":90,"props":383,"children":385},{"className":384},[],[386],{"type":70,"value":387},"~\u002F.zshrc",{"type":70,"value":389},"; bash →\n",{"type":65,"tag":90,"props":391,"children":393},{"className":392},[],[394],{"type":70,"value":395},"~\u002F.bashrc",{"type":70,"value":397}," plus ",{"type":65,"tag":90,"props":399,"children":401},{"className":400},[],[402],{"type":70,"value":403},"~\u002F.bash_profile",{"type":70,"value":405}," or ",{"type":65,"tag":90,"props":407,"children":409},{"className":408},[],[410],{"type":70,"value":411},"~\u002F.profile",{"type":70,"value":413},". Decide ",{"type":65,"tag":79,"props":415,"children":416},{},[417],{"type":70,"value":418},"managed vs plain",{"type":70,"value":420},":",{"type":65,"tag":422,"props":423,"children":424},"ul",{},[425,494],{"type":65,"tag":254,"props":426,"children":427},{},[428,433,435,441,443,449,451,457,458,464,465,471,472,478,480,485,486,492],{"type":65,"tag":79,"props":429,"children":430},{},[431],{"type":70,"value":432},"Managed",{"type":70,"value":434}," = ",{"type":65,"tag":90,"props":436,"children":438},{"className":437},[],[439],{"type":70,"value":440},"symlink=yes",{"type":70,"value":442}," (any ",{"type":65,"tag":90,"props":444,"children":446},{"className":445},[],[447],{"type":70,"value":448},"class",{"type":70,"value":450},": ",{"type":65,"tag":90,"props":452,"children":454},{"className":453},[],[455],{"type":70,"value":456},"nix",{"type":70,"value":295},{"type":65,"tag":90,"props":459,"children":461},{"className":460},[],[462],{"type":70,"value":463},"chezmoi",{"type":70,"value":295},{"type":65,"tag":90,"props":466,"children":468},{"className":467},[],[469],{"type":70,"value":470},"git-dotfiles",{"type":70,"value":227},{"type":65,"tag":90,"props":473,"children":475},{"className":474},[],[476],{"type":70,"value":477},"unknown",{"type":70,"value":479},") ",{"type":65,"tag":79,"props":481,"children":482},{},[483],{"type":70,"value":484},"or",{"type":70,"value":279},{"type":65,"tag":90,"props":487,"children":489},{"className":488},[],[490],{"type":70,"value":491},"class=nix-generated",{"type":70,"value":493}," (a real file with a \"Generated by Home\nManager\u002FNix\" header). These are owned by a tool; editing the deployed file is\nwrong — it's read-only (nix) or gets reverted on the next rebuild\u002Fapply.",{"type":65,"tag":254,"props":495,"children":496},{},[497,502],{"type":65,"tag":79,"props":498,"children":499},{},[500],{"type":70,"value":501},"Plain",{"type":70,"value":503}," = a regular, writable file (or absent). Safe to edit directly.",{"type":65,"tag":505,"props":506,"children":507},"blockquote",{},[508],{"type":65,"tag":73,"props":509,"children":510},{},[511,516,517,522,524,530,532,537,539,545],{"type":65,"tag":79,"props":512,"children":513},{},[514],{"type":70,"value":515},"Why this gate exists:",{"type":70,"value":279},{"type":65,"tag":90,"props":518,"children":520},{"className":519},[],[521],{"type":70,"value":173},{"type":70,"value":523}," writes its one-line hook with an atomic\n",{"type":65,"tag":90,"props":525,"children":527},{"className":526},[],[528],{"type":70,"value":529},"rename()",{"type":70,"value":531}," over the rc file, which ",{"type":65,"tag":79,"props":533,"children":534},{},[535],{"type":70,"value":536},"replaces a symlink with a regular file",{"type":70,"value":538}," —\nclobbering a nix\u002Fhome-manager-managed rc. So managed rc files must never be\nedited in place; mfw's one-line hook goes into the user's ",{"type":65,"tag":540,"props":541,"children":542},"em",{},[543],{"type":70,"value":544},"source-of-truth",{"type":70,"value":546},"\ninstead.",{"type":65,"tag":73,"props":548,"children":549},{},[550],{"type":70,"value":551},"Remember the result; it decides Step 3 and Step 4.",{"type":65,"tag":149,"props":553,"children":555},{"id":554},"step-3-install",[556],{"type":70,"value":557},"Step 3 — Install",{"type":65,"tag":73,"props":559,"children":560},{},[561,566,568,573],{"type":65,"tag":79,"props":562,"children":563},{},[564],{"type":70,"value":565},"If the shell config is PLAIN",{"type":70,"value":567}," (and you don't otherwise need the managed path),\nuse the standard installer — it downloads, verifies, and runs ",{"type":65,"tag":90,"props":569,"children":571},{"className":570},[],[572],{"type":70,"value":173},{"type":70,"value":574},", correctly\nediting the real rc file:",{"type":65,"tag":358,"props":576,"children":579},{"className":577,"code":578,"language":70},[361],"curl -fsSL https:\u002F\u002Fsemgrep.dev\u002Fdist\u002Fmfw\u002Finstall.sh | sh\n",[580],{"type":65,"tag":90,"props":581,"children":582},{"__ignoreMap":366},[583],{"type":70,"value":578},{"type":65,"tag":73,"props":585,"children":586},{},[587,589,594,596,602],{"type":70,"value":588},"(Swap the host if ",{"type":65,"tag":90,"props":590,"children":592},{"className":591},[],[593],{"type":70,"value":95},{"type":70,"value":595},"\u002Fenv gave an override: ",{"type":65,"tag":90,"props":597,"children":599},{"className":598},[],[600],{"type":70,"value":601},"…\u002F\u003Chost>\u002Fdist\u002Fmfw\u002Finstall.sh",{"type":70,"value":603},".)",{"type":65,"tag":73,"props":605,"children":606},{},[607,613,615,621,623,629,631,636,638,644],{"type":65,"tag":90,"props":608,"children":610},{"className":609},[],[611],{"type":70,"value":612},"install.sh",{"type":70,"value":614}," reconnects a TTY (",{"type":65,"tag":90,"props":616,"children":618},{"className":617},[],[619],{"type":70,"value":620},"mfw fixup \u003C\u002Fdev\u002Ftty",{"type":70,"value":622},") so a human running it in a\nterminal gets the interactive prompts, and falls back to ",{"type":65,"tag":90,"props":624,"children":626},{"className":625},[],[627],{"type":70,"value":628},"mfw fixup --yes",{"type":70,"value":630}," when\nthere's no controlling terminal. When ",{"type":65,"tag":540,"props":632,"children":633},{},[634],{"type":70,"value":635},"you",{"type":70,"value":637}," run this line through the Bash tool\nthere's no TTY, so it takes the ",{"type":65,"tag":90,"props":639,"children":641},{"className":640},[],[642],{"type":70,"value":643},"--yes",{"type":70,"value":645}," path: fixup auto-accepts and edits the\nreal rc file at mfw's best-guess paths — exactly what we want for a plain config.",{"type":65,"tag":73,"props":647,"children":648},{},[649,654,656,661],{"type":65,"tag":79,"props":650,"children":651},{},[652],{"type":70,"value":653},"If the shell config is MANAGED",{"type":70,"value":655},", do ",{"type":65,"tag":79,"props":657,"children":658},{},[659],{"type":70,"value":660},"not",{"type":70,"value":662}," run the bundled fixup (it would\nclobber the symlink). Install the binary only, then drive fixup with shell edits\nturned off:",{"type":65,"tag":358,"props":664,"children":667},{"className":665,"code":666,"language":70},[361],"sh ${CLAUDE_SKILL_DIR}\u002Fscripts\u002Finstall-binary.sh\n~\u002F.local\u002Fbin\u002Fmfw fixup --skip-login\n",[668],{"type":65,"tag":90,"props":669,"children":670},{"__ignoreMap":366},[671],{"type":70,"value":666},{"type":65,"tag":73,"props":673,"children":674},{},[675,680,682,687,689,694,696,702],{"type":65,"tag":90,"props":676,"children":678},{"className":677},[],[679],{"type":70,"value":173},{"type":70,"value":681}," here runs non-interactively (no TTY), so it writes\n",{"type":65,"tag":90,"props":683,"children":685},{"className":684},[],[686],{"type":70,"value":203},{"type":70,"value":688},", installs certs\u002Fshims\u002Fdaemon, and ",{"type":65,"tag":79,"props":690,"children":691},{},[692],{"type":70,"value":693},"prints",{"type":70,"value":695}," the\nshell lines instead of editing your rc — exactly what we want. We handle login in\nStep 6 and the shell hook in Step 4. (Pass an override URL with\n",{"type":65,"tag":90,"props":697,"children":699},{"className":698},[],[700],{"type":70,"value":701},"--backend-url \u003Curl>",{"type":70,"value":703}," if one was given.)",{"type":65,"tag":73,"props":705,"children":706},{},[707,709,714,716,722],{"type":70,"value":708},"Use ",{"type":65,"tag":90,"props":710,"children":712},{"className":711},[],[713],{"type":70,"value":165},{"type":70,"value":715}," for subsequent calls in case ",{"type":65,"tag":90,"props":717,"children":719},{"className":718},[],[720],{"type":70,"value":721},"~\u002F.local\u002Fbin",{"type":70,"value":723}," isn't on PATH\nin this session yet.",{"type":65,"tag":149,"props":725,"children":727},{"id":726},"step-4-shell-integration-for-managed-configs",[728],{"type":70,"value":729},"Step 4 — Shell integration for managed configs",{"type":65,"tag":73,"props":731,"children":732},{},[733],{"type":70,"value":734},"Skip this whole step for plain configs (the installer already did it). For managed\nconfigs, the only thing the user's shell needs is this exact hook, which sources\nmfw's self-managed env file:",{"type":65,"tag":358,"props":736,"children":739},{"className":737,"code":738,"language":70},[361],"[ -r \"$HOME\u002F.semgrep\u002Fmfw\u002Frc-setup.sh\" ] && . \"$HOME\u002F.semgrep\u002Fmfw\u002Frc-setup.sh\"\n",[740],{"type":65,"tag":90,"props":741,"children":742},{"__ignoreMap":366},[743],{"type":70,"value":738},{"type":65,"tag":73,"props":745,"children":746},{},[747,749,755,757,762,764,769,771,777],{"type":70,"value":748},"This single line is exactly what ",{"type":65,"tag":90,"props":750,"children":752},{"className":751},[],[753],{"type":70,"value":754},"mfw doctor",{"type":70,"value":756}," looks for (a trimmed line match — no\ncomment markers). Now find where it belongs and ",{"type":65,"tag":79,"props":758,"children":759},{},[760],{"type":70,"value":761},"ask the user",{"type":70,"value":763}," with ",{"type":65,"tag":90,"props":765,"children":767},{"className":766},[],[768],{"type":70,"value":39},{"type":70,"value":770},",\noffering the ",{"type":65,"tag":90,"props":772,"children":774},{"className":773},[],[775],{"type":70,"value":776},"candidate=",{"type":70,"value":778}," paths the inspector found plus an \"Other\" path:",{"type":65,"tag":422,"props":780,"children":781},{},[782,908,962,987],{"type":65,"tag":254,"props":783,"children":784},{},[785,790,792,798,799,805,807,813,815,821,822,828,829,835,837,843,845,851,853,859,861,867,869,875,877,883,885,891,893,899,900,906],{"type":65,"tag":79,"props":786,"children":787},{},[788],{"type":70,"value":789},"nix \u002F home-manager",{"type":70,"value":791}," (",{"type":65,"tag":90,"props":793,"children":795},{"className":794},[],[796],{"type":70,"value":797},"class=nix",{"type":70,"value":405},{"type":65,"tag":90,"props":800,"children":802},{"className":801},[],[803],{"type":70,"value":804},"nix-generated",{"type":70,"value":806},"): add the hook to the\nshell-init attribute, e.g. ",{"type":65,"tag":90,"props":808,"children":810},{"className":809},[],[811],{"type":70,"value":812},"programs.zsh.initContent",{"type":70,"value":814}," (newer) or\n",{"type":65,"tag":90,"props":816,"children":818},{"className":817},[],[819],{"type":70,"value":820},"initExtra",{"type":70,"value":287},{"type":65,"tag":90,"props":823,"children":825},{"className":824},[],[826],{"type":70,"value":827},"programs.bash.initExtra",{"type":70,"value":287},{"type":65,"tag":90,"props":830,"children":832},{"className":831},[],[833],{"type":70,"value":834},"bashrcExtra",{"type":70,"value":836},"; on NixOS\n",{"type":65,"tag":90,"props":838,"children":840},{"className":839},[],[841],{"type":70,"value":842},"programs.zsh.interactiveShellInit",{"type":70,"value":844},". If they instead manage the file wholesale\n(",{"type":65,"tag":90,"props":846,"children":848},{"className":847},[],[849],{"type":70,"value":850},"home.file.\".zshrc\".text = ''…''",{"type":70,"value":852},"), append the hook inside that string. A bare\n",{"type":65,"tag":90,"props":854,"children":856},{"className":855},[],[857],{"type":70,"value":858},"$HOME",{"type":70,"value":860}," is literal in nix strings (interpolation is ",{"type":65,"tag":90,"props":862,"children":864},{"className":863},[],[865],{"type":70,"value":866},"${…}",{"type":70,"value":868},"), so the line is safe\nverbatim; if you're inside a ",{"type":65,"tag":90,"props":870,"children":872},{"className":871},[],[873],{"type":70,"value":874},"''…''",{"type":70,"value":876}," block and the linter complains about ",{"type":65,"tag":90,"props":878,"children":880},{"className":879},[],[881],{"type":70,"value":882},"${",{"type":70,"value":884},",\nthere is none here, so no escaping is needed. After editing, tell the user to\nrebuild: ",{"type":65,"tag":90,"props":886,"children":888},{"className":887},[],[889],{"type":70,"value":890},"home-manager switch",{"type":70,"value":892}," \u002F ",{"type":65,"tag":90,"props":894,"children":896},{"className":895},[],[897],{"type":70,"value":898},"darwin-rebuild switch",{"type":70,"value":892},{"type":65,"tag":90,"props":901,"children":903},{"className":902},[],[904],{"type":70,"value":905},"sudo nixos-rebuild switch",{"type":70,"value":907},".",{"type":65,"tag":254,"props":909,"children":910},{},[911,915,916,922,924,929,931,937,939,945,947,953,955,961],{"type":65,"tag":79,"props":912,"children":913},{},[914],{"type":70,"value":463},{"type":70,"value":791},{"type":65,"tag":90,"props":917,"children":919},{"className":918},[],[920],{"type":70,"value":921},"class=chezmoi",{"type":70,"value":923},"): edit the ",{"type":65,"tag":540,"props":925,"children":926},{},[927],{"type":70,"value":928},"source",{"type":70,"value":930},", not the deployed file —\n",{"type":65,"tag":90,"props":932,"children":934},{"className":933},[],[935],{"type":70,"value":936},"chezmoi edit ~\u002F.zshrc",{"type":70,"value":938}," opens it, or edit the matching ",{"type":65,"tag":90,"props":940,"children":942},{"className":941},[],[943],{"type":70,"value":944},"dot_zshrc",{"type":70,"value":946}," in\n",{"type":65,"tag":90,"props":948,"children":950},{"className":949},[],[951],{"type":70,"value":952},"~\u002F.local\u002Fshare\u002Fchezmoi",{"type":70,"value":954},"; append the hook, then ",{"type":65,"tag":90,"props":956,"children":958},{"className":957},[],[959],{"type":70,"value":960},"chezmoi apply",{"type":70,"value":907},{"type":65,"tag":254,"props":963,"children":964},{},[965,970,971,977,979,985],{"type":65,"tag":79,"props":966,"children":967},{},[968],{"type":70,"value":969},"GNU stow \u002F dotfiles git repo",{"type":70,"value":791},{"type":65,"tag":90,"props":972,"children":974},{"className":973},[],[975],{"type":70,"value":976},"class=git-dotfiles",{"type":70,"value":978},"): the ",{"type":65,"tag":90,"props":980,"children":982},{"className":981},[],[983],{"type":70,"value":984},"resolved=",{"type":70,"value":986}," path IS\nthe real file in the repo (the symlink points straight at it). Append the hook\nthere with Edit, then remind the user to commit. No relink needed.",{"type":65,"tag":254,"props":988,"children":989},{},[990,994,996,1002,1003,1009],{"type":65,"tag":79,"props":991,"children":992},{},[993],{"type":70,"value":477},{"type":70,"value":995},": show the ",{"type":65,"tag":90,"props":997,"children":999},{"className":998},[],[1000],{"type":70,"value":1001},"link_target",{"type":70,"value":287},{"type":65,"tag":90,"props":1004,"children":1006},{"className":1005},[],[1007],{"type":70,"value":1008},"resolved",{"type":70,"value":1010}," path, ask the user where the\nsource-of-truth is, and edit that.",{"type":65,"tag":73,"props":1012,"children":1013},{},[1014,1016,1021],{"type":70,"value":1015},"Read the target file first, then make a ",{"type":65,"tag":79,"props":1017,"children":1018},{},[1019],{"type":70,"value":1020},"minimal",{"type":70,"value":1022}," Edit that inserts the hook in\nthe right place (inside the right nix attribute \u002F at the end of the rc source).\nConfirm the destination with the user before writing if there's any ambiguity.",{"type":65,"tag":149,"props":1024,"children":1026},{"id":1025},"step-5-finish-the-trust-store",[1027],{"type":70,"value":1028},"Step 5 — Finish the trust store",{"type":65,"tag":422,"props":1030,"children":1031},{},[1032,1064],{"type":65,"tag":254,"props":1033,"children":1034},{},[1035,1040,1042,1047,1049,1054,1056,1062],{"type":65,"tag":79,"props":1036,"children":1037},{},[1038],{"type":70,"value":1039},"Linux:",{"type":70,"value":1041}," the per-user pass usually can't establish trust (no per-user store).\nAsk with ",{"type":65,"tag":90,"props":1043,"children":1045},{"className":1044},[],[1046],{"type":70,"value":39},{"type":70,"value":1048}," whether to install the CA into the ",{"type":65,"tag":79,"props":1050,"children":1051},{},[1052],{"type":70,"value":1053},"system",{"type":70,"value":1055}," store\n(needs sudo): ",{"type":65,"tag":90,"props":1057,"children":1059},{"className":1058},[],[1060],{"type":70,"value":1061},"sudo mfw install-certs --store system",{"type":70,"value":1063},". If they decline, note that\ngated downloads will fail TLS verification until it's trusted.",{"type":65,"tag":254,"props":1065,"children":1066},{},[1067,1072,1074,1080],{"type":65,"tag":79,"props":1068,"children":1069},{},[1070],{"type":70,"value":1071},"macOS:",{"type":70,"value":1073}," adding the CA to the login keychain can pop a GUI \"allow\" \u002F password\nprompt that you can't click. If the certs step didn't complete, tell the user to\nrun ",{"type":65,"tag":90,"props":1075,"children":1077},{"className":1076},[],[1078],{"type":70,"value":1079},"mfw install-certs",{"type":70,"value":1081}," themselves and approve the prompt. (Homebrew's openssl\ntrust is handled by fixup automatically when brew is present.)",{"type":65,"tag":149,"props":1083,"children":1085},{"id":1084},"step-6-login-optional-browser",[1086],{"type":70,"value":1087},"Step 6 — Login (optional, browser)",{"type":65,"tag":73,"props":1089,"children":1090},{},[1091,1093,1098,1100,1106,1108,1113,1115,1121,1123,1129],{"type":70,"value":1092},"mfw runs without login — unauthenticated requests just follow the configured\nfail-open\u002Fclosed policy — but it can't actually scan until authenticated. Check\nthe login line in ",{"type":65,"tag":90,"props":1094,"children":1096},{"className":1095},[],[1097],{"type":70,"value":754},{"type":70,"value":1099}," (Step 7). If not authenticated, ask whether to log\nin now. ",{"type":65,"tag":90,"props":1101,"children":1103},{"className":1102},[],[1104],{"type":70,"value":1105},"mfw login",{"type":70,"value":1107}," opens a browser OAuth flow you can't complete for them, so\nhave ",{"type":65,"tag":79,"props":1109,"children":1110},{},[1111],{"type":70,"value":1112},"them",{"type":70,"value":1114}," run it in this session: suggest they type ",{"type":65,"tag":90,"props":1116,"children":1118},{"className":1117},[],[1119],{"type":70,"value":1120},"! mfw login",{"type":70,"value":1122}," (or set\n",{"type":65,"tag":90,"props":1124,"children":1126},{"className":1125},[],[1127],{"type":70,"value":1128},"SEMGREP_APP_TOKEN",{"type":70,"value":1130},"). Don't block the rest of fixup on it.",{"type":65,"tag":149,"props":1132,"children":1134},{"id":1133},"step-7-verify-and-hand-off",[1135],{"type":70,"value":1136},"Step 7 — Verify and hand off",{"type":65,"tag":250,"props":1138,"children":1139},{},[1140,1182,1231],{"type":65,"tag":254,"props":1141,"children":1142},{},[1143,1145,1150,1152,1158,1160,1165,1167,1173,1174,1180],{"type":70,"value":1144},"Run ",{"type":65,"tag":90,"props":1146,"children":1148},{"className":1147},[],[1149],{"type":70,"value":754},{"type":70,"value":1151}," (use ",{"type":65,"tag":90,"props":1153,"children":1155},{"className":1154},[],[1156],{"type":70,"value":1157},"~\u002F.local\u002Fbin\u002Fmfw doctor",{"type":70,"value":1159}," if needed). Walk the user\nthrough anything still ✗. For managed configs the shell line stays ✗ until they\nrestart their shell (and, for nix, rebuild first). Doctor also prints a few\n",{"type":65,"tag":79,"props":1161,"children":1162},{},[1163],{"type":70,"value":1164},"informational",{"type":70,"value":1166}," lines that aren't failures: a version\u002Fupdate check\n(",{"type":65,"tag":90,"props":1168,"children":1170},{"className":1169},[],[1171],{"type":70,"value":1172},"up to date",{"type":70,"value":892},{"type":65,"tag":90,"props":1175,"children":1177},{"className":1176},[],[1178],{"type":70,"value":1179},"update available … run mfw upgrade",{"type":70,"value":1181},"), whether auto-update is\ndisabled, and whether the supervisor is running — don't treat those as ✗.",{"type":65,"tag":254,"props":1183,"children":1184},{},[1185,1187,1192,1194,1200,1202,1207,1209,1215,1217,1222,1224,1229],{"type":70,"value":1186},"Tell them to ",{"type":65,"tag":79,"props":1188,"children":1189},{},[1190],{"type":70,"value":1191},"restart their shell",{"type":70,"value":1193}," — ",{"type":65,"tag":90,"props":1195,"children":1197},{"className":1196},[],[1198],{"type":70,"value":1199},"exec \"$SHELL\" -l",{"type":70,"value":1201}," or a new terminal —\nthen re-run ",{"type":65,"tag":90,"props":1203,"children":1205},{"className":1204},[],[1206],{"type":70,"value":754},{"type":70,"value":1208},"; it should print the \"Semgrep mfw is protecting this\nmachine.\" banner (a green ",{"type":65,"tag":90,"props":1210,"children":1212},{"className":1211},[],[1213],{"type":70,"value":1214},"○○○",{"type":70,"value":1216}," logo + a little watching face whose eyes are\nrandomized each run). If\nthey're not logged in the headline is instead \"mfw can't scan anything until\nyou authenticate — run ",{"type":65,"tag":90,"props":1218,"children":1220},{"className":1219},[],[1221],{"type":70,"value":1105},{"type":70,"value":1223},"\" (see Step 6); other steps can still be ✓.\nIf they're signed in but their Semgrep deployment doesn't have the Semgrep\nmalware firewall enabled, the login line is ✗ and the headline is \"the Semgrep\nmalware firewall isn't enabled for your Semgrep deployment. Enable it in Semgrep\nor ask your org admin.\" — that's a backend entitlement issue, not a fixup step,\nso re-running ",{"type":65,"tag":90,"props":1225,"children":1227},{"className":1226},[],[1228],{"type":70,"value":173},{"type":70,"value":1230}," won't fix it.",{"type":65,"tag":254,"props":1232,"children":1233},{},[1234,1236,1242,1244,1249,1251,1257,1259,1265],{"type":70,"value":1235},"Summarize what you did, where things live (",{"type":65,"tag":90,"props":1237,"children":1239},{"className":1238},[],[1240],{"type":70,"value":1241},"~\u002F.semgrep\u002Fmfw\u002F",{"type":70,"value":1243},", shims on PATH,\nthe managed daemon), and that ",{"type":65,"tag":90,"props":1245,"children":1247},{"className":1246},[],[1248],{"type":70,"value":240},{"type":70,"value":1250}," reverses everything (and deletes\nthe mfw binary). mfw keeps\nitself updated via the supervisor (auto-update on by default); ",{"type":65,"tag":90,"props":1252,"children":1254},{"className":1253},[],[1255],{"type":70,"value":1256},"mfw upgrade",{"type":70,"value":1258},"\nforces it now and ",{"type":65,"tag":90,"props":1260,"children":1262},{"className":1261},[],[1263],{"type":70,"value":1264},"mfw restart",{"type":70,"value":1266}," bounces the daemon.",{"type":65,"tag":149,"props":1268,"children":1270},{"id":1269},"notes",[1271],{"type":70,"value":1272},"Notes",{"type":65,"tag":422,"props":1274,"children":1275},{},[1276,1289,1358,1363],{"type":65,"tag":254,"props":1277,"children":1278},{},[1279,1281,1287],{"type":70,"value":1280},"Prefer the pre-approved commands above so the user isn't re-prompted. The\n",{"type":65,"tag":90,"props":1282,"children":1284},{"className":1283},[],[1285],{"type":70,"value":1286},"curl … | install.sh | sh",{"type":70,"value":1288}," line modifies the system — it's expected to need one\nconfirmation; let it.",{"type":65,"tag":254,"props":1290,"children":1291},{},[1292,1297,1299,1305,1307,1313,1315,1320,1322,1328,1330,1336,1338,1343,1345,1351,1352,1356],{"type":65,"tag":79,"props":1293,"children":1294},{},[1295],{"type":70,"value":1296},"mfw's own rc-edit prompt",{"type":70,"value":1298}," (only shown with a TTY — not when you drive it via\nthe Bash tool): for the shell step it batches into one question,\n",{"type":65,"tag":90,"props":1300,"children":1302},{"className":1301},[],[1303],{"type":70,"value":1304},"Edit them all? [Y]es \u002F [n]o, show me the line to add myself \u002F [s]kip",{"type":70,"value":1306},", and\nper-file it's ",{"type":65,"tag":90,"props":1308,"children":1310},{"className":1309},[],[1311],{"type":70,"value":1312},"Apply to \u003Cpath>? [Y]es \u002F [n]o, I'll do it myself \u002F [s]kip",{"type":70,"value":1314},". The\ndefault is ",{"type":65,"tag":79,"props":1316,"children":1317},{},[1318],{"type":70,"value":1319},"yes",{"type":70,"value":1321}," (Enter applies the edit); ",{"type":65,"tag":90,"props":1323,"children":1325},{"className":1324},[],[1326],{"type":70,"value":1327},"n",{"type":70,"value":1329}," immediately prints the source\nline to paste yourself, ",{"type":65,"tag":90,"props":1331,"children":1333},{"className":1332},[],[1334],{"type":70,"value":1335},"s",{"type":70,"value":1337}," skips.\nBecause your Bash-tool calls have no TTY, ",{"type":65,"tag":90,"props":1339,"children":1341},{"className":1340},[],[1342],{"type":70,"value":173},{"type":70,"value":1344}," runs non-interactively: it\nstill writes ",{"type":65,"tag":90,"props":1346,"children":1348},{"className":1347},[],[1349],{"type":70,"value":1350},"rc-setup.sh",{"type":70,"value":688},{"type":65,"tag":540,"props":1353,"children":1354},{},[1355],{"type":70,"value":693},{"type":70,"value":1357}," (never\nedits) the rc lines — which is exactly why the managed-config path in Step 3 works.",{"type":65,"tag":254,"props":1359,"children":1360},{},[1361],{"type":70,"value":1362},"Never put secrets\u002Ftokens in anything you write. The hook only sources a file.",{"type":65,"tag":254,"props":1364,"children":1365},{},[1366],{"type":70,"value":1367},"If a step fails, report the actual error and what it means for protection\n(e.g. \"certs not trusted → gated downloads fail TLS\"); don't paper over it.",{"items":1369,"total":1377},[1370],{"slug":4,"name":4,"fn":5,"description":6,"org":1371,"tags":1372,"stars":25,"repoUrl":26,"updatedAt":27},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1373,1374,1375,1376],{"name":20,"slug":21,"type":15},{"name":23,"slug":24,"type":15},{"name":17,"slug":18,"type":15},{"name":13,"slug":14,"type":15},1,{"items":1379,"total":29},[1380,1396,1411,1425,1432],{"slug":1381,"name":1381,"fn":1382,"description":1383,"org":1384,"tags":1385,"stars":1393,"repoUrl":1394,"updatedAt":1395},"code-security","write and review secure code","Security guidelines for writing secure code. Use when writing code, reviewing code for vulnerabilities, or asking about secure coding practices like 'check for SQL injection' or 'review security'. IMPORTANT: Always consult this skill when writing or reviewing any code that handles user input, authentication, file operations, database queries, network requests, cryptography, or infrastructure configuration (Terraform, Kubernetes, Docker, GitHub Actions) — even if the user doesn't explicitly mention security. Also use when users ask to 'review my code', 'check this for bugs', or 'is this safe'.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1386,1389,1392],{"name":1387,"slug":1388,"type":15},"Code Review","code-review",{"name":1390,"slug":1391,"type":15},"Compliance","compliance",{"name":13,"slug":14,"type":15},257,"https:\u002F\u002Fgithub.com\u002Fsemgrep\u002Fskills","2026-04-06T18:52:52.030224",{"slug":1397,"name":1397,"fn":1398,"description":1399,"org":1400,"tags":1401,"stars":1393,"repoUrl":1394,"updatedAt":1410},"llm-security","apply LLM security guidelines","Security guidelines for LLM applications based on OWASP Top 10 for LLM 2025. Use when building LLM apps, reviewing AI security, implementing RAG systems, or asking about LLM vulnerabilities like 'prompt injection' or 'check LLM security'. IMPORTANT: Always consult this skill when building chatbots, AI agents, RAG pipelines, tool-using LLMs, agentic systems, or any application that calls an LLM API (OpenAI, Anthropic, Gemini, etc.) — even if the user doesn't explicitly mention security. Also use when users import 'openai', 'anthropic', 'langchain', 'llamaindex', or similar LLM libraries.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1402,1403,1406,1409],{"name":1390,"slug":1391,"type":15},{"name":1404,"slug":1405,"type":15},"LLM","llm",{"name":1407,"slug":1408,"type":15},"Risk Assessment","risk-assessment",{"name":13,"slug":14,"type":15},"2026-04-06T18:52:50.687939",{"slug":8,"name":8,"fn":1412,"description":1413,"org":1414,"tags":1415,"stars":1393,"repoUrl":1394,"updatedAt":1424},"run Semgrep scans and create rules","Run Semgrep static analysis scans and create custom detection rules. Use when asked to scan code with Semgrep, find security vulnerabilities, write custom YAML rules, or detect specific bug patterns. IMPORTANT: Also use this skill when users ask to 'scan for bugs', 'check code quality', 'find vulnerabilities', 'static analysis', 'lint for security', 'audit this code', or want to enforce coding standards — even if they don't mention Semgrep by name. Semgrep is the right tool for pattern-based code scanning across 30+ languages.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1416,1419,1420,1421],{"name":1417,"slug":1418,"type":15},"Code Analysis","code-analysis",{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"name":1422,"slug":1423,"type":15},"Static Analysis","static-analysis","2026-04-06T18:52:49.360762",{"slug":4,"name":4,"fn":5,"description":6,"org":1426,"tags":1427,"stars":25,"repoUrl":26,"updatedAt":27},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1428,1429,1430,1431],{"name":20,"slug":21,"type":15},{"name":23,"slug":24,"type":15},{"name":17,"slug":18,"type":15},{"name":13,"slug":14,"type":15},{"slug":1433,"name":1433,"fn":1434,"description":1435,"org":1436,"tags":1437,"stars":1377,"repoUrl":1443,"updatedAt":1444},"setup-semgrep-plugin","set up the Semgrep plugin","Set up the Semgrep plugin by installing Semgrep, authenticating, and verifying compatibility",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1438,1441,1442],{"name":1439,"slug":1440,"type":15},"Local Development","local-development",{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"https:\u002F\u002Fgithub.com\u002Fsemgrep\u002Fcursor-plugin","2026-04-06T18:52:53.29796"]