[{"data":1,"prerenderedAt":1191},["ShallowReactive",2],{"dev-setup":3},{"id":4,"title":5,"body":6,"description":1180,"extension":1181,"meta":1182,"navigation":1186,"path":1187,"seo":1188,"stem":1189,"__hash__":1190},"content\u002Fwriting\u002Fdev-setup.md","How I Set Up a Dev Machine from Scratch",{"type":7,"value":8,"toc":1164},"minimark",[9,18,21,24,27,32,35,52,55,65,111,114,116,120,140,143,176,179,181,185,188,193,225,231,235,305,319,334,338,389,400,407,411,448,461,470,474,477,507,574,580,586,589,633,639,645,651,655,658,665,684,691,701,708,718,725,728,735,750,769,779,781,785,810,872,874,878,881,948,956,992,999,1001,1005,1008,1050,1052,1056,1064,1071,1079,1082,1094,1101,1109,1112,1146,1149,1157,1160],[10,11,12,13,17],"p",{},"Every time I sit down in front of a new machine, I used to spend the first few hours doing the same tedious thing: installing tools one by one, copying config snippets from memory, setting up SSH keys, and wondering why ",[14,15,16],"code",{},"pnpm"," wasn't on the path.",[10,19,20],{},"I wrote a script to fix that. One run and the machine is ready to write TypeScript, Rust, Solidity, or Cairo.",[10,22,23],{},"Here's exactly what it does and why.",[25,26],"hr",{},[28,29,31],"h2",{"id":30},"before-you-start","Before You Start",[10,33,34],{},"You need two things before running:",[36,37,38,46],"ol",{},[39,40,41,45],"li",{},[42,43,44],"strong",{},"A terminal"," - on Linux open Terminal from your applications menu. On macOS open Terminal from Applications > Utilities.",[39,47,48,51],{},[42,49,50],{},"An internet connection"," - the script downloads tools and checks your GitHub SSH connection.",[10,53,54],{},"That's it. Everything else is handled for you.",[10,56,57,60,61,64],{},[42,58,59],{},"macOS users only:"," The default ",[14,62,63],{},"bash"," on macOS is version 3, which is too old. Install a newer one first:",[66,67,71],"pre",{"className":68,"code":69,"language":63,"meta":70,"style":70},"language-bash shiki shiki-themes github-light github-dark","\u002Fbin\u002Fbash -c \"$(curl -fsSL https:\u002F\u002Fraw.githubusercontent.com\u002FHomebrew\u002Finstall\u002FHEAD\u002Finstall.sh)\"\nbrew install bash\n","",[14,72,73,99],{"__ignoreMap":70},[74,75,78,82,86,90,93,96],"span",{"class":76,"line":77},"line",1,[74,79,81],{"class":80},"sScJk","\u002Fbin\u002Fbash",[74,83,85],{"class":84},"sj4cs"," -c",[74,87,89],{"class":88},"sZZnC"," \"$(",[74,91,92],{"class":80},"curl",[74,94,95],{"class":84}," -fsSL",[74,97,98],{"class":88}," https:\u002F\u002Fraw.githubusercontent.com\u002FHomebrew\u002Finstall\u002FHEAD\u002Finstall.sh)\"\n",[74,100,102,105,108],{"class":76,"line":101},2,[74,103,104],{"class":80},"brew",[74,106,107],{"class":88}," install",[74,109,110],{"class":88}," bash\n",[10,112,113],{},"Then close and reopen your terminal before running the setup script.",[25,115],{},[28,117,119],{"id":118},"how-to-run-it","How to Run It",[66,121,123],{"className":68,"code":122,"language":63,"meta":70,"style":70},"curl -fsSL https:\u002F\u002Fshogo-portfolio-ebon.vercel.app\u002Fscripts\u002Fdev-setup.sh | bash\n",[14,124,125],{"__ignoreMap":70},[74,126,127,129,131,134,138],{"class":76,"line":77},[74,128,92],{"class":80},[74,130,95],{"class":84},[74,132,133],{"class":88}," https:\u002F\u002Fshogo-portfolio-ebon.vercel.app\u002Fscripts\u002Fdev-setup.sh",[74,135,137],{"class":136},"szBVR"," |",[74,139,110],{"class":80},[10,141,142],{},"If you want to read the script before running it (recommended):",[66,144,146],{"className":68,"code":145,"language":63,"meta":70,"style":70},"curl -o dev-setup.sh https:\u002F\u002Fshogo-portfolio-ebon.vercel.app\u002Fscripts\u002Fdev-setup.sh\ncat dev-setup.sh\nbash dev-setup.sh\n",[14,147,148,161,169],{"__ignoreMap":70},[74,149,150,152,155,158],{"class":76,"line":77},[74,151,92],{"class":80},[74,153,154],{"class":84}," -o",[74,156,157],{"class":88}," dev-setup.sh",[74,159,160],{"class":88}," https:\u002F\u002Fshogo-portfolio-ebon.vercel.app\u002Fscripts\u002Fdev-setup.sh\n",[74,162,163,166],{"class":76,"line":101},[74,164,165],{"class":80},"cat",[74,167,168],{"class":88}," dev-setup.sh\n",[74,170,172,174],{"class":76,"line":171},3,[74,173,63],{"class":80},[74,175,168],{"class":88},[10,177,178],{},"The script will pause at the start of each phase and ask whether you want to run it or skip it. You stay in control the whole time. If you only need Git and nothing else, you can skip every other phase.",[25,180],{},[28,182,184],{"id":183},"what-the-script-installs","What the Script Installs",[10,186,187],{},"The script runs six phases in order.",[189,190,192],"h3",{"id":191},"phase-1-system-update-and-essentials","Phase 1 - System update and essentials",[10,194,195,196,199,200,203,204,206,207,206,210,213,214,217,218,199,221,224],{},"On Linux it runs ",[14,197,198],{},"apt-get update"," and ",[14,201,202],{},"apt-get upgrade",", then installs ",[14,205,92],{},", ",[14,208,209],{},"wget",[14,211,212],{},"git",", and ",[14,215,216],{},"build-essential",". On macOS it installs Homebrew first if it's missing, then does ",[14,219,220],{},"brew update",[14,222,223],{},"brew upgrade",".",[10,226,227,228,230],{},"This is the boring but necessary foundation. Nothing else works reliably without ",[14,229,216],{}," on Linux - it provides the C compiler that Rust, Node native modules, and several other tools require to compile.",[189,232,234],{"id":233},"phase-2-rust-via-rustup","Phase 2 - Rust via rustup",[66,236,238],{"className":68,"code":237,"language":63,"meta":70,"style":70},"curl --proto '=https' --tlsv1.2 -sSf https:\u002F\u002Fsh.rustup.rs | sh -s -- -y\nsource \"$HOME\u002F.cargo\u002Fenv\"\nrustup component add rustfmt clippy\n",[14,239,240,273,288],{"__ignoreMap":70},[74,241,242,244,247,250,253,256,259,261,264,267,270],{"class":76,"line":77},[74,243,92],{"class":80},[74,245,246],{"class":84}," --proto",[74,248,249],{"class":88}," '=https'",[74,251,252],{"class":84}," --tlsv1.2",[74,254,255],{"class":84}," -sSf",[74,257,258],{"class":88}," https:\u002F\u002Fsh.rustup.rs",[74,260,137],{"class":136},[74,262,263],{"class":80}," sh",[74,265,266],{"class":84}," -s",[74,268,269],{"class":84}," --",[74,271,272],{"class":84}," -y\n",[74,274,275,278,281,285],{"class":76,"line":101},[74,276,277],{"class":84},"source",[74,279,280],{"class":88}," \"",[74,282,284],{"class":283},"sVt8B","$HOME",[74,286,287],{"class":88},"\u002F.cargo\u002Fenv\"\n",[74,289,290,293,296,299,302],{"class":76,"line":171},[74,291,292],{"class":80},"rustup",[74,294,295],{"class":88}," component",[74,297,298],{"class":88}," add",[74,300,301],{"class":88}," rustfmt",[74,303,304],{"class":88}," clippy\n",[10,306,307,308,311,312,199,315,318],{},"I install Rust before Node because it takes longer and I want it done early. The ",[14,309,310],{},"-y"," flag skips the interactive prompt. After install, the script sources the Cargo env so ",[14,313,314],{},"rustc",[14,316,317],{},"cargo"," are immediately available in the same shell session without needing a restart.",[10,320,321,199,324,327,328,330,331,333],{},[14,322,323],{},"rustfmt",[14,325,326],{},"clippy"," are added immediately - ",[14,329,323],{}," formats your code, ",[14,332,326],{}," catches common mistakes and style issues. There's no reason to ever skip them.",[189,335,337],{"id":336},"phase-3-nodejs-24-via-nvm","Phase 3 - Node.js 24 via nvm",[66,339,341],{"className":68,"code":340,"language":63,"meta":70,"style":70},"curl -o- https:\u002F\u002Fraw.githubusercontent.com\u002Fnvm-sh\u002Fnvm\u002Fv0.40.4\u002Finstall.sh | bash\nnvm install 24\nnvm use 24\nnvm alias default 24\n",[14,342,343,357,367,376],{"__ignoreMap":70},[74,344,345,347,350,353,355],{"class":76,"line":77},[74,346,92],{"class":80},[74,348,349],{"class":84}," -o-",[74,351,352],{"class":88}," https:\u002F\u002Fraw.githubusercontent.com\u002Fnvm-sh\u002Fnvm\u002Fv0.40.4\u002Finstall.sh",[74,354,137],{"class":136},[74,356,110],{"class":80},[74,358,359,362,364],{"class":76,"line":101},[74,360,361],{"class":80},"nvm",[74,363,107],{"class":88},[74,365,366],{"class":84}," 24\n",[74,368,369,371,374],{"class":76,"line":171},[74,370,361],{"class":80},[74,372,373],{"class":88}," use",[74,375,366],{"class":84},[74,377,379,381,384,387],{"class":76,"line":378},4,[74,380,361],{"class":80},[74,382,383],{"class":88}," alias",[74,385,386],{"class":88}," default",[74,388,366],{"class":84},[10,390,391,392,395,396,399],{},"nvm (Node Version Manager) lets you install and switch between Node versions without needing ",[14,393,394],{},"sudo",". Node 24 is the current active LTS at the time of writing. Using ",[14,397,398],{},"alias default 24"," makes Node 24 the version that loads in every new terminal session automatically.",[10,401,402,403,406],{},"Why nvm instead of a system install? Because system Node requires ",[14,404,405],{},"sudo npm install -g",", which is a security risk and causes permissions headaches. With nvm, everything lives in your home directory.",[189,408,410],{"id":409},"phase-4-corepack-pnpm-and-yarn","Phase 4 - Corepack, pnpm, and yarn",[66,412,414],{"className":68,"code":413,"language":63,"meta":70,"style":70},"corepack enable\ncorepack prepare pnpm@latest --activate\ncorepack prepare yarn@stable --activate\n",[14,415,416,424,437],{"__ignoreMap":70},[74,417,418,421],{"class":76,"line":77},[74,419,420],{"class":80},"corepack",[74,422,423],{"class":88}," enable\n",[74,425,426,428,431,434],{"class":76,"line":101},[74,427,420],{"class":80},[74,429,430],{"class":88}," prepare",[74,432,433],{"class":88}," pnpm@latest",[74,435,436],{"class":84}," --activate\n",[74,438,439,441,443,446],{"class":76,"line":171},[74,440,420],{"class":80},[74,442,430],{"class":88},[74,444,445],{"class":88}," yarn@stable",[74,447,436],{"class":84},[10,449,450,451,454,455,199,457,460],{},"Corepack ships with Node 16+ and manages package manager versions without a global install. This is the correct way to set up pnpm now - not ",[14,452,453],{},"npm install -g pnpm",". After this phase, ",[14,456,16],{},[14,458,459],{},"yarn"," are both available and pinned to their latest stable versions.",[10,462,463,465,466,469],{},[14,464,16],{}," is faster and more disk-efficient than ",[14,467,468],{},"npm",". It stores packages once on your machine and hard-links them across projects, so you are not downloading the same dependency 30 times.",[189,471,473],{"id":472},"phase-5-git-identity-ssh-key-and-commit-signing","Phase 5 - Git identity, SSH key, and commit signing",[10,475,476],{},"This phase is the most interactive. The script prompts for your name and email, then:",[36,478,479,488,498,501,504],{},[39,480,481,482,199,485],{},"Configures ",[14,483,484],{},"git config --global user.name",[14,486,487],{},"git config --global user.email",[39,489,490,491,494,495],{},"Checks for an existing ",[14,492,493],{},"~\u002F.ssh\u002Fid_ed25519"," key - if none found, generates one with ",[14,496,497],{},"ssh-keygen -t ed25519",[39,499,500],{},"Prints the public key so you can paste it into GitHub",[39,502,503],{},"Waits for you to add the key before testing the connection",[39,505,506],{},"Configures SSH commit signing:",[66,508,510],{"className":68,"code":509,"language":63,"meta":70,"style":70},"git config --global gpg.format ssh\ngit config --global user.signingkey \"$PUB_FILE\"\ngit config --global commit.gpgsign true\ngit config --global tag.gpgsign true\n",[14,511,512,528,547,561],{"__ignoreMap":70},[74,513,514,516,519,522,525],{"class":76,"line":77},[74,515,212],{"class":80},[74,517,518],{"class":88}," config",[74,520,521],{"class":84}," --global",[74,523,524],{"class":88}," gpg.format",[74,526,527],{"class":88}," ssh\n",[74,529,530,532,534,536,539,541,544],{"class":76,"line":101},[74,531,212],{"class":80},[74,533,518],{"class":88},[74,535,521],{"class":84},[74,537,538],{"class":88}," user.signingkey",[74,540,280],{"class":88},[74,542,543],{"class":283},"$PUB_FILE",[74,545,546],{"class":88},"\"\n",[74,548,549,551,553,555,558],{"class":76,"line":171},[74,550,212],{"class":80},[74,552,518],{"class":88},[74,554,521],{"class":84},[74,556,557],{"class":88}," commit.gpgsign",[74,559,560],{"class":84}," true\n",[74,562,563,565,567,569,572],{"class":76,"line":378},[74,564,212],{"class":80},[74,566,518],{"class":88},[74,568,521],{"class":84},[74,570,571],{"class":88}," tag.gpgsign",[74,573,560],{"class":84},[10,575,576,579],{},[42,577,578],{},"What is a signing key?"," When you push a commit to GitHub, it shows \"Verified\" next to your commit if it's signed. This proves the commit actually came from you and wasn't tampered with. Commit signing with SSH keys is the modern approach - it uses the exact same key you already use for GitHub access, with no separate GPG setup required.",[10,581,582,585],{},[42,583,584],{},"What is an SSH key?"," It's a pair of files: a private key (which stays on your machine and is never shared) and a public key (which you upload to GitHub). When you push code, GitHub checks your public key to confirm you're allowed to access that repository. You never type a password.",[10,587,588],{},"The script also sets these critical git globals:",[66,590,592],{"className":68,"code":591,"language":63,"meta":70,"style":70},"git config --global pull.rebase true\ngit config --global rebase.autoStash true\ngit config --global fetch.prune true\n",[14,593,594,607,620],{"__ignoreMap":70},[74,595,596,598,600,602,605],{"class":76,"line":77},[74,597,212],{"class":80},[74,599,518],{"class":88},[74,601,521],{"class":84},[74,603,604],{"class":88}," pull.rebase",[74,606,560],{"class":84},[74,608,609,611,613,615,618],{"class":76,"line":101},[74,610,212],{"class":80},[74,612,518],{"class":88},[74,614,521],{"class":84},[74,616,617],{"class":88}," rebase.autoStash",[74,619,560],{"class":84},[74,621,622,624,626,628,631],{"class":76,"line":171},[74,623,212],{"class":80},[74,625,518],{"class":88},[74,627,521],{"class":84},[74,629,630],{"class":88}," fetch.prune",[74,632,560],{"class":84},[10,634,635,638],{},[14,636,637],{},"pull.rebase true"," - instead of creating a merge commit every time you pull, git replays your local commits on top of the remote. This keeps history linear and readable.",[10,640,641,644],{},[14,642,643],{},"rebase.autoStash true"," - if you have uncommitted changes when you pull, git automatically stashes them, does the rebase, then restores them. You never get blocked by a \"please commit or stash\" message.",[10,646,647,650],{},[14,648,649],{},"fetch.prune true"," - automatically removes local references to remote branches that have been deleted. Keeps your branch list clean.",[189,652,654],{"id":653},"phase-6-global-config-files","Phase 6 - Global config files",[10,656,657],{},"The script writes five config files to your home directory:",[10,659,660],{},[42,661,662],{},[14,663,664],{},"~\u002F.vscode\u002Fsettings.json",[10,666,667,668,206,671,206,674,206,677,206,680,683],{},"Format on save with Prettier, ESLint auto-fix on save, Rust analyzer with clippy, Solidity formatter, file exclusions for build output (",[14,669,670],{},"target\u002F",[14,672,673],{},"artifacts\u002F",[14,675,676],{},".next\u002F",[14,678,679],{},".nuxt\u002F",[14,681,682],{},".output\u002F","). This applies globally to every project you open in VS Code, so you never have to configure formatting per project again.",[10,685,686],{},[42,687,688],{},[14,689,690],{},"~\u002F.prettierrc",[10,692,693,694,697,698,224],{},"Single quotes, trailing commas, 100 char print width, ",[14,695,696],{},"prettier-plugin-solidity"," included. Applied globally as a fallback for any project that doesn't have its own ",[14,699,700],{},".prettierrc",[10,702,703],{},[42,704,705],{},[14,706,707],{},"~\u002F.solhint.json",[10,709,710,713,714,717],{},[14,711,712],{},"solhint:recommended"," ruleset with warnings on long lines and missing reason strings in ",[14,715,716],{},"require"," calls. This runs automatically on Solidity files through the lint-staged config.",[10,719,720],{},[42,721,722],{},[14,723,724],{},"~\u002F.lintstagedrc.json",[10,726,727],{},"Runs Prettier on all JS\u002FTS\u002FJSON\u002FCSS\u002FMD files before every commit. Runs both Prettier and Solhint on Solidity files. This means your code is always formatted before it reaches the remote.",[10,729,730],{},[42,731,732],{},[14,733,734],{},"~\u002F.gitignore_global",[10,736,737,738,741,742,745,746,749],{},"A comprehensive global gitignore covering Node, Rust, Solidity, Python, Go, Docker, editors (VS Code, JetBrains, Vim, Sublime), OS files (macOS ",[14,739,740],{},".DS_Store",", Windows ",[14,743,744],{},"Thumbs.db","), and security-sensitive files (",[14,747,748],{},".env*",", private keys, keystores, SSH keys). Registered via:",[66,751,753],{"className":68,"code":752,"language":63,"meta":70,"style":70},"git config --global core.excludesfile ~\u002F.gitignore_global\n",[14,754,755],{"__ignoreMap":70},[74,756,757,759,761,763,766],{"class":76,"line":77},[74,758,212],{"class":80},[74,760,518],{"class":88},[74,762,521],{"class":84},[74,764,765],{"class":88}," core.excludesfile",[74,767,768],{"class":88}," ~\u002F.gitignore_global\n",[10,770,771,772,774,775,778],{},"This means you never accidentally commit a ",[14,773,740],{}," or ",[14,776,777],{},".env"," file regardless of which project you're in.",[25,780],{},[28,782,784],{"id":783},"after-running","After Running",[36,786,787,801,807],{},[39,788,789,792,793,796,797,800],{},[42,790,791],{},"Restart your terminal"," - nvm and Cargo env are added to ",[14,794,795],{},".bashrc","\u002F",[14,798,799],{},".zshrc"," and only load in a fresh shell.",[39,802,803,806],{},[42,804,805],{},"Restart VS Code"," if it was open when the script ran.",[39,808,809],{},"Install VS Code extensions:",[66,811,813],{"className":68,"code":812,"language":63,"meta":70,"style":70},"code --install-extension rust-lang.rust-analyzer\ncode --install-extension esbenp.prettier-vscode\ncode --install-extension dbaeumer.vscode-eslint\ncode --install-extension NomicFoundation.hardhat-solidity\ncode --install-extension Vue.volar\ncode --install-extension starkware.cairo1\n",[14,814,815,825,834,843,852,862],{"__ignoreMap":70},[74,816,817,819,822],{"class":76,"line":77},[74,818,14],{"class":80},[74,820,821],{"class":84}," --install-extension",[74,823,824],{"class":88}," rust-lang.rust-analyzer\n",[74,826,827,829,831],{"class":76,"line":101},[74,828,14],{"class":80},[74,830,821],{"class":84},[74,832,833],{"class":88}," esbenp.prettier-vscode\n",[74,835,836,838,840],{"class":76,"line":171},[74,837,14],{"class":80},[74,839,821],{"class":84},[74,841,842],{"class":88}," dbaeumer.vscode-eslint\n",[74,844,845,847,849],{"class":76,"line":378},[74,846,14],{"class":80},[74,848,821],{"class":84},[74,850,851],{"class":88}," NomicFoundation.hardhat-solidity\n",[74,853,855,857,859],{"class":76,"line":854},5,[74,856,14],{"class":80},[74,858,821],{"class":84},[74,860,861],{"class":88}," Vue.volar\n",[74,863,865,867,869],{"class":76,"line":864},6,[74,866,14],{"class":80},[74,868,821],{"class":84},[74,870,871],{"class":88}," starkware.cairo1\n",[25,873],{},[28,875,877],{"id":876},"verifying-everything-worked","Verifying Everything Worked",[10,879,880],{},"Run these after restarting your terminal:",[66,882,884],{"className":68,"code":883,"language":63,"meta":70,"style":70},"git --version          # should print git version 2.x.x\nnode --version         # should print v24.x.x\npnpm --version         # should print 9.x.x or 10.x.x\nrustc --version        # should print rustc 1.x.x\ncargo --version        # should print cargo 1.x.x\nssh -T git@github.com  # should print: Hi \u003Cusername>! You've successfully authenticated\n",[14,885,886,897,907,916,925,934],{"__ignoreMap":70},[74,887,888,890,893],{"class":76,"line":77},[74,889,212],{"class":80},[74,891,892],{"class":84}," --version",[74,894,896],{"class":895},"sJ8bj","          # should print git version 2.x.x\n",[74,898,899,902,904],{"class":76,"line":101},[74,900,901],{"class":80},"node",[74,903,892],{"class":84},[74,905,906],{"class":895},"         # should print v24.x.x\n",[74,908,909,911,913],{"class":76,"line":171},[74,910,16],{"class":80},[74,912,892],{"class":84},[74,914,915],{"class":895},"         # should print 9.x.x or 10.x.x\n",[74,917,918,920,922],{"class":76,"line":378},[74,919,314],{"class":80},[74,921,892],{"class":84},[74,923,924],{"class":895},"        # should print rustc 1.x.x\n",[74,926,927,929,931],{"class":76,"line":854},[74,928,317],{"class":80},[74,930,892],{"class":84},[74,932,933],{"class":895},"        # should print cargo 1.x.x\n",[74,935,936,939,942,945],{"class":76,"line":864},[74,937,938],{"class":80},"ssh",[74,940,941],{"class":84}," -T",[74,943,944],{"class":88}," git@github.com",[74,946,947],{"class":895},"  # should print: Hi \u003Cusername>! You've successfully authenticated\n",[10,949,950,951,774,953,955],{},"If ",[14,952,901],{},[14,954,16],{}," is not found after restarting, check that nvm added itself to your shell config:",[66,957,959],{"className":68,"code":958,"language":63,"meta":70,"style":70},"grep -n \"nvm\" ~\u002F.bashrc   # Linux \u002F bash\ngrep -n \"nvm\" ~\u002F.zshrc    # macOS \u002F zsh\n",[14,960,961,978],{"__ignoreMap":70},[74,962,963,966,969,972,975],{"class":76,"line":77},[74,964,965],{"class":80},"grep",[74,967,968],{"class":84}," -n",[74,970,971],{"class":88}," \"nvm\"",[74,973,974],{"class":88}," ~\u002F.bashrc",[74,976,977],{"class":895},"   # Linux \u002F bash\n",[74,979,980,982,984,986,989],{"class":76,"line":101},[74,981,965],{"class":80},[74,983,968],{"class":84},[74,985,971],{"class":88},[74,987,988],{"class":88}," ~\u002F.zshrc",[74,990,991],{"class":895},"    # macOS \u002F zsh\n",[10,993,994,995,998],{},"You should see a block of lines referencing ",[14,996,997],{},"~\u002F.nvm",". If they're missing, re-run Phase 3 or add them manually from the nvm README.",[25,1000],{},[28,1002,1004],{"id":1003},"what-it-does-not-install","What It Does Not Install",[10,1006,1007],{},"Deliberately excluded:",[1009,1010,1011,1017,1023,1029,1035],"ul",{},[39,1012,1013,1016],{},[42,1014,1015],{},"VS Code itself"," - install it from the official source. The script only configures it.",[39,1018,1019,1022],{},[42,1020,1021],{},"Docker"," - too varied by OS and use case to automate reliably.",[39,1024,1025,1028],{},[42,1026,1027],{},"Cairo \u002F Scarb"," - separate setup depending on whether you're doing Starknet development.",[39,1030,1031,1034],{},[42,1032,1033],{},"Database clients"," - project-specific.",[39,1036,1037,1040,1041,224],{},[42,1038,1039],{},"Multiple Git identities"," - if you need to manage separate personal and work GitHub accounts from one machine, see the companion article on ",[1042,1043,1049],"a",{"href":1044,"target":1045,"rel":1046},"\u002Fwriting\u002Fgit-multiple-accounts","_blank",[1047,1048],"noopener","noreferrer","Git setup here",[25,1051],{},[28,1053,1055],{"id":1054},"troubleshooting","Troubleshooting",[10,1057,1058],{},[42,1059,1060,1063],{},[14,1061,1062],{},"pnpm: command not found"," after install",[10,1065,1066,1067,1070],{},"Corepack needs Node to be active. Make sure ",[14,1068,1069],{},"node --version"," returns something first, then re-run Phase 4.",[10,1072,1073],{},[42,1074,1075,1078],{},[14,1076,1077],{},"ssh -T git@github.com"," returns \"Permission denied\"",[10,1080,1081],{},"The public key was not added to GitHub, or the wrong key was added. Run:",[66,1083,1085],{"className":68,"code":1084,"language":63,"meta":70,"style":70},"cat ~\u002F.ssh\u002Fid_ed25519.pub\n",[14,1086,1087],{"__ignoreMap":70},[74,1088,1089,1091],{"class":76,"line":77},[74,1090,165],{"class":80},[74,1092,1093],{"class":88}," ~\u002F.ssh\u002Fid_ed25519.pub\n",[10,1095,1096,1097,1100],{},"Copy that exact output, go to ",[14,1098,1099],{},"github.com\u002Fsettings\u002Fkeys",", click \"New SSH key\", set type to \"Authentication Key\", and paste it in.",[10,1102,1103],{},[42,1104,1105,1108],{},[14,1106,1107],{},"rustc: command not found"," after restart",[10,1110,1111],{},"The Cargo env is missing from your shell config. Add it manually:",[66,1113,1115],{"className":68,"code":1114,"language":63,"meta":70,"style":70},"echo 'source \"$HOME\u002F.cargo\u002Fenv\"' >> ~\u002F.bashrc   # Linux\necho 'source \"$HOME\u002F.cargo\u002Fenv\"' >> ~\u002F.zshrc    # macOS\n",[14,1116,1117,1133],{"__ignoreMap":70},[74,1118,1119,1122,1125,1128,1130],{"class":76,"line":77},[74,1120,1121],{"class":84},"echo",[74,1123,1124],{"class":88}," 'source \"$HOME\u002F.cargo\u002Fenv\"'",[74,1126,1127],{"class":136}," >>",[74,1129,974],{"class":88},[74,1131,1132],{"class":895},"   # Linux\n",[74,1134,1135,1137,1139,1141,1143],{"class":76,"line":101},[74,1136,1121],{"class":84},[74,1138,1124],{"class":88},[74,1140,1127],{"class":136},[74,1142,988],{"class":88},[74,1144,1145],{"class":895},"    # macOS\n",[10,1147,1148],{},"Then restart your terminal.",[10,1150,1151],{},[42,1152,1153,1154],{},"Script exits with ",[14,1155,1156],{},"bash: ... syntax error",[10,1158,1159],{},"You are likely on macOS with the old system bash (version 3). Install bash via Homebrew as described in the \"Before You Start\" section above.",[1161,1162,1163],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":70,"searchDepth":101,"depth":101,"links":1165},[1166,1167,1168,1176,1177,1178,1179],{"id":30,"depth":101,"text":31},{"id":118,"depth":101,"text":119},{"id":183,"depth":101,"text":184,"children":1169},[1170,1171,1172,1173,1174,1175],{"id":191,"depth":171,"text":192},{"id":233,"depth":171,"text":234},{"id":336,"depth":171,"text":337},{"id":409,"depth":171,"text":410},{"id":472,"depth":171,"text":473},{"id":653,"depth":171,"text":654},{"id":783,"depth":101,"text":784},{"id":876,"depth":101,"text":877},{"id":1003,"depth":101,"text":1004},{"id":1054,"depth":101,"text":1055},"The shell script I use to bootstrap any Linux or macOS machine - Rust, Node.js 24, pnpm, Git with SSH signing, and global configs in one run.","md",{"date":1183,"tag":1184,"readingTime":1185},"2026-06-20","Tooling",9,true,"\u002Fwriting\u002Fdev-setup",{"title":5,"description":1180},"writing\u002Fdev-setup","C0bD7EF7IdjUGe8D8jm9rvYS6jgfyrkLA1IpIWDTVmg",1782459956858]