[{"content":"I wanted to fix one annoying thing about my blog\u0026rsquo;s theme. Several weekends later I had written a new theme from scratch, given it a name, an MIT license and a generated changelog, and submitted it to the Hugo theme registry. At no point did I write an actual blog post. This is a well-documented failure mode and I walked into it with my eyes open.\nIt is called Vellum, this blog runs on it, and as of today it is at 0.2.2. It went up two patch versions while I was writing this post, which tells you something about how the weekends went.\nThe premise Blog themes mostly look like each other: a narrow centered column, a gray byline under the title, and a lot of white space doing work that a single rule could do better. That is fine for essays. It is wrong for what I actually publish, which is command blocks and terminal output.\nSo I took the reference from somewhere else entirely — the engineering drawing sheet. A drawn frame around the page. Graph paper inside it, and nowhere else. And instead of the gray byline, a ruled title block: the bordered box a real drawing carries in its corner to state what the sheet is, who drew it, when, and at what revision.\nThe one rule I gave myself was that the metaphor had to be load-bearing. If an element only looked like drawing furniture, it was decoration and it didn\u0026rsquo;t ship. That is a much stricter rule than it sounds, and it killed a lot of ideas that photographed beautifully.\nBuilt with Claude Code and impeccable Here is the part I should be upfront about: I did not hand-write most of this. I built it with Claude Code, and the thing that made it produce a coherent theme rather than a large pile of plausible CSS was a skill called impeccable.\nimpeccable\u0026rsquo;s trick is that it won\u0026rsquo;t let a design live only in the code. It keeps two documents beside the repo:\nPRODUCT.md — what the theme is for, who it is for, and which of its properties are binding commitments as opposed to merely true today. URL stability and 4.5:1 contrast are binding. Working without JavaScript is not; it just happens to work, and I\u0026rsquo;m allowed to trade it away later without calling it a bug. DESIGN.md — the visual world as actually built, not as intended. It opens by conceding that where it and the stylesheet disagree, the stylesheet is right and the document is stale. Then it holds the code against those documents as things change, and takes screenshots to check whether the thing it just described is the thing on the screen.\nFor a blog theme this is, admittedly, absurd overhead. It is also the reason the theme ended up with a real three-step line system instead of three tokens that all quietly resolve to 1px — which is precisely what it had at one point. Two of them were the same width, eleven declarations had drifted between them, and the result was pixel-identical either way. Nobody was ever going to catch that by looking at it. The document caught it.\nThis post was written the same way, which the theme now discloses by itself — that is the stamp in the title block at the top.\nThe zone rail, or: the part I\u0026rsquo;m unreasonably pleased with On a real drawing, the border is divided into zones — letters down one edge, numbers along the other — so that two people on a phone call can agree about where they are looking. \u0026ldquo;The bracket in C4.\u0026rdquo; It is a coordinate system for a conversation.\nVellum keeps the letters and gives them a job: one zone per top-level heading, each one a link, each sitting at that heading\u0026rsquo;s own measured offset down the sheet, and lit in amber while you are reading it. It is a table of contents that costs no vertical space at all, because it lives in the frame margin — which was otherwise just ruling.\nThe title block states real fields, and omits the ones it has no value for — on a drawing, an empty field and a missing one mean different things. And if a page has fewer than two headings, the rail doesn\u0026rsquo;t render at all; the frame simply closes the column it would have taken. Lettering an empty margin would have been exactly the decoration I had banned in the first place.\nBuilt for code, not for prose The reading column is 92 characters wide. That is well past the 65–75 the typography books recommend, and it is on purpose: an 80-column terminal paste has to land in it without wrapping. I counted it off a rendered line instead of estimating, because every estimate I made turned out to be wrong by a wide margin.\nNothing casts a shadow. Depth is carried entirely by line weight — two widths crossed with three ink weights — and there is exactly one accent color, an amber that never does more than one job on a screen at a time. It\u0026rsquo;s the red pencil of the drawing office.\nDark mode, with zone B lit on the rail. Syntax colors are drawn from the same ink family as the page chrome, so code and sheet share one palette instead of arguing. The index pages get the same treatment: posts separated by ruled lines rather than boxed in cards, because a drawing divides a schedule with rules.\nThe demo site\u0026rsquo;s index sheet. The stamp on the right counts the sheets on file. What\u0026rsquo;s new in 0.2 0.2.0 was mostly plumbing — releases are scripted now, and CHANGELOG.md is generated from the commit history instead of being written by hand and immediately forgotten. It shipped two visible fixes: the zone rail no longer comes back as a little stack of marks in the frame\u0026rsquo;s corner on narrow screens, and the body text of an _index.md now attaches to the page head instead of sitting flush against the first post card, where it read as that card\u0026rsquo;s caption.\n0.2.1 added the AI disclosure you can see on this post: a stamp in the title block, the same mark in the post index so you see it before opening anything, and an optional shortcode for marking individual passages rather than a whole post. Since I built the theme with an AI and write with one, having the theme state that in its own vocabulary seemed better than a disclaimer in the footer.\n0.2.2 then turned those marks down. They had been drawn at the weight of a heading when what they annotate is body text, so they read as more important than the sentence they were attached to — which is the opposite of what a disclosure should do.\nTry it [module] [[module.imports]] path = \u0026#34;github.com/cebor/vellum\u0026#34; Then hugo mod get -u. There\u0026rsquo;s a live demo at pages.stkn.org/felix/vellum , and the source, README and changelog are at github.com/cebor/vellum . It needs Hugo extended 0.158 or newer.\nNote\nIt isn\u0026rsquo;t on themes.gohugo.io yet — the submission is in, but upstream has paused merging new themes, so the queue is the constraint rather than the theme.\nIt was built for this blog first, and where my needs and a hypothetical adopter\u0026rsquo;s collide, my blog wins. It\u0026rsquo;s documented in full and the demo is real, though. If your posts are mostly code too, it might suit you.","date":"August 16, 2026","extent":"6 min read","permalink":"/en/posts/vellum-hugo-theme/","summary":"I wanted to fix one thing about my blog\u0026rsquo;s theme. Several weekends later I had written a new one, named it, licensed it, and submitted it to the Hugo theme registry.","title":"Vellum: a Hugo theme that sets every page as an engineering drawing"},{"content":"If you want AI coding assistance without sending your code to the cloud, this setup is for you. Since VS Code 1.113, GitHub Copilot Chat natively supports custom language model providers — which means you can point it directly at a locally running Ollama instance and use whatever model you want.\nThis post covers two things: how I organize my Ollama models in a dedicated repository, and how to wire them up to VS Code.\nPart 1: Organizing Ollama Models with Modelfiles Rather than pulling models ad-hoc and tweaking parameters every time, I maintain a dedicated Git repository for my Ollama setup: cebor/ollama_models .\nThe core idea is a clean separation between two model roles — coding and planning — each tuned with different parameters and matched to the available hardware.\nHardware The setup targets two machines with quite different capabilities:\nMachine Chip RAM VRAM MacBook Apple M3 24 GB Unified Memory — PC NVIDIA RTX 5090 64 GB RAM 32 GB VRAM The context window sizes and which models are available differ accordingly.\nThe Models Model Type Size (Q4_K_M) Mac ctx PC ctx gemma4:26b-a4b-it-q4_K_M MoE ~18 GB 16384 131072 gemma4:31b-it-q4_K_M Dense ~21 GB 8192 65536 qwen3.6:27b-q4_K_M Dense ~17 GB 8192 65536 qwen3.6:35b-a3b-q4_K_M MoE ~24 GB — 131072 A few things worth noting here:\nGemma4 26b is MoE — despite being smaller on disk (~18 GB), it\u0026rsquo;s used as the coding model. MoE (Mixture-of-Experts) architectures only activate a subset of parameters per token, making them significantly faster at inference. That speed advantage matters a lot during active coding sessions. Gemma4 31b and Qwen3.6 27b are Dense — used for planning. Dense models reason more thoroughly per parameter, which is better suited for architectural discussions, reviewing context, and exploratory conversations. Qwen3.6 35b is PC-only due to its size — it doesn\u0026rsquo;t fit comfortably on the MacBook\u0026rsquo;s unified memory. Custom Model Names After pulling the base models, each is created with a custom name via ollama create:\nMac:\nollama create gemma4-26b-coding -f ./mac-m3-24gb/gemma4-26b-a4b-it-q4_K_M.txt ollama create gemma4-31b-planning -f ./mac-m3-24gb/gemma4-31b-it-q4_K_M.txt ollama create qwen3.6-27b-planning -f ./mac-m3-24gb/qwen3.6-27b-q4_K_M.txt PC:\nollama create gemma4-26b-coding -f ./pc-rtx5090-32gb/gemma4-26b-a4b-it-q4_K_M.txt ollama create gemma4-31b-planning -f ./pc-rtx5090-32gb/gemma4-31b-it-q4_K_M.txt ollama create qwen3.6-27b-planning -f ./pc-rtx5090-32gb/qwen3.6-27b-q4_K_M.txt ollama create qwen3.6-35b-coding -f ./pc-rtx5090-32gb/qwen3.6-35b-a3b-q4_K_M.txt The result is a consistent set of named models (gemma4-26b-coding, gemma4-31b-planning, etc.) that show up identically in VS Code\u0026rsquo;s model picker on both machines, regardless of the underlying hardware-specific configuration.\nModelfile Parameters Each Modelfile sets a handful of parameters tuned for the model\u0026rsquo;s role:\nParameter Value Description num_ctx varies by model/hardware Maximum context length in tokens temperature 0.2 (coding) / 0.5 (planning) Lower = more deterministic; higher = more creative repeat_penalty 1.1 Prevents repetitive outputs The temperature difference is intentional: coding benefits from deterministic, predictable output while planning is better served by a model that explores ideas more freely.\nRepository Structure ollama-modelfiles/ ├── README.md ├── mac-m3-24gb/ │ ├── gemma4-26b-a4b-it-q4_K_M.txt │ ├── gemma4-31b-it-q4_K_M.txt │ └── qwen3.6-27b-q4_K_M.txt ├── pc-rtx5090-32gb/ │ ├── gemma4-26b-a4b-it-q4_K_M.txt │ ├── gemma4-31b-it-q4_K_M.txt │ ├── qwen3.6-27b-q4_K_M.txt │ └── qwen3.6-35b-a3b-q4_K_M.txt └── scripts/ └── ollama-network-expose.ps1 The scripts/ folder also contains a PowerShell script for exposing the Ollama API on the local network — useful if you want to access your PC\u0026rsquo;s Ollama instance from other devices:\n# Run from repo root in an elevated PowerShell session powershell -ExecutionPolicy Bypass -File .\\scripts\\ollama-network-expose.ps1 Part 2: Integrating Ollama with VS Code Copilot Chat Prerequisites Ollama v0.18.3+ VS Code 1.113+ GitHub Copilot Chat extension 0.41.0+ Note on GitHub login: VS Code requires you to be signed in with a GitHub account to use the model selector — even for fully local, custom models. However, no paid GitHub Copilot subscription is required. The free GitHub Copilot Free tier is sufficient to enable custom model selection.\nManual Setup Open the Copilot Chat sidebar from the top-right activity bar. Click the settings gear icon (⚙) to open the Language Models window. Click Add Models and select Ollama from the provider list — VS Code will load all locally available Ollama models. Click Unhide next to your Ollama models to make them selectable in chat. Make sure Local is selected at the bottom of the Copilot Chat panel. That\u0026rsquo;s it. Your locally hosted models are now available directly in the Copilot Chat model picker.\nSwitching Between Models Once set up, switching models is just a dropdown in the chat panel. In practice:\nCoding / Agent / Edit sessions → gemma4-26b-coding or qwen3.6-35b-coding (PC only) Planning / exploratory sessions → gemma4-31b-planning or qwen3.6-27b-planning This mirrors the role separation maintained in the Modelfile repository and keeps the workflow consistent across both machines.\nWrapping Up Running local models in VS Code Copilot Chat is surprisingly seamless once Ollama is set up. Maintaining Modelfiles in version control is worth the small upfront effort — a single ollama create command restores a known-good configuration on any machine.\nThe full repository with all Modelfiles and the network expose script is available at: github.com/cebor/ollama_models .\nHave questions or want to share your own model setup? Feel free to reach out.","date":"April 23, 2026","extent":"4 min read","permalink":"/en/posts/local-llms-in-vscode/","summary":"How to run fully local language models in VS Code\u0026rsquo;s Copilot Chat using Ollama — including a structured approach to maintaining separate planning and coding models per machine.","title":"Local LLMs in VS Code with GitHub Copilot Chat and Ollama"},{"content":" This is an updated version of Leptos can use Tailwind CSS and daisyUI without Node.js by Marc, reflecting changes in Tailwind CSS v4 and the current daisyUI standalone release.\nLeptos projects created with cargo-leptos have built-in support for Tailwind CSS — no Node.js, no separate build tool, no npm scripts required. cargo-leptos downloads and runs the Tailwind CSS standalone executable automatically as part of the build pipeline. daisyUI plugs into that same pipeline via its standalone .mjs bundle, so the entire styling setup stays purely within the Rust/Cargo ecosystem.\nThis guide uses leptos-rs/start-axum as the project base. Bootstrap it with:\ncargo leptos new --git https://github.com/leptos-rs/start-axum cd \u0026lt;your-project-name\u0026gt; 1. Integrating Tailwind CSS Create style/tailwind.css touch style/tailwind.css Add the Tailwind CSS v4 import directive:\n@import \u0026#34;tailwindcss\u0026#34;; That single line is all cargo-leptos needs to kick off the Tailwind build.\nConfigure Cargo.toml In the [package.metadata.leptos] section of your Cargo.toml, add the following key to point cargo-leptos at your new CSS source file:\n[package.metadata.leptos] # ... existing config ... tailwind-input-file = \u0026#34;style/tailwind.css\u0026#34; Note: If there is an existing style-file entry referencing a .scss or .css file, you can remove it — tailwind-input-file takes over as the CSS entry point.\nTry it out Update the HomePage component in src/app.rs to use some Tailwind utility classes:\n\u0026lt;h1 class=\u0026#34;m-8 text-4xl underline decoration-solid\u0026#34;\u0026gt;\u0026#34;Welcome to Leptos!\u0026#34;\u0026lt;/h1\u0026gt; Then start the dev server:\ncargo leptos watch cargo-leptos will download the Tailwind executable on first run, process style/tailwind.css, and serve the compiled stylesheet alongside your app.\nOptional: By default, cargo-leptos downloads Tailwind v4.2.2. To pin a different version, set the LEPTOS_TAILWIND_VERSION environment variable before running the dev server, e.g. export LEPTOS_TAILWIND_VERSION=v4.1.5.\nTailwind CSS is live: the heading picks up m-8 text-4xl underline, while the counter below it is still an unstyled browser button. 2. Integrating daisyUI daisyUI ships a self-contained .mjs bundle that Tailwind CSS v4 can load directly as a @plugin — no npm install needed.\nDownload the daisyUI bundle Download the latest daisyUI standalone bundle directly into your style/ folder:\ncurl -sLo style/daisyui.mjs https://github.com/saadeghi/daisyui/releases/latest/download/daisyui.mjs Hint: The official daisyUI standalone install docs can be found at daisyui.com/docs/install/standalone/ . They also describe an optional daisyui-theme.mjs file for custom theme definitions.\nUpdate style/tailwind.css Edit style/tailwind.css to load the daisyUI plugin and configure your themes:\n@import \u0026#34;tailwindcss\u0026#34;; @source not \u0026#34;./daisyui{,*}.mjs\u0026#34;; @plugin \u0026#34;./daisyui.mjs\u0026#34; { themes: light --default, dark --prefersdark; } The @source not directive prevents Tailwind from scanning the daisyUI bundle file itself for class names, which keeps the build clean and fast.\nUse daisyUI classes in your component Update the HomePage component in src/app.rs to use daisyUI component classes alongside Tailwind utilities:\n\u0026lt;h1 class=\u0026#34;m-8 text-4xl underline decoration-solid\u0026#34;\u0026gt;\u0026#34;Welcome to Leptos!\u0026#34;\u0026lt;/h1\u0026gt; \u0026lt;button class=\u0026#34;m-8 btn btn-primary\u0026#34; on:click=on_click\u0026gt;\u0026#34;Click Me: \u0026#34; {count}\u0026lt;/button\u0026gt; Run the dev server again:\ncargo leptos watch The button will now render with daisyUI\u0026rsquo;s themed btn btn-primary styles, and the active theme will automatically follow the user\u0026rsquo;s prefers-color-scheme setting.\nThe same page with daisyUI loaded: btn btn-primary styles the counter, and the dark theme follows the OS via --prefersdark. That\u0026rsquo;s it — a fully styled Leptos app with Tailwind CSS v4 and daisyUI, driven entirely by cargo-leptos with no JavaScript toolchain required.","date":"April 20, 2026","extent":"3 min read","permalink":"/en/posts/leptos-tailwind-daisyui/","summary":"This is an updated version of Leptos can use Tailwind CSS and daisyUI without Node.js by Marc, reflecting changes in Tailwind CSS v4 and the current daisyUI standalone release.\nLeptos projects created with cargo-leptos have built-in support for Tailwind CSS — no Node.js, no separate build tool, no npm scripts required. cargo-leptos downloads and runs the Tailwind CSS standalone executable automatically as part of the build pipeline. daisyUI plugs into that same pipeline via its standalone .mjs bundle, so the entire styling setup stays purely within the Rust/Cargo ecosystem.","title":"Integrating Tailwind CSS and daisyUI into a Leptos Project with cargo-leptos"},{"content":"Legal notice under § 5 DDG (German Digital Services Act).\nService provider Felix Itzenplitz — responsible for the content under § 18 (2) MStV.\nContact Email: admin+pub@stkn.org This address is the fastest route for anything about this blog: a question about a post, a mistake I missed, or a link that leads nowhere.\nAbout this site A personal blog with no commercial purpose: no ads, no affiliate links, no sponsored posts. Everything here is my own view, not that of my employer or any client.\nExternal links Linked sites are outside my control; their operators are responsible for what they publish. Nothing unlawful was apparent on them when the link was made. If you spot one that has gone bad, write to me and I will take it out.\nContent Text, images and code samples are mine unless stated otherwise. Quotations and borrowed excerpts are marked as such; the rights to them stay with their respective holders.\nColophon Built statically with Hugo and my own theme Vellum , which lays out every page like an engineering drawing sheet: frame, zone rail and title block. What ships is plain HTML — no database, no comment section.","date":"","extent":"","permalink":"/en/imprint/","summary":"Legal notice under § 5 DDG (German Digital Services Act).\nService provider Felix Itzenplitz — responsible for the content under § 18 (2) MStV.\nContact Email: admin+pub@stkn.org This address is the fastest route for anything about this blog: a question about a post, a mistake I missed, or a link that leads nowhere.","title":"Imprint"},{"content":"Workflow automation tools are becoming essential for businesses aiming to streamline operations, boost productivity, and allocate resources more efficiently. Among these, n8n stands out as a powerful, open-source platform that is transforming how businesses manage their processes. This article explores the features, capabilities, and unique advantages of n8n, including a comparison with other players in the market.\nCapabilities of n8n n8n allows users to automate a wide variety of tasks, from simple data transfers to complex workflows with multiple conditional steps. The platform excels due to the following features:\nIntegration with Over 200 Applications: These include popular tools such as Slack, Google Sheets, and Trello, allowing seamless data flow and task automation across different platforms. No-Code Automation: Users can create, update, or delete records, automate data processing tasks, and even build detailed reports—all without needing to write code. Custom Workflows: Whether it’s automating notifications or creating automated reports, n8n offers flexibility in designing workflows that suit specific business needs. Example Automations Here are a few ways businesses are using n8n to automate their daily operations:\nLead Generation: By integrating with CRM and marketing platforms, companies can automate the gathering and initial processing of leads. Data Synchronization: Syncing data between social media accounts and analytics tools helps businesses gain comprehensive insights without manual effort. Automated Alerts: Teams can use tools like Slack or Microsoft Teams to automate notifications, ensuring crucial information reaches the right people at the right time. Custom Approval Workflows: n8n can automate email responses and updates, streamlining the approval processes within organizations. Comparison with Flowise When compared to Flowise, n8n stands out due to its open-source nature and extensive customization capabilities. Some significant differences include:\nCustomization and Flexibility: n8n allows developers to extend and modify the platform according to their unique requirements, which is often limited in more rigid platforms like Flowise. Self-Hosting Capabilities: n8n provides businesses the option to self-host the platform, offering complete control over their data and operations—a crucial advantage for businesses focusing on data privacy and security. Self-Hosting Made Easy One of the most appealing features of n8n is its ease of self-hosting. Companies can deploy n8n on their own servers, ensuring maximum control and security. Here’s how easy it is to get started:\nMinimal Setup Requirements: All that’s needed is a server with Node.js and npm installed, with Docker recommended for containerization and simple deployment. Data Privacy and Control: Self-hosting empowers businesses to comply effortlessly with data regulations, maintaining privacy and security standards. Conclusion For businesses looking to optimize their operations, n8n offers a versatile, cost-effective solution for automating workflows. Its open-source foundation, coupled with the ability to self-host, provides a platform that not only meets diverse automation needs but also emphasizes data privacy and control. As the demand for automation continues to grow, n8n remains an ideal choice for businesses seeking to enhance their operational efficiency and drive growth.","date":"March 13, 2025","extent":"3 min read","permalink":"/en/posts/n8n-a-versatile-open-source-workflow-automation-tool/","summary":"Workflow automation tools are becoming essential for businesses aiming to streamline operations, boost productivity, and allocate resources more efficiently. Among these, n8n stands out as a powerful, open-source platform that is transforming how businesses manage their processes. This article explores the features, capabilities, and unique advantages of n8n, including a comparison with other players in the market.\nCapabilities of n8n n8n allows users to automate a wide variety of tasks, from simple data transfers to complex workflows with multiple conditional steps. The platform excels due to the following features:","title":"n8n: A Versatile Open-Source Workflow Automation Tool"},{"content":"Since Ubuntu 22.04 it is possible to use systemd in an experimental state on WSL installations. This guide explains how you can easily set it up in just a few steps.\nSetup Guide Install wsl-setup package, if its not already there. sudo apt install wsl-setup Create a /etc/wsl.conf file ( WSL Configuration Documentation ): For WSL comes with Windows 10/11:\n[boot] command=\u0026#34;/usr/libexec/wsl-systemd\u0026#34; For WSL Preview from MS Store in Windows 11:\n[boot] systemd=true Create /run/users/1000 and set user rights (optional: but was needed for snapd): sudo mkdir -p /run/users/1000 sudo chown $USER:$GROUP /run/users/1000 Relaunch wsl with following command from windows or set as launch option in your terminal: wsl -e /usr/libexec/nslogin /bin/bash Links Official Ubuntu Bug Report Install Snippet ","date":"June 24, 2022","extent":"1 min read","permalink":"/en/posts/wsl-enabling-systemd-ubuntu22.04/","summary":"Since Ubuntu 22.04 it is possible to use systemd in an experimental state on WSL installations. This guide explains how you can easily set it up in just a few steps.\nSetup Guide Install wsl-setup package, if its not already there. sudo apt install wsl-setup Create a /etc/wsl.conf file ( WSL Configuration Documentation ): For WSL comes with Windows 10/11:","title":"WSL2: Enabling systemd in Ubuntu 22.04"},{"content":"This is my first post.","date":"February 4, 2022","extent":"1 min read","permalink":"/en/posts/my-first-post/","summary":"This is my first post.","title":"My First Post"}]