[{"data":1,"prerenderedAt":632},["ShallowReactive",2],{"navigation_docs":3,"-docs-templates-hooks":145,"-docs-templates-hooks-surround":627},[4,8,12,16,51,81,103],{"title":5,"path":6,"stem":7},"Introduction","\u002Fdocs\u002Fintroduction","docs\u002F1.introduction",{"title":9,"path":10,"stem":11},"Getting started","\u002Fdocs\u002Fgetting-started","docs\u002F2.getting-started",{"title":13,"path":14,"stem":15},"Environment variables","\u002Fdocs\u002Fenvironment-variables","docs\u002F3.environment-variables",{"title":17,"icon":18,"path":19,"stem":20,"children":21,"page":50},"Guide","i-lucide-book-open","\u002Fdocs\u002Fguide","docs\u002F4.guide",[22,26,30,34,38,42,46],{"title":23,"path":24,"stem":25},"Scaffold a project","\u002Fdocs\u002Fguide\u002Fscaffold","docs\u002F4.guide\u002F1.scaffold",{"title":27,"path":28,"stem":29},"Pin and manage templates","\u002Fdocs\u002Fguide\u002Fpin","docs\u002F4.guide\u002F2.pin",{"title":31,"path":32,"stem":33},"Update pinned templates","\u002Fdocs\u002Fguide\u002Fupdating","docs\u002F4.guide\u002F3.updating",{"title":35,"path":36,"stem":37},"Find templates","\u002Fdocs\u002Fguide\u002Fsearch","docs\u002F4.guide\u002F4.search",{"title":39,"path":40,"stem":41},"Manage registries","\u002Fdocs\u002Fguide\u002Fregistry","docs\u002F4.guide\u002F5.registry",{"title":43,"path":44,"stem":45},"Troubleshooting","\u002Fdocs\u002Fguide\u002Ftroubleshooting","docs\u002F4.guide\u002F6.troubleshooting",{"title":47,"path":48,"stem":49},"Build your first template","\u002Fdocs\u002Fguide\u002Fcreate-template","docs\u002F4.guide\u002F7.create-template",false,{"title":52,"icon":53,"path":54,"stem":55,"children":56,"page":50},"Templates","i-lucide-layout-template","\u002Fdocs\u002Ftemplates","docs\u002F5.templates",[57,61,65,69,73,77],{"title":58,"path":59,"stem":60},"Template anatomy","\u002Fdocs\u002Ftemplates\u002Fanatomy","docs\u002F5.templates\u002F1.anatomy",{"title":62,"path":63,"stem":64},"Template params","\u002Fdocs\u002Ftemplates\u002Fparams","docs\u002F5.templates\u002F2.params",{"title":66,"path":67,"stem":68},"Template rendering","\u002Fdocs\u002Ftemplates\u002Ftemplate-rendering","docs\u002F5.templates\u002F3.template-rendering",{"title":70,"path":71,"stem":72},"Hooks","\u002Fdocs\u002Ftemplates\u002Fhooks","docs\u002F5.templates\u002F4.hooks",{"title":74,"path":75,"stem":76},"Publish a template","\u002Fdocs\u002Ftemplates\u002Fpublish","docs\u002F5.templates\u002F5.publish",{"title":78,"path":79,"stem":80},"spin.toml","\u002Fdocs\u002Ftemplates\u002Fspin-toml","docs\u002F5.templates\u002F6.spin-toml",{"title":82,"icon":83,"path":84,"stem":85,"children":86,"page":50},"Registries","i-lucide-database","\u002Fdocs\u002Fregistries","docs\u002F6.registries",[87,91,95,99],{"title":88,"path":89,"stem":90},"Registry anatomy","\u002Fdocs\u002Fregistries\u002Fanatomy","docs\u002F6.registries\u002F1.anatomy",{"title":92,"path":93,"stem":94},"Template metadata file","\u002Fdocs\u002Fregistries\u002Ftemplate-metadata","docs\u002F6.registries\u002F2.template-metadata",{"title":96,"path":97,"stem":98},"Run a registry","\u002Fdocs\u002Fregistries\u002Frun","docs\u002F6.registries\u002F3.run",{"title":100,"path":101,"stem":102},"registry.toml","\u002Fdocs\u002Fregistries\u002Fregistry-toml","docs\u002F6.registries\u002F4.registry-toml",{"title":104,"icon":105,"path":106,"stem":107,"children":108,"page":50},"Commands","i-lucide-terminal","\u002Fdocs\u002Fcommands","docs\u002F7.commands",[109,113,117,121,125,129,133,137,141],{"title":110,"path":111,"stem":112},"spin new","\u002Fdocs\u002Fcommands\u002Fnew","docs\u002F7.commands\u002F1.new",{"title":114,"path":115,"stem":116},"spin add","\u002Fdocs\u002Fcommands\u002Fadd","docs\u002F7.commands\u002F2.add",{"title":118,"path":119,"stem":120},"spin list","\u002Fdocs\u002Fcommands\u002Flist","docs\u002F7.commands\u002F3.list",{"title":122,"path":123,"stem":124},"spin update","\u002Fdocs\u002Fcommands\u002Fupdate","docs\u002F7.commands\u002F4.update",{"title":126,"path":127,"stem":128},"spin remove","\u002Fdocs\u002Fcommands\u002Fremove","docs\u002F7.commands\u002F5.remove",{"title":130,"path":131,"stem":132},"spin search","\u002Fdocs\u002Fcommands\u002Fsearch","docs\u002F7.commands\u002F6.search",{"title":134,"path":135,"stem":136},"spin registry","\u002Fdocs\u002Fcommands\u002Fregistry","docs\u002F7.commands\u002F7.registry",{"title":138,"path":139,"stem":140},"spin init","\u002Fdocs\u002Fcommands\u002Finit","docs\u002F7.commands\u002F8.init",{"title":142,"path":143,"stem":144},"spin version","\u002Fdocs\u002Fcommands\u002Fversion","docs\u002F7.commands\u002F9.version",{"id":146,"title":70,"body":147,"description":621,"extension":622,"links":623,"meta":624,"navigation":275,"path":71,"seo":625,"stem":72,"__hash__":626},"docs\u002Fdocs\u002F5.templates\u002F4.hooks.md",{"type":148,"value":149,"toc":611},"minimark",[150,170,175,195,216,219,222,226,329,332,336,343,368,371,375,378,427,430,434,441,467,486,512,516,527,535,552,574,578,597,601,607],[151,152,153,161],"ul",{},[154,155,156,160],"li",{},[157,158,159],"code",{},"[[pre]]"," runs after params are resolved but before files are rendered or written.",[154,162,163,166,167,169],{},[157,164,165],{},"[[post]]"," runs after files are written but before the output ",[157,168,78],{}," is removed.",[171,172,174],"h2",{"id":173},"trust-and-safety","Trust and safety",[176,177,178,179,181,182,184,185,187,188,184,191,194],"p",{},"Every hook command is shown to you before it runs. When you open the hooks review screen (the second step of ",[157,180,110],{},"), you see a scrollable list of every ",[157,183,159],{}," and ",[157,186,165],{}," command the template will execute, including hook scripts from ",[157,189,190],{},"_pre\u002F",[157,192,193],{},"_post\u002F",". You can inspect them all and choose between:",[151,196,197,204,210],{},[154,198,199,203],{},[200,201,202],"strong",{},"Run"," — execute all hooks and scaffold the project",[154,205,206,209],{},[200,207,208],{},"Skip"," — scaffold the project but skip all hooks",[154,211,212,215],{},[200,213,214],{},"Cancel"," — do nothing, dismiss the dialog",[176,217,218],{},"No shell command runs without your review. This is intentional: spin treats every template as potentially untrusted and gives you full visibility before any code executes.",[176,220,221],{},"Spin also rejects any rendered file path that resolves outside the destination directory, protecting you from path traversal attacks in malicious templates.",[171,223,225],{"id":224},"quick-example","Quick example",[227,228,233],"pre",{"className":229,"code":230,"language":231,"meta":232,"style":232},"language-toml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","[[pre]]\nrun = \"mkdir -p cmd\"\n\n[[post]]\nrun = \"go mod init {{ .project_name }}\"\n\n[[post]]\nrun = \"git init && git add -A && git commit -m 'initial'\"\n","toml","",[157,234,235,250,270,277,287,301,306,315],{"__ignoreMap":232},[236,237,240,244,247],"span",{"class":238,"line":239},"line",1,[236,241,243],{"class":242},"sMK4o","[[",[236,245,227],{"class":246},"sBMFI",[236,248,249],{"class":242},"]]\n",[236,251,253,257,260,263,267],{"class":238,"line":252},2,[236,254,256],{"class":255},"sTEyZ","run ",[236,258,259],{"class":242},"=",[236,261,262],{"class":242}," \"",[236,264,266],{"class":265},"sfazB","mkdir -p cmd",[236,268,269],{"class":242},"\"\n",[236,271,273],{"class":238,"line":272},3,[236,274,276],{"emptyLinePlaceholder":275},true,"\n",[236,278,280,282,285],{"class":238,"line":279},4,[236,281,243],{"class":242},[236,283,284],{"class":246},"post",[236,286,249],{"class":242},[236,288,290,292,294,296,299],{"class":238,"line":289},5,[236,291,256],{"class":255},[236,293,259],{"class":242},[236,295,262],{"class":242},[236,297,298],{"class":265},"go mod init {{ .project_name }}",[236,300,269],{"class":242},[236,302,304],{"class":238,"line":303},6,[236,305,276],{"emptyLinePlaceholder":275},[236,307,309,311,313],{"class":238,"line":308},7,[236,310,243],{"class":242},[236,312,284],{"class":246},[236,314,249],{"class":242},[236,316,318,320,322,324,327],{"class":238,"line":317},8,[236,319,256],{"class":255},[236,321,259],{"class":242},[236,323,262],{"class":242},[236,325,326],{"class":265},"git init && git add -A && git commit -m 'initial'",[236,328,269],{"class":242},[176,330,331],{},"Commands run in order. The first failure stops the hook chain.",[171,333,335],{"id":334},"pre-hooks","Pre-hooks",[176,337,338,339,342],{},"Use pre-hooks to prepare the destination directory before files land. They can create directories, initialise package managers that need a project root, or write files that later ",[157,340,341],{},".tmpl"," files can reference.",[227,344,346],{"className":229,"code":345,"language":231,"meta":232,"style":232},"[[pre]]\nrun = \"go mod init {{ .project_name }}\"\n",[157,347,348,356],{"__ignoreMap":232},[236,349,350,352,354],{"class":238,"line":239},[236,351,243],{"class":242},[236,353,227],{"class":246},[236,355,249],{"class":242},[236,357,358,360,362,364,366],{"class":238,"line":252},[236,359,256],{"class":255},[236,361,259],{"class":242},[236,363,262],{"class":242},[236,365,298],{"class":265},[236,367,269],{"class":242},[176,369,370],{},"If a pre-hook fails, no files are written and no post-hooks run.",[171,372,374],{"id":373},"post-hooks","Post-hooks",[176,376,377],{},"Use post-hooks to finish the project after files are written.",[227,379,381],{"className":229,"code":380,"language":231,"meta":232,"style":232},"[[post]]\nrun = \"go mod init {{ .project_name }}\"\n\n[[post]]\nrun = \"git init && git add -A && git commit -m 'initial'\"\n",[157,382,383,391,403,407,415],{"__ignoreMap":232},[236,384,385,387,389],{"class":238,"line":239},[236,386,243],{"class":242},[236,388,284],{"class":246},[236,390,249],{"class":242},[236,392,393,395,397,399,401],{"class":238,"line":252},[236,394,256],{"class":255},[236,396,259],{"class":242},[236,398,262],{"class":242},[236,400,298],{"class":265},[236,402,269],{"class":242},[236,404,405],{"class":238,"line":272},[236,406,276],{"emptyLinePlaceholder":275},[236,408,409,411,413],{"class":238,"line":279},[236,410,243],{"class":242},[236,412,284],{"class":246},[236,414,249],{"class":242},[236,416,417,419,421,423,425],{"class":238,"line":289},[236,418,256],{"class":255},[236,420,259],{"class":242},[236,422,262],{"class":242},[236,424,326],{"class":265},[236,426,269],{"class":242},[176,428,429],{},"If a post-hook fails, the rendered files remain on disk so you can inspect or fix the state.",[171,431,433],{"id":432},"templating","Templating",[176,435,436,437,440],{},"Hook commands are rendered through ",[157,438,439],{},"text\u002Ftemplate"," with the same param values used for file rendering, but only field access is available:",[227,442,444],{"className":229,"code":443,"language":231,"meta":232,"style":232},"[[post]]\nrun = \"echo {{ .project_name }}\"\n",[157,445,446,454],{"__ignoreMap":232},[236,447,448,450,452],{"class":238,"line":239},[236,449,243],{"class":242},[236,451,284],{"class":246},[236,453,249],{"class":242},[236,455,456,458,460,462,465],{"class":238,"line":252},[236,457,256],{"class":255},[236,459,259],{"class":242},[236,461,262],{"class":242},[236,463,464],{"class":265},"echo {{ .project_name }}",[236,466,269],{"class":242},[176,468,469,470,473,474,477,478,481,482,485],{},"Custom functions like ",[157,471,472],{},"upper",", ",[157,475,476],{},"quote",", and ",[157,479,480],{},"snake_case"," are only available in ",[157,483,484],{},"_base\u002F*.tmpl"," file templates, not in hook commands. If you need a transformed value in a hook, use shell tools:",[227,487,489],{"className":229,"code":488,"language":231,"meta":232,"style":232},"[[post]]\nrun = \"echo {{ .project_name }} | tr '[:lower:]' '[:upper:]'\"\n",[157,490,491,499],{"__ignoreMap":232},[236,492,493,495,497],{"class":238,"line":239},[236,494,243],{"class":242},[236,496,284],{"class":246},[236,498,249],{"class":242},[236,500,501,503,505,507,510],{"class":238,"line":252},[236,502,256],{"class":255},[236,504,259],{"class":242},[236,506,262],{"class":242},[236,508,509],{"class":265},"echo {{ .project_name }} | tr '[:lower:]' '[:upper:]'",[236,511,269],{"class":242},[171,513,515],{"id":514},"hook-scripts","Hook scripts",[176,517,518,519,184,521,523,524,526],{},"For non-trivial hooks you can drop scripts in ",[157,520,190],{},[157,522,193],{}," instead of inlining everything in ",[157,525,78],{},":",[227,528,533],{"className":529,"code":531,"language":532},[530],"language-text","my-template\u002F\n  spin.toml\n  _base\u002F\n  _pre\u002F\n    01-mkdir.sh\n    02-init.sh\n  _post\u002F\n    setup.sh\n    cleanup.sh\n","text",[157,534,531],{"__ignoreMap":232},[176,536,537,540,541,184,543,545,546,548,549,551],{},[157,538,539],{},"spin"," runs every file in ",[157,542,190],{},[157,544,193],{}," automatically as the last pre-hook and post-hook steps, sorted alphabetically. Inline ",[157,547,159],{},"\u002F",[157,550,165],{}," commands and hook scripts can be used together.",[151,553,554,565,571],{},[154,555,556,557,560,561,564],{},"Executable files are run as ",[157,558,559],{},".\u002F_pre\u002F\u003Cfile>"," or ",[157,562,563],{},".\u002F_post\u002F\u003Cfile>",".",[154,566,567,568,564],{},"Non-executable files are run with ",[157,569,570],{},"sh",[154,572,573],{},"Hidden files and subdirectories are ignored.",[171,575,577],{"id":576},"skipping-hooks","Skipping hooks",[176,579,580,581,584,585,587,588,184,590,592,593,596],{},"Pass ",[157,582,583],{},"--no-hooks"," to ",[157,586,110],{}," to skip both ",[157,589,159],{},[157,591,165],{}," hooks and hook scripts. Pass ",[157,594,595],{},"--verbose"," to print hook output.",[171,598,600],{"id":599},"failure-behavior","Failure behavior",[176,602,603,604,606],{},"If a hook fails, ",[157,605,539],{}," reports the command and its combined output. Pre-hook failures stop before any files are written; post-hook failures leave the rendered files in place.",[608,609,610],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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);}",{"title":232,"searchDepth":252,"depth":252,"links":612},[613,614,615,616,617,618,619,620],{"id":173,"depth":252,"text":174},{"id":224,"depth":252,"text":225},{"id":334,"depth":252,"text":335},{"id":373,"depth":252,"text":374},{"id":432,"depth":252,"text":433},{"id":514,"depth":252,"text":515},{"id":576,"depth":252,"text":577},{"id":599,"depth":252,"text":600},"Hooks are shell commands declared in spin.toml. They are rendered through text\u002Ftemplate with the resolved param values and run via sh -c in the generated pro...","md",null,{},{"title":70,"description":621},"dj9vSz_NdtmAxxuip2P2pudQv8hk9DoNkCH7akH8hR8",[628,630],{"title":66,"path":67,"stem":68,"description":629,"children":-1},"How spin processes _base\u002F files through Go text\u002Ftemplate with built-in helpers, excludes, and path safety.",{"title":74,"path":75,"stem":76,"description":631,"children":-1},"A template is a normal directory or Git repository. Publish it by making it available at a URL or local path that others can pass to spin new or spin add.",1787755180240]