[{"data":1,"prerenderedAt":727},["ShallowReactive",2],{"navigation_docs":3,"-getting-started-installation":191,"-getting-started-installation-surround":722},[4,31,67,103,129,155,175],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":30},"Getting started","i-lucide-rocket","\u002Fgetting-started","1.getting-started",[10,15,20,25],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Quick start","\u002Fgetting-started\u002Fquick-start","1.getting-started\u002F3.quick-start","i-lucide-play",{"title":26,"path":27,"stem":28,"icon":29},"Agent Skill","\u002Fgetting-started\u002Fagent-skill","1.getting-started\u002F4.agent-skill","i-lucide-sparkles",false,{"title":32,"icon":33,"path":34,"stem":35,"children":36,"page":30},"Authoring","i-lucide-pen-line","\u002Fauthoring","2.authoring",[37,42,47,52,57,62],{"title":38,"path":39,"stem":40,"icon":41},"Comark syntax","\u002Fauthoring\u002Fcomark-syntax","2.authoring\u002F1.comark-syntax","i-lucide-file-code",{"title":43,"path":44,"stem":45,"icon":46},"Frontmatter","\u002Fauthoring\u002Ffrontmatter","2.authoring\u002F2.frontmatter","i-lucide-heading",{"title":48,"path":49,"stem":50,"icon":51},"Modules","\u002Fauthoring\u002Fmodules","2.authoring\u002F3.modules","i-lucide-blocks",{"title":53,"path":54,"stem":55,"icon":56},"Merge tags and bindings","\u002Fauthoring\u002Fmerge-tags-and-bindings","2.authoring\u002F4.merge-tags-and-bindings","i-lucide-braces",{"title":58,"path":59,"stem":60,"icon":61},"Actions and spans","\u002Fauthoring\u002Factions-and-spans","2.authoring\u002F5.actions-and-spans","i-lucide-mouse-pointer-click",{"title":63,"path":64,"stem":65,"icon":66},"Compile errors","\u002Fauthoring\u002Fcompile-errors","2.authoring\u002F6.compile-errors","i-lucide-circle-alert",{"title":68,"icon":69,"path":70,"stem":71,"children":72,"page":30},"Rendering","i-lucide-layout-template","\u002Frendering","3.rendering",[73,78,83,88,93,98],{"title":74,"path":75,"stem":76,"icon":77},"Families and streams","\u002Frendering\u002Ffamilies-and-streams","3.rendering\u002F1.families-and-streams","i-lucide-users",{"title":79,"path":80,"stem":81,"icon":82},"Themes","\u002Frendering\u002Fthemes","3.rendering\u002F2.themes","i-lucide-palette",{"title":84,"path":85,"stem":86,"icon":87},"Config and the renderer","\u002Frendering\u002Fconfig-and-renderer","3.rendering\u002F3.config-and-renderer","i-lucide-settings",{"title":89,"path":90,"stem":91,"icon":92},"Layout and spacing","\u002Frendering\u002Flayout-and-spacing","3.rendering\u002F4.layout-and-spacing","i-lucide-ruler",{"title":94,"path":95,"stem":96,"icon":97},"HTML output","\u002Frendering\u002Fhtml-output","3.rendering\u002F5.html-output","i-lucide-code-xml",{"title":99,"path":100,"stem":101,"icon":102},"Plain text","\u002Frendering\u002Fplain-text","3.rendering\u002F6.plain-text","i-lucide-file-text",{"title":104,"icon":105,"path":106,"stem":107,"children":108,"page":30},"Sending","i-lucide-send","\u002Fsending","4.sending",[109,114,119,124],{"title":110,"path":111,"stem":112,"icon":113},"Message and MIME","\u002Fsending\u002Fmessage-and-mime","4.sending\u002F1.message-and-mime","i-lucide-mail",{"title":115,"path":116,"stem":117,"icon":118},"Router and streams","\u002Fsending\u002Frouter-and-streams","4.sending\u002F2.router-and-streams","i-lucide-route",{"title":120,"path":121,"stem":122,"icon":123},"SMTP","\u002Fsending\u002Fsmtp","4.sending\u002F3.smtp","i-lucide-server",{"title":125,"path":126,"stem":127,"icon":128},"Maps","\u002Fsending\u002Fmaps","4.sending\u002F4.maps","i-lucide-map",{"title":130,"icon":131,"path":132,"stem":133,"children":134,"page":30},"Tooling","i-lucide-wrench","\u002Ftooling","5.tooling",[135,140,145,150],{"title":136,"path":137,"stem":138,"icon":139},"The lttr CLI","\u002Ftooling\u002Fcli","5.tooling\u002F1.cli","i-lucide-terminal",{"title":141,"path":142,"stem":143,"icon":144},"Live preview","\u002Ftooling\u002Flive-preview","5.tooling\u002F2.live-preview","i-lucide-eye",{"title":146,"path":147,"stem":148,"icon":149},"Screenshots","\u002Ftooling\u002Fscreenshots","5.tooling\u002F3.screenshots","i-lucide-camera",{"title":151,"path":152,"stem":153,"icon":154},"Goldens and testing","\u002Ftooling\u002Fgoldens-and-testing","5.tooling\u002F4.goldens-and-testing","i-lucide-flask-conical",{"title":156,"icon":157,"path":158,"stem":159,"children":160,"page":30},"Guides","i-lucide-book-open","\u002Fguides","6.guides",[161,166,170],{"title":162,"path":163,"stem":164,"icon":165},"The Quiet example","\u002Fguides\u002Fthe-quiet-example","6.guides\u002F1.the-quiet-example","i-lucide-mail-open",{"title":167,"path":168,"stem":169,"icon":82},"Your own family and theme","\u002Fguides\u002Fyour-own-family-and-theme","6.guides\u002F2.your-own-family-and-theme",{"title":171,"path":172,"stem":173,"icon":174},"Releasing","\u002Fguides\u002Freleasing","6.guides\u002F3.releasing","i-lucide-tag",{"title":176,"icon":177,"path":178,"stem":179,"children":180,"page":30},"Reference","i-lucide-library","\u002Freference","7.reference",[181,186],{"title":182,"path":183,"stem":184,"icon":185},"API reference","\u002Freference\u002Fapi-reference","7.reference\u002F1.api-reference","i-lucide-list-tree",{"title":187,"path":188,"stem":189,"icon":190},"Gallery","\u002Freference\u002Fgallery","7.reference\u002F2.gallery","i-lucide-images",{"id":192,"title":16,"body":193,"description":715,"extension":716,"links":717,"meta":718,"navigation":719,"path":17,"seo":720,"stem":18,"__hash__":721},"docs\u002F1.getting-started\u002F2.installation.md",{"type":194,"value":195,"toc":703},"minimark",[196,201,205,229,233,243,432,440,444,459,480,483,591,609,617,621,644,653,681,685,699],[197,198,200],"h2",{"id":199},"check-your-go-version","Check your Go version",[202,203,204],"p",{},"lttr needs Go 1.25 or newer.",[206,207,213],"pre",{"className":208,"code":209,"filename":210,"language":211,"meta":212,"style":212},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go version\n","Terminal","bash","",[214,215,216],"code",{"__ignoreMap":212},[217,218,221,225],"span",{"class":219,"line":220},"line",1,[217,222,224],{"class":223},"sBMFI","go",[217,226,228],{"class":227},"sfazB"," version\n",[197,230,232],{"id":231},"configure-private-module-access","Configure private module access",[202,234,235,238,239,242],{},[214,236,237],{},"sulv-io\u002Flttr"," is a private repository. The public module proxy and checksum database cannot read it, so ",[214,240,241],{},"go get"," fails until you tell Go to fetch it directly and give Git a credential that can read it. You do this once per machine.",[244,245,247,252,280,298,302,305,357,360,390,394,422],"steps",{"level":246},"3",[248,249,251],"h3",{"id":250},"mark-the-module-as-private","Mark the module as private",[206,253,255],{"className":208,"code":254,"filename":210,"language":211,"meta":212,"style":212},"go env -w GOPRIVATE='github.com\u002Fsulv-io\u002F*'\n",[214,256,257],{"__ignoreMap":212},[217,258,259,261,264,267,270,274,277],{"class":219,"line":220},[217,260,224],{"class":223},[217,262,263],{"class":227}," env",[217,265,266],{"class":227}," -w",[217,268,269],{"class":227}," GOPRIVATE=",[217,271,273],{"class":272},"sMK4o","'",[217,275,276],{"class":227},"github.com\u002Fsulv-io\u002F*",[217,278,279],{"class":272},"'\n",[202,281,282,285,286,289,290,293,294,297],{},[214,283,284],{},"GOPRIVATE"," sets ",[214,287,288],{},"GONOPROXY"," and ",[214,291,292],{},"GONOSUMDB"," to the same pattern, so Go fetches anything under ",[214,295,296],{},"github.com\u002Fsulv-io\u002F"," straight from GitHub and skips the checksum lookup that would fail on a repository it cannot see.",[248,299,301],{"id":300},"let-git-authenticate","Let Git authenticate",[202,303,304],{},"Go fetches modules over HTTPS. Rewrite those URLs to carry a token that can read the repository:",[206,306,308],{"className":208,"code":307,"filename":210,"language":211,"meta":212,"style":212},"git config --global url.\"https:\u002F\u002Fx-access-token:${GITHUB_TOKEN}@github.com\u002Fsulv-io\u002F\".insteadOf \"https:\u002F\u002Fgithub.com\u002Fsulv-io\u002F\"\n",[214,309,310],{"__ignoreMap":212},[217,311,312,315,318,321,324,327,330,333,337,340,343,345,348,351,354],{"class":219,"line":220},[217,313,314],{"class":223},"git",[217,316,317],{"class":227}," config",[217,319,320],{"class":227}," --global",[217,322,323],{"class":227}," url.",[217,325,326],{"class":272},"\"",[217,328,329],{"class":227},"https:\u002F\u002Fx-access-token:",[217,331,332],{"class":272},"${",[217,334,336],{"class":335},"sTEyZ","GITHUB_TOKEN",[217,338,339],{"class":272},"}",[217,341,342],{"class":227},"@github.com\u002Fsulv-io\u002F",[217,344,326],{"class":272},[217,346,347],{"class":227},".insteadOf",[217,349,350],{"class":272}," \"",[217,352,353],{"class":227},"https:\u002F\u002Fgithub.com\u002Fsulv-io\u002F",[217,355,356],{"class":272},"\"\n",[202,358,359],{},"If you already use an SSH key with GitHub, rewrite to SSH instead and no token is stored:",[206,361,363],{"className":208,"code":362,"filename":210,"language":211,"meta":212,"style":212},"git config --global url.\"git@github.com:sulv-io\u002F\".insteadOf \"https:\u002F\u002Fgithub.com\u002Fsulv-io\u002F\"\n",[214,364,365],{"__ignoreMap":212},[217,366,367,369,371,373,375,377,380,382,384,386,388],{"class":219,"line":220},[217,368,314],{"class":223},[217,370,317],{"class":227},[217,372,320],{"class":227},[217,374,323],{"class":227},[217,376,326],{"class":272},[217,378,379],{"class":227},"git@github.com:sulv-io\u002F",[217,381,326],{"class":272},[217,383,347],{"class":227},[217,385,350],{"class":272},[217,387,353],{"class":227},[217,389,356],{"class":272},[248,391,393],{"id":392},"verify","Verify",[206,395,397],{"className":208,"code":396,"filename":210,"language":211,"meta":212,"style":212},"go env GOPRIVATE\ngit ls-remote https:\u002F\u002Fgithub.com\u002Fsulv-io\u002Flttr HEAD\n",[214,398,399,408],{"__ignoreMap":212},[217,400,401,403,405],{"class":219,"line":220},[217,402,224],{"class":223},[217,404,263],{"class":227},[217,406,407],{"class":227}," GOPRIVATE\n",[217,409,411,413,416,419],{"class":219,"line":410},2,[217,412,314],{"class":223},[217,414,415],{"class":227}," ls-remote",[217,417,418],{"class":227}," https:\u002F\u002Fgithub.com\u002Fsulv-io\u002Flttr",[217,420,421],{"class":227}," HEAD\n",[202,423,424,425,427,428,431],{},"The first prints ",[214,426,276],{},". The second prints a commit hash. If it asks for a password or reports ",[214,429,430],{},"Repository not found",", the credential is the problem, not Go.",[433,434,435,436,439],"warning",{},"The token form writes the token in cleartext to ",[214,437,438],{},"~\u002F.gitconfig",". On a workstation prefer SSH; in CI, inject a short-lived token as an environment variable.",[197,441,443],{"id":442},"add-the-module","Add the module",[206,445,447],{"className":208,"code":446,"filename":210,"language":211,"meta":212,"style":212},"go get github.com\u002Fsulv-io\u002Flttr\n",[214,448,449],{"__ignoreMap":212},[217,450,451,453,456],{"class":219,"line":220},[217,452,224],{"class":223},[217,454,455],{"class":227}," get",[217,457,458],{"class":227}," github.com\u002Fsulv-io\u002Flttr\n",[202,460,461,462,469,470,473,474,479],{},"lttr depends on two modules besides the standard library: ",[463,464,468],"a",{"href":465,"rel":466},"https:\u002F\u002Fgithub.com\u002Fyuin\u002Fgoldmark",[467],"nofollow","goldmark",", which the ",[214,471,472],{},"comark"," parser extends, and ",[463,475,478],{"href":476,"rel":477},"https:\u002F\u002Fpkg.go.dev\u002Fgopkg.in\u002Fyaml.v3",[467],"yaml.v3",", which reads frontmatter.",[202,481,482],{},"Most services import the root package and two leaf packages:",[484,485,486,499],"table",{},[487,488,489],"thead",{},[490,491,492,496],"tr",{},[493,494,495],"th",{},"Import path",[493,497,498],{},"What it holds",[500,501,502,539,564,577],"tbody",{},[490,503,504,510],{},[505,506,507],"td",{},[214,508,509],{},"github.com\u002Fsulv-io\u002Flttr",[505,511,512,515,516,515,519,515,522,515,525,515,528,515,531,515,534,515,537],{},[214,513,514],{},"Compile",", ",[214,517,518],{},"Template",[214,520,521],{},"Renderer",[214,523,524],{},"Config",[214,526,527],{},"Family",[214,529,530],{},"Registry",[214,532,533],{},"Message",[214,535,536],{},"Router",[214,538,120],{},[490,540,541,546],{},[505,542,543],{},[214,544,545],{},"github.com\u002Fsulv-io\u002Flttr\u002Fdata",[505,547,548,549,515,552,515,555,515,558,515,561],{},"Typed template values: ",[214,550,551],{},"Money",[214,553,554],{},"Exact",[214,556,557],{},"Receipt",[214,559,560],{},"Product",[214,562,563],{},"StockItem",[490,565,566,571],{},[505,567,568],{},[214,569,570],{},"github.com\u002Fsulv-io\u002Flttr\u002Ftheme",[505,572,573,574],{},"The palette, font and brand types behind ",[214,575,576],{},"lttr.Theme",[490,578,579,584],{},[505,580,581],{},[214,582,583],{},"github.com\u002Fsulv-io\u002Flttr\u002Fmapbox",[505,585,586,587,590],{},"Mapbox Static Images URLs for the ",[214,588,589],{},"map"," module (optional)",[202,592,593,594,515,596,515,599,515,602,515,605,608],{},"The pipeline packages (",[214,595,472],{},[214,597,598],{},"ir",[214,600,601],{},"layout",[214,603,604],{},"render\u002Fhtml",[214,606,607],{},"render\u002Ftext",") are exported for tools and tests. You rarely import them directly.",[610,611,612,613,616],"note",{},"lttr is pre-1.0, so the API can still change between minor versions. Check which version you resolved with ",[214,614,615],{},"go list -m github.com\u002Fsulv-io\u002Flttr",".",[197,618,620],{"id":619},"install-the-cli","Install the CLI",[206,622,624],{"className":208,"code":623,"filename":210,"language":211,"meta":212,"style":212},"go install github.com\u002Fsulv-io\u002Flttr\u002Fcmd\u002Flttr@latest\nlttr -h\n",[214,625,626,636],{"__ignoreMap":212},[217,627,628,630,633],{"class":219,"line":220},[217,629,224],{"class":223},[217,631,632],{"class":227}," install",[217,634,635],{"class":227}," github.com\u002Fsulv-io\u002Flttr\u002Fcmd\u002Flttr@latest\n",[217,637,638,641],{"class":219,"line":410},[217,639,640],{"class":223},"lttr",[217,642,643],{"class":227}," -h\n",[206,645,651],{"className":646,"code":648,"filename":649,"language":650,"meta":212},[647],"language-text","usage: lttr \u003Ccommand> [flags]\n\ncommands:\n  preview   render every example to a directory with an index page\n  render    write one example's .eml to stdout\n  lint      compile template files and print errors and warnings\n  tags      list a template's merge tags and bindings\n  serve     live preview that recompiles templates on every request\n\nRun \"lttr \u003Ccommand> -h\" for a command's flags.\n","Output","text",[214,652,648],{"__ignoreMap":212},[202,654,655,656,659,660,663,664,667,668,671,672,675,676,289,679,616],{},"The CLI works on the worked example in ",[214,657,658],{},"examples\u002Fquiet",": it compiles templates against the example's data types and renders them with its theme and families. Use it to see the design, try a module or check a change to the library. ",[214,661,662],{},"lttr serve"," reads the templates from ",[214,665,666],{},"examples\u002Fquiet\u002Ftemplates"," by default, so run it from a checkout of the repository or pass ",[214,669,670],{},"-dir",". In your own service, the compile checks run when your package initialises, so ",[214,673,674],{},"go test"," catches a broken template. See ",[463,677,678],{"href":137},"CLI",[463,680,151],{"href":152},[197,682,684],{"id":683},"next-steps","Next steps",[686,687,688,694],"ul",{},[689,690,691,693],"li",{},[463,692,21],{"href":22}," builds, renders and sends a complete email in one file.",[689,695,696,698],{},[463,697,38],{"href":39}," covers what a template can contain.",[700,701,702],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}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);}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"title":212,"searchDepth":410,"depth":410,"links":704},[705,706,712,713,714],{"id":199,"depth":410,"text":200},{"id":231,"depth":410,"text":232,"children":707},[708,710,711],{"id":250,"depth":709,"text":251},3,{"id":300,"depth":709,"text":301},{"id":392,"depth":709,"text":393},{"id":442,"depth":410,"text":443},{"id":619,"depth":410,"text":620},{"id":683,"depth":410,"text":684},"Add lttr to a Go module, set up access to the private repository, and install the CLI.","md",null,{},{"icon":19},{"title":16,"description":715},"gLFIDog1j9XJNTtBPjmlmCfxKA9Z-3W-NgMJdxWep1U",[723,725],{"title":11,"path":12,"stem":13,"description":724,"icon":14,"children":-1},"What lttr is, how a template becomes a message, and what the library leaves to you.",{"title":21,"path":22,"stem":23,"description":726,"icon":24,"children":-1},"One Go file that defines a data type, compiles a template against it, renders the email and sends it over SMTP.",1790309826746]