[{"content":"Building an AI Operating Model: A Practical Framework TLDR Model routing by task type is the foundation: Use low/mid-tier models for simple tasks (Q\u0026amp;A, boilerplate, documentation), mid-tier for bounded work (unit tests, small fixes), and high-tier for complex work (architecture, security, production debugging). Structural workflow for VS Code: Plan → Generate → Review → Refine → Final Validate. This separates thinking from typing and prevents wasted token execution. Companies need enablement, not just licences. Train developers on model selection, context management, prompt patterns, secure usage, and cost awareness. Agent mode governance: Require plans before execution, bound task scope, and developer checkpoints. Make usage auditable and repeatable. Governance progression: Visibility → Training → Routing → Guardrails → Optimisation. Start with transparency, not restriction. Good habits reduce waste more effectively than blunt controls. Measure ROI as \u0026ldquo;cost per valuable engineering outcome\u0026rdquo; (shipped features, resolved incidents, cycle time), not tokens consumed. Seven-step implementation roadmap: Define task-based routing, set VS Code patterns, create prompt templates, teach context management, establish thresholds, review patterns monthly, and keep premium models available for serious work. About this series This is Part 2 of a 2-part series on AI operating models:\nPart 1: The AI Governance Problem — The challenges — governance gaps, token accounting risks, context window mismanagement, and why casual AI adoption no longer works. Part 2 (this post): The practical changes — how to implement model routing by task type, build effective enablement programmes, create agent governance rules, and measure AI value against business outcomes. This post is the implementation guide. If you haven\u0026rsquo;t read Part 1, start here to understand the \u0026ldquo;why\u0026rdquo; behind these changes.\nModel routing: use the right tier for the task Companies need to teach developers how to select models based on the work being done. This should be part of AI coding enablement, not left to individual trial and error.\nA practical model-routing pattern could look like this:\nWork type Recommended model tier Why Simple Q\u0026amp;A Low / mid Low risk and low reasoning requirement Boilerplate code Low / mid Mostly pattern-based generation README, comments, documentation Low / mid Primarily language generation and summarisation Unit test scaffolding Mid Needs code awareness, but usually bounded Small bug fixes Mid Requires reasoning within a narrow scope Existing code explanation Mid Depends on codebase size and context required Refactoring across files High Requires consistency, dependency awareness, and reasoning Architecture design High Ambiguous, trade-off-heavy, and context-sensitive Security review High High consequence if the model misses something Production issue analysis High Time-sensitive and high impact Final PR review High Quality gate before merge Agentic multi-step coding High, but bounded Can burn tokens quickly without scope control This table is not about forcing developers into weaker tools. It is about protecting the strongest tools for the work where they create the most value.\nA useful principle is:\nPremium models should be an escalation path and quality gate, not the default execution engine for every prompt.\nThe VS Code workflow needs structure Most developers are now interacting with AI directly inside VS Code or another IDE. That is powerful because the assistant can see files, selections, diagnostics, terminal output, and repository context. It is also dangerous because a poorly scoped agent session can consume a large amount of context and credits before anyone notices.\nThe default workflow should not be \u0026ldquo;ask the most powerful model to do everything.\u0026rdquo;\nA better workflow is:\nPlan → Generate → Review → Refine → Final Validate Step Model tier Purpose Plan Mid / high Clarify the approach before burning tokens on implementation Generate Mid Produce the first version of the change Review High Check correctness, edge cases, maintainability, and risk Refine Mid Apply specific corrections and improvements Final validate High Perform final reasoning and confidence check before merge This workflow is important because it separates thinking from typing.\nDevelopers often waste tokens because they ask the AI to execute before they have forced it to explain the plan. For small changes, that may not matter. For multi-file changes, migrations, refactors, test rewrites, or infrastructure-as-code updates, it matters a lot.\nBefore allowing an agent to modify files, the developer should ask for a plan first:\nDo not change any files yet. Review the relevant files and propose an implementation plan. List the files you expect to modify, the risk areas, and the tests that should be run. Wait for confirmation before editing. That small habit prevents a lot of wasted execution.\nCompanies need AI coding enablement, not just licences Many organisations have invested in Copilot licences but have not invested enough in operating practices.\nA licence gives access. It does not teach:\nhow to choose the right model how to manage context windows how to write scoped prompts how to use agent mode safely how to evaluate AI-generated code how to avoid leaking sensitive data into prompts how to measure productivity against AI spend how to decide when a premium model is justified how to use AI for review rather than just generation This is where engineering leadership needs to step in.\nA good enablement programme should include:\nTraining module What it should cover Model selection Which model tier to use for different engineering tasks Token and credit basics How input, output, cached tokens, and context affect cost Context management How to attach files, use selections, avoid context pollution, and start clean sessions Prompt patterns How to define context, constraints, expected output, and definition of done Agent mode How to scope agentic tasks, review diffs, and apply checkpoints Code review with AI How to use AI as a reviewer without outsourcing accountability Secure usage Data classification, secrets, customer data, and policy boundaries Cost awareness How to read usage dashboards and understand burn patterns Team playbooks Standard prompts and workflows for common engineering activities The outcome should be a shared engineering language around AI usage.\nWithout that, each developer invents their own workflow. Some will be careful and effective. Others will burn tokens, generate noisy changes, and create review burden.\nPrompt templates for common work Provide internal templates for:\nbug investigation unit test creation pull request review infrastructure-as-code review security review code explanation migration/refactor planning documentation generation When developers have a template, they are more likely to be structured. Structured prompts lead to fewer retries, better output, and lower cost.\nContext management discipline Developers should understand that adding more context is not always better. The skill is to provide the minimum relevant context needed for a good answer.\nThis is a learned behaviour. It requires training and team reinforcement.\nA practical enterprise usage policy Here is a simple policy that organisations can adapt.\nAI model usage policy for VS Code and Copilot Rule Policy Default model Use a mid-tier or auto-selected model for normal development work Premium model use Allowed for complex, ambiguous, high-risk, or high-value work Agent mode Must start with a scoped plan before execution for non-trivial changes Large refactors Premium model permitted, but task must be broken into bounded steps Context window Use default context for everyday tasks; extend only for large multi-file analysis Reasoning level Use regular reasoning by default; increase for architecture, debugging, and complex analysis Token threshold Above an agreed threshold, require a brief justification or work item reference Budget control Use enterprise, cost centre, and user-level budgets where available Review Monthly review of usage, outcomes, cycle time, and rework Enablement Provide prompt templates, examples, and internal office hours Measurement Track usage by model, workflow, repository, and delivery outcome This does not create heavy bureaucracy. It creates a minimum viable operating model.\nThe right governance model: visibility before restriction The first instinct in many organisations will be to restrict usage aggressively. That may reduce cost, but it can also damage adoption and push teams back into old ways of working.\nA better pattern is:\nVisibility → Training → Routing → Guardrails → Optimisation Stage Focus Outcome Visibility Understand who is using what, where, and why Baseline usage and cost patterns Training Teach model selection, prompting, context, and agent workflows Better usage behaviour Routing Define recommended model tiers by task Lower waste without reducing quality Guardrails Apply budgets, approval paths, and thresholds Controlled spend and accountability Optimisation Review outcomes and refine policy Better cost-to-value ratio over time The goal is not to punish heavy users. Some heavy users may be creating significant value. The goal is to distinguish high-value usage from avoidable waste.\nA developer using premium models to resolve a production outage, accelerate a migration, or perform a critical security review should not be treated the same as someone burning credits on vague exploratory prompts.\nThat distinction requires visibility.\nHow to measure ROI One of the weakest areas in AI adoption is measurement. Most organisations can measure licence cost. Fewer can measure delivery impact.\nA better ROI model should combine platform usage with engineering outcomes.\nMetric What it tells you AI Credits consumed by model Which models drive cost Usage by repo/team Where adoption is concentrated Agent sessions per work item Whether agent mode is being used deliberately PR cycle time Whether AI is reducing delivery friction Review comments and rework Whether AI output is increasing or reducing review burden Defect escape rate Whether quality is improving or degrading Test coverage changes Whether AI is helping with validation Developer satisfaction Whether developers feel faster or more burdened Cost per accepted PR A rough but useful economic signal Cost per resolved incident or feature Better alignment to business outcome The most useful metric is not \u0026ldquo;tokens consumed\u0026rdquo; in isolation.\nIt is:\nAI cost per valuable engineering outcome.\nThat could be a shipped feature, resolved incident, completed migration story, closed security finding, or reduced technical debt item.\nMy recommended operating model If I were setting this up inside an enterprise engineering environment, I would use the following approach.\n1. Define task-based model routing Publish a simple table that tells developers which model tier to start with for common activities.\nDo not make this overly complex. A one-page guide is more useful than a 40-page policy.\n2. Set a default VS Code pattern Use a standard flow:\nPlan first. Generate second. Review with a stronger model. Refine. Final validate. This gives developers a repeatable way to use AI without handing over control.\n3. Create prompt templates Provide internal templates for:\nbug investigation unit test creation pull request review infrastructure-as-code review security review code explanation migration/refactor planning documentation generation 4. Teach context management Developers should understand that adding more context is not always better. The skill is to provide the minimum relevant context needed for a good answer.\n5. Put thresholds in place For example:\nThreshold Action 70% of monthly allowance Notify the user and team lead 90% of allowance Recommend usage review and model-routing check Above agreed limit Require work item, incident, or delivery justification Repeated overage Review workflow, not just spend The point is not to shame usage. It is to understand whether the usage is intentional.\n6. Review patterns monthly A monthly AI usage review should cover:\nwhich teams are using premium models most whether high usage maps to high-value work whether agent mode is being used safely where training is needed whether budgets need adjustment whether default models should change 7. Keep premium models available Do not remove premium models from serious engineers doing serious work. That would be counterproductive.\nInstead, make premium usage deliberate.\nThe leadership position The right position is balanced:\nWe absolutely need strong models. But we also need an operating model. Without one, the best users will self-manage, while the majority will burn quota through poor prompting, default premium model usage, and unbounded agent runs. A simple model-routing framework gives us both productivity and cost control.\nThat is the argument I think companies need to make now.\nNot \u0026ldquo;use cheap models.\u0026rdquo;\nNot \u0026ldquo;let everyone use the most expensive model all the time.\u0026rdquo;\nBut:\nUse the right model, with the right context, for the right task.\nThat is how AI coding tools become a sustainable engineering capability rather than a noisy cost line.\nPractical checklist for engineering leaders Question Why it matters Do we know which models our developers are using most? Without visibility, cost control is guesswork Do developers understand AI Credits, tokens, and context windows? Billing now maps more closely to actual usage Do we have model-routing guidance? Prevents premium models being used as the default for low-value work Do we have prompt templates? Reduces retries and inconsistent output quality Do we have rules for agent mode? Agentic workflows can consume rapidly if unbounded Do we review AI-generated code consistently? AI does not remove engineering accountability Do we track usage against delivery outcomes? Spend must be connected to value Do we have budget thresholds? Enables control without blocking useful work Do we train teams continuously? Tool capability is changing too quickly for one-off enablement Do we treat premium models as quality gates? Keeps high-end reasoning available where it matters most Closing thought AI-assisted engineering is not going away. But the next phase will favour teams that know how to operate it properly.\nThe winners will not be the teams with the largest token quota.\nThe winners will be the teams that know when to spend it.\nGo back to Part 1 ← Back to Part 1: The AI Governance Problem\nIf you missed Part 1, it covers the governance challenges and risks that make this framework necessary.\nReferences GitHub Blog: GitHub Copilot is moving to usage-based billing GitHub Docs: Models and pricing for GitHub Copilot GitHub Docs: Usage-based billing for individuals GitHub Changelog: Larger context windows and configurable reasoning levels for GitHub Copilot GitHub Docs: AI model comparison GitHub Changelog: Copilot code review will start consuming GitHub Actions minutes on June 1, 2026 Author\u0026rsquo;s note This post was co-written with AI assistance. I used GitHub Copilot to help structure the framework, develop the policies and checklists, and refine the prose. The implementation approach and operating model are my own, informed by engineering leadership experience. AI was valuable in articulating practical implementation steps clearly.\n","permalink":"https://dev.wellytonian.com/posts/ai/building-an-ai-operating-model/","summary":"Move beyond casual AI adoption. Here is a practical framework for model routing, prompt discipline, agent governance, and ROI measurement that engineering leaders can implement today.","title":"Building an AI Operating Model: A Practical Framework"},{"content":"TLDR GitHub\u0026rsquo;s June 1 billing change signals the end of casual AI usage. Companies must move from \u0026ldquo;enable Copilot and hope\u0026rdquo; to structured AI engineering practice. The real problem is not expensive models — it is unstructured usage. Premium models are justified for complex work, but using them for boilerplate, documentation, or simple Q\u0026amp;A is waste. Context windows and prompt discipline matter more than model choice. Vague prompts, unpruned conversations, and unbounded agent sessions drive cost without value. Agent mode needs governance: Require plans before execution, bound task scope, and developer checkpoints. Agentic workflows can burn tokens quickly. Why companies are underprepared: Most organisations have licences but lack enablement. Without training on model selection, context management, and cost awareness, developers default to premium models for everything. On 1 June 2026, GitHub Copilot moved from a premium-request model to usage-based billing through GitHub AI Credits. That sounds like a billing change, but I think it is actually a much bigger signal for engineering organisations.\nIt tells us that the era of casual, unstructured AI usage inside developer tools is ending.\nFor the last couple of years, many organisations have treated AI coding assistants as a productivity add-on: enable Copilot, give developers access to the best models available, and assume productivity will follow. That may have worked when usage was simpler and cost exposure was less visible. But GitHub Copilot is no longer just an autocomplete tool. It now includes chat, agent mode, code review, CLI-based workflows, model selection, custom context, larger context windows, and increasingly autonomous coding sessions.\nThat changes the governance problem.\nThe question is no longer:\n\u0026ldquo;Should developers use AI?\u0026rdquo;\nThe better question is:\n\u0026ldquo;How do we train developers to use the right model, with the right context, for the right task, at the right cost?\u0026rdquo;\nThat is where many companies are currently underprepared.\nAbout this series This is Part 1 of a 2-part series on AI operating models:\nPart 1 (this post): The problems and challenges — what governance gaps exist, why token costs are spiralling, and what risks come with unstructured AI usage. Part 2: Building an AI Operating Model — The practical framework — how to implement model routing, build enablement programmes, govern agent mode, and measure ROI. This post focuses on the diagnosis. The next post provides the cure. Read Part 2 →\nWhat changed on 1 June? GitHub announced that from 1 June 2026, Copilot plans would transition to usage-based billing. Instead of counting only premium requests, Copilot now consumes GitHub AI Credits based on token usage. That includes input tokens, output tokens, and cached tokens, with cost varying by model. GitHub\u0026rsquo;s own explanation is clear: the cost of an interaction depends on both the model used and the number of tokens consumed.\nThe headline items are:\nArea What changed Why it matters Billing unit Premium Request Units were replaced by GitHub AI Credits Cost is now more directly linked to actual model usage Token accounting Input, output, and cached tokens are counted Long prompts, long responses, and large context can materially affect cost Model choice Different models consume credits at different rates A premium model used casually can become expensive quickly Agentic workflows Long-running agent sessions can consume significantly more Autonomous multi-step work is not equivalent to a quick chat question Enterprise controls Budgets can be managed at enterprise, cost centre, and user levels Governance is now a first-class requirement Pooled usage Business usage can be pooled across the organisation Organisations need usage analytics, not just seat counts Code review Copilot code review can consume AI Credits and GitHub Actions minutes AI use can now cross into adjacent platform cost lines GitHub has also stated that larger context windows and higher reasoning levels consume more AI Credits per interaction. In June, GitHub announced support for one-million-token context windows and configurable reasoning levels in Copilot, while explicitly recommending that users keep the default context and reasoning level for everyday tasks and reserve extended context or higher reasoning for complex, multi-file problems.\nThat recommendation is important. It is effectively saying: capability has increased, but so has the need for discipline.\nThe real problem is not expensive models There is a common argument that appears whenever AI tooling costs increase:\n\u0026ldquo;We need to use cheaper models.\u0026rdquo;\nThat is too simplistic.\nA colleague of mine provided an equally common counterargument:\n\u0026ldquo;Cheaper models produce weaker results, and if we need twice as many prompts, we have not saved anything.\u0026rdquo;\nThat is also valid, but does not address the core issue.\nThe real issue is not expensive models. The real issue is unstructured model usage.\nA premium model is absolutely justified when the task demands it. If someone is performing complex architecture analysis, debugging a difficult production issue, reviewing a security-sensitive change, or refactoring across a large codebase, then using a stronger model may be the most economical choice.\nBut that does not mean the same model should be used for every activity in the development lifecycle.\nUsing the strongest available model for every prompt is like using a senior architect to format YAML, write boilerplate comments, summarise a README, or explain a simple compiler error. It will work, but it is not a sensible operating model.\nThe goal should not be to minimise model cost in isolation.\nThe goal should be:\nLowest total cost to an acceptable outcome.\nThat includes:\nCost factor Why it matters Token cost Direct consumption of AI Credits or equivalent platform spend Developer time Poor model choice can increase re-prompting and review effort Context size Unnecessary files, logs, and history increase token usage Output quality Weak output can create rework or false confidence Review effort AI-generated code still needs human validation Defect risk Poor recommendations can create production, security, or maintainability issues Delivery speed Good model routing can reduce cycle time without uncontrolled spend Governance overhead Untracked usage makes forecasting and accountability difficult This is why the better discussion is not \u0026ldquo;cheap models vs expensive models.\u0026rdquo;\nThe better discussion is model routing.\nContext windows are not free memory One of the most important concepts companies need to teach is the context window.\nA context window is the amount of information the model can consider at one time. It includes the developer\u0026rsquo;s prompt, previous conversation, system instructions, selected files, retrieved repository context, tool outputs, terminal output, and the model\u0026rsquo;s own responses. In long sessions, this can fill quickly.\nLarger context windows are useful, but they are not automatically better. They allow the model to inspect more information, but they can also increase token consumption and cost.\nGitHub\u0026rsquo;s June update is a good example. One-million-token context windows make it possible to work across larger codebases and longer documents. That is powerful for complex multi-file work. But GitHub also states that larger context windows and higher reasoning levels consume more AI Credits, and recommends using default context and reasoning for everyday tasks.\nThat should become a standard enterprise training point:\nContext practice Good behaviour Poor behaviour File selection Attach only the files needed for the task Attach the whole repository by default Conversation length Start a fresh session for a new task Keep reusing one long, polluted chat Terminal output Paste only relevant errors and logs Paste thousands of lines without filtering Agent scope Give a bounded task and stop condition Tell the agent to \u0026ldquo;fix everything\u0026rdquo; Reasoning level Increase only for complex problems Use maximum reasoning for routine edits Context window size Extend for large multi-file analysis Use large context as the default Documentation Provide architecture notes and constraints Assume the model will infer business rules The context window should be treated like an engineering resource. It needs to be curated.\nPrompt discipline matters more than most people think A large percentage of AI waste comes from poor prompting, not poor models.\nDevelopers often ask vague questions like:\nCan you fix this? or:\nMake this better. That forces the model to infer intent, inspect unnecessary context, make assumptions, and often generate broad changes that require another round of correction.\nA better prompt has structure:\nContext: Goal: Files involved: Constraints: Expected output: Definition of done: What not to change: For example:\nContext: This is a Python FastAPI service deployed to Azure Container Apps. Goal: Add structured logging to the upload endpoint. Files involved: app/api/upload.py, app/core/logging.py. Constraints: Do not change the API contract. Do not introduce new dependencies. Expected output: Minimal code changes and a short explanation. Definition of done: Existing tests pass, new logging is included, and no secrets are logged. What not to change: Do not modify authentication or request validation logic. This kind of prompt reduces ambiguity. It also reduces the number of retries. That is good for cost, but more importantly, it is good for engineering quality.\nAgent mode needs governance Agentic workflows are where the economics change most dramatically.\nA normal chat request might be one model interaction. An agentic workflow can involve many model calls, file reads, shell commands, searches, edits, test runs, and follow-up reasoning. That is the point of agent mode, but it also means agent mode needs stronger usage discipline.\nOrganisations should define explicit agent rules:\nRule Policy Start with a plan Agent must propose a plan before modifying files for non-trivial work Bound the task The prompt must define scope, files, and expected outcome Limit blast radius Avoid broad instructions like \u0026ldquo;refactor the project\u0026rdquo; without decomposition Require checkpoints Developer reviews diffs after each meaningful step Use tests deliberately Agent should run targeted tests before broad test suites Stop on uncertainty Agent should ask when requirements are unclear instead of guessing Use premium models selectively Premium models are allowed for complex agentic work, but not every task Track consumption Teams should monitor usage by user, repo, workflow, and model The key point is not to block agentic development. The key point is to make it auditable and repeatable.\nWhy companies are underprepared Many organisations have invested in Copilot licences but have not invested enough in operating practices.\nThat gap is now visible.\nA licence gives access. It does not teach:\nhow to choose the right model how to manage context windows how to write scoped prompts how to use agent mode safely how to evaluate AI-generated code how to avoid leaking sensitive data into prompts how to measure productivity against AI spend how to decide when a premium model is justified how to use AI for review rather than just generation This is where engineering leadership needs to step in.\nWhat happens next The June 1 billing change is not just a pricing event. It is a maturity test.\nOrganisations that treat it only as a finance problem will respond with blunt restrictions. Organisations that treat it as an engineering operating model problem will build better habits.\nThe next post covers the practical framework: how to implement model routing, train developers, govern agent mode, and measure ROI properly.\nThe question is no longer \u0026ldquo;Should we use AI?\u0026rdquo;\nThe question is: \u0026ldquo;Are we structured enough to use it well?\u0026rdquo;\nReady for Part 2? Continue to Part 2: Building an AI Operating Model →\nPart 2 covers the implementation roadmap: model routing tables, enablement programmes, prompt templates, agent governance rules, and how to measure AI ROI properly.\nAuthor\u0026rsquo;s note This post was co-written with AI assistance. I used GitHub Copilot to help structure the argument, develop the tables and examples, and refine the prose. The core thesis and governance concerns are my own, but AI was valuable in articulating the problems clearly.\n","permalink":"https://dev.wellytonian.com/posts/ai/the-ai-governance-problem/","summary":"GitHub\u0026rsquo;s June 1 billing change reveals a critical governance gap: casual AI adoption is no longer sustainable. Engineering leaders need to understand the real risks.","title":"The AI Governance Problem: Why Casual Model Usage No Longer Works"},{"content":"The Concurrency Paradox: Solving the Parallel Development Bottleneck in the Age of AI It is the oldest cliché in software engineering: adding manpower to a late software project makes it later. But today, we aren\u0026rsquo;t just adding manpower; we are adding Agentic power.\nWith the rise of AI Agents and LLM-assisted coding, the velocity at which code is generated has exploded. What used to take a human developer three days can now be scaffolded by an agent in three minutes. But this speed comes with a hidden cost.\nWe call it the Concurrency Paradox: as you increase the speed of execution, you exponentially increase the cost of coordination.\nWhen you have humans and agents working on the same codebase, the bottlenecks shift violently from \u0026ldquo;writing code\u0026rdquo; to \u0026ldquo;integrating code.\u0026rdquo; In an Agentic world, this manifests in even more painful ways:\nVelocity-Induced Entropy: Agents can generate 1,000 lines of code in seconds. If that code isn\u0026rsquo;t strictly bounded, you essentially DDoS your own integration branch with changes that are hard to review. Contextless Implementation: An agent typically solves the problem right in front of it. Without a broader \u0026ldquo;Spec,\u0026rdquo; it lacks the systemic context, leading to \u0026ldquo;Logic Drift\u0026rdquo; where features work in isolation but fail in concert. The \u0026ldquo;Big Bang\u0026rdquo; Integration: If humans struggle to merge weekly, agents—who don\u0026rsquo;t feel the pain of a merge conflict—will happily drift miles off course until the merge becomes impossible. To survive the Agentic Era, high-performing organizations are shifting toward a Spec-Driven Development (SDD) framework. This isn\u0026rsquo;t about writing waterfall-style novels; it’s about establishing the Guardrails that allow AI to move at light speed without crashing the system.\nThe Spec as the Prompt In an Agentic workflow, the Spec is more than a contract; it is the Prompt Context.\nAgents are stochastic. If you ask three agents to \u0026ldquo;build a user profile page,\u0026rdquo; you will get three radically different data structures. In a team environment, this is chaos.\nBy mandating that a Spec is written, reviewed, and committed before implementation starts, we constrain the Agent\u0026rsquo;s solution space. The Spec defines the inputs, the outputs, the schema, and the dependencies. It turns the Agent from a \u0026ldquo;Wild Creative\u0026rdquo; into a \u0026ldquo;Precision Engineer.\u0026rdquo;\nBy creating a centralized \u0026ldquo;Spec Coordination\u0026rdquo; role, we ensure that the instructions fed to our Agents (and humans) are consistent. We detect collisions at the prompt engineering phase, not the pull request phase.\nArchitecture as Traffic Lanes Agentic development requires rigid architectural boundaries even more than human development. An agent doesn\u0026rsquo;t \u0026ldquo;know\u0026rdquo; that utils/helpers.ts is a shared file used by the Finance Team. It just sees a file it can modify to solve its immediate task.\nZoning Laws: Define strict module ownership. If Team A owns the \u0026ldquo;Dashboard\u0026rdquo; domain, Team B (and their Agents) cannot simply patch a file in that directory. They must request a change or use an exposed interface. Shared Infrastructure: Core utilities and database schemas are \u0026ldquo;high-risk zones.\u0026rdquo; Changes here require a permit because they affect all traffic. By mapping these domains explicitly, we reduce the surface area for merge conflicts. Developer X\u0026rsquo;s Agent works in Module A, Developer Y\u0026rsquo;s Agent works in Module B. They rarely touch the same file.\nThe Ritual of Aggressive Synchronization The final piece of the puzzle is the Daily Rebase Ritual.\nIn many teams, developers fear pulling the latest code because it might break their local environment. They drift further and further away from the main branch, isolating themselves for days. This is a recipe for disaster.\nWe mandate a workflow where every developer rebases their feature branch onto the integration branch every single morning.\nMicro-Conflicts: By syncing daily, conflicts are small—often just a few lines. They are annoying, but manageable. Macro-Conflicts: By syncing weekly, conflicts become structural. Entire functions have moved; files have been renamed. These conflicts destroy morale. Conclusion In the age of AI, Coordination is the new Coding.\nYou cannot rely on developers—or their agents—to \u0026ldquo;just figure it out\u0026rdquo; once the team scales. The speed of generation is too high. You need a framework that enforces isolation, mandates synchronization, and defines the spec before the code.\nBy moving the conflict detection upstream—to the spec phase—we provide the necessary guardrails for Agentic Code Development. We allow the team to move at the speed of AI, without crashing the car.\n","permalink":"https://dev.wellytonian.com/posts/ai/spec-driven-parallel-dev/","summary":"Why AI agents and faster coding speeds require stricter guardrails, and how Spec-Driven Development acts as traffic control for high-velocity teams.","title":"The Concurrency Paradox: Solving the Parallel Development Bottleneck in the Age of AI"},{"content":"Deploy Secrets to GitHub via Bulk Upload: Streamline Your DevOps Security In modern DevOps workflows, managing sensitive information like API keys, database credentials, and configuration variables is crucial for maintaining security while enabling seamless deployments. GitHub Secrets provides a secure way to store sensitive data, but manually uploading dozens of environment variables can be tedious and error-prone. This guide shows you how to automate the process using bulk upload scripts.\nWhy GitHub Secrets Matter Before diving into the automation, let\u0026rsquo;s understand why GitHub Secrets are essential:\n🔐 Security Benefits Encrypted Storage: Secrets are encrypted at rest and in transit Limited Access: Only workflows and authorized users can access secrets No Exposure in Logs: Secret values are automatically masked in workflow logs Environment Isolation: Different secrets for different environments (dev, staging, prod) ⚙️ DevOps Advantages Centralized Management: All secrets managed in one place Version Control Integration: Seamlessly integrated with your repository workflow CI/CD Ready: Instantly available to GitHub Actions workflows Team Collaboration: Secure sharing without exposing sensitive data 🚧 The Problem with Manual Secret Management Manually adding secrets through the GitHub UI becomes problematic when you have:\nMultiple environment variables (often 20+ for modern applications) Multiple repositories requiring the same secrets Frequent secret rotations Team onboarding scenarios ✅ Common Use Cases Here are some real-world examples where bulk secret uploads make a big difference:\nBootstrapping new projects or environments Rotating shared secrets across multiple repositories Automating secrets for ephemeral CI/CD environments Onboarding teams with standardized .env templates 🔁 Repository vs. Organization vs. Environment Secrets GitHub supports secrets at different scopes:\nScope Use Case Repository Per-repo control (default for scripts) Environment Scoped to workflows targeting dev, prod, etc. Organization Shared secrets across all repos in an org This guide focuses on repository-level secrets, but can be adapted to others with a few CLI flag changes.\n💡 Solution: Automated Bulk Upload Scripts Here are two scripts that automate the bulk upload process by reading from your local .env file:\nBash Script (Linux/macOS) #!/bin/bash REPO=\u0026#34;githubusername/reponame\u0026#34; # 🔁 Replace with your target repo ENV_FILE=\u0026#34;.env.local\u0026#34; while IFS=\u0026#39;=\u0026#39; read -r key value do if [[ ! $key =~ ^# \u0026amp;\u0026amp; $key ]]; then echo \u0026#34;🔐 Uploading $key...\u0026#34; gh secret set \u0026#34;$key\u0026#34; --repo \u0026#34;$REPO\u0026#34; --body \u0026#34;$value\u0026#34; fi done \u0026lt; \u0026#34;$ENV_FILE\u0026#34; echo \u0026#34;✅ All secrets uploaded to $REPO\u0026#34; PowerShell Script (Windows) $repo = \u0026#34;githubusername/reponame\u0026#34; # 🔁 Replace with your GitHub repo $envFile = \u0026#34;.env.local\u0026#34; Get-Content $envFile | ForEach-Object { if ($_ -match \u0026#34;^(.*?)=(.*)$\u0026#34;) { $key = $matches[1].Trim() $value = $matches[2].Trim() if ($key -and $value) { Write-Host \u0026#34;🔐 Uploading $key...\u0026#34; gh secret set $key --repo $repo --body $value } } } Write-Host \u0026#34;✅ All secrets uploaded to $repo successfully.\u0026#34; 🧠 How the Scripts Work Both scripts follow the same logic:\nRead Environment File: Parse your .env.local file line by line Extract Key-Value Pairs: Split each line on the = character Filter Valid Entries: Skip comments (lines starting with #) and empty lines Upload to GitHub: Use GitHub CLI to set each secret Progress Feedback: Display upload progress for each secret ⚙️ Prerequisites Before using these scripts, ensure you have:\n1. GitHub CLI Installed # macOS brew install gh # Windows (using winget) winget install GitHub.cli # Ubuntu/Debian sudo apt install gh 2. GitHub CLI Authentication gh auth login 3. Repository Access Ensure you have admin access to the target repository, as secret management requires administrative privileges.\n📄 Setting Up Your Environment File Create a .env.local file in your project root:\n# Database Configuration DATABASE_URL=postgresql://user:password@localhost:5432/mydb DATABASE_HOST=localhost DATABASE_PORT=5432 # API Keys STRIPE_SECRET_KEY=sk_test_xxxxxxxxxxxxxxxxxxxx SENDGRID_API_KEY=SG.xxxxxxxxxxxxxxxxxxxxxxx GOOGLE_MAPS_API_KEY=AIzaxxxxxxxxxxxxxxxxxxxxxxxxx # Azure Configuration AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=https;AccountName=... AZURE_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx AZURE_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Application Settings JWT_SECRET=your-super-secret-jwt-key ENCRYPTION_KEY=your-32-char-encryption-key-here APP_ENV=production ⚠️ Avoid multiline or quoted values. These may break the parsing logic in basic scripts. Keep secrets in plain KEY=value format.\n🚀 Usage Instructions Step 1: Prepare Your Script Copy the appropriate script (Bash or PowerShell) to a file Replace \u0026quot;username/reponame\u0026quot; with your repository name Ensure your .env.local file is in the same directory Step 2: Make the Script Executable (Bash only) chmod +x upload-secrets.sh Step 3: Run the Script # Bash ./upload-secrets.sh # PowerShell .\\upload-secrets.ps1 Step 4: Verify Upload Check your repository\u0026rsquo;s Settings → Secrets and variables → Actions to confirm all secrets were uploaded correctly.\nBest Practices 🔐 Security Considerations Never commit .env files: Add them to .gitignore Use different secrets per environment: Separate dev, staging, and production secrets Rotate secrets regularly: Update and re-upload secrets periodically Principle of least privilege: Only grant necessary access to secrets File Management Use descriptive names: Make secret names clear and consistent Document your secrets: Maintain documentation of what each secret does Environment-specific files: Use .env.development, .env.production, etc. Script Enhancements You can enhance these scripts by adding:\n# Add environment prefix gh secret set \u0026#34;${ENV_PREFIX}_${key}\u0026#34; --repo \u0026#34;$REPO\u0026#34; --body \u0026#34;$value\u0026#34; # Add validation if gh secret set \u0026#34;$key\u0026#34; --repo \u0026#34;$REPO\u0026#34; --body \u0026#34;$value\u0026#34;; then echo \u0026#34;✅ Successfully uploaded $key\u0026#34; else echo \u0026#34;❌ Failed to upload $key\u0026#34; fi # Add dry-run mode if [[ \u0026#34;$DRY_RUN\u0026#34; == \u0026#34;true\u0026#34; ]]; then echo \u0026#34;Would upload: $key\u0026#34; else gh secret set \u0026#34;$key\u0026#34; --repo \u0026#34;$REPO\u0026#34; --body \u0026#34;$value\u0026#34; fi 🧰 Advanced Use Cases\n# Upload to Multiple Repositories REPOS=(\u0026#34;org/repo1\u0026#34; \u0026#34;org/repo2\u0026#34;) for repo in \u0026#34;${REPOS[@]}\u0026#34;; do echo \u0026#34;📦 Uploading to $repo...\u0026#34; # Reuse upload logic here done # Environment-Aware Secret Files ENV=${1:-development} ENV_FILE=\u0026#34;.env.${ENV}\u0026#34; [[ ! -f \u0026#34;$ENV_FILE\u0026#34; ]] \u0026amp;\u0026amp; echo \u0026#34;Missing $ENV_FILE\u0026#34; \u0026amp;\u0026amp; exit 1 #CI/CD Workflow Integration (GitHub Actions) name: Upload Secrets on: workflow_dispatch: inputs: environment: description: \u0026#34;Target environment\u0026#34; default: \u0026#34;development\u0026#34; jobs: upload-secrets: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - run: | chmod +x ./scripts/upload-secrets.sh ./scripts/upload-secrets.sh ${{ github.event.inputs.environment }} Troubleshooting Common Issues Authentication Errors # Re-authenticate with GitHub CLI gh auth logout gh auth login Problem Solution Repo not found Double-check org/repo name Permission denied Ensure you’re an admin Invalid secret name Use only alphanumeric + _ Secrets \u0026gt;64KB Use Azure Key Vault or AWS Secrets Manager Conclusion Automating secret deployment to GitHub significantly improves your DevOps workflow by:\nReducing Manual Errors: Automated scripts eliminate typos and missed variables Saving Time: Bulk upload dozens of secrets in seconds Improving Security: Consistent, repeatable process reduces security gaps Enabling Scalability: Easy replication across multiple repositories and environments By implementing these bulk upload scripts, you\u0026rsquo;re taking a crucial step toward more secure, efficient, and maintainable DevOps practices. Remember to always follow security best practices and regularly audit your secret management processes.\nStart with the basic scripts provided, then customize them based on your specific needs. Your future self (and your team) will thank you for the time saved and improved security posture.\n","permalink":"https://dev.wellytonian.com/posts/devops/deploygithubsecrets/","summary":"Learn how to securely bulk upload environment variables and secrets to GitHub repositories using automated scripts for Bash and PowerShell. Protect your sensitive data while streamlining your DevOps workflow.","title":"Deploy Secrets to GitHub via Bulk Upload: Streamline Your DevOps Security"},{"content":"Introduction Microsoft has introduced Foundry Local, an on-device AI inference solution that offers performance, privacy, customization, and cost advantages. It integrates seamlessly into your existing workflows and applications through an intuitive CLI, SDK, and REST API.\nKey Features On-Device Inference: Run models locally on your own hardware, reducing costs while keeping all your data on your device. Model Customization: Select from preset models or use your own to meet specific requirements and use cases. Cost Efficiency: Eliminate recurring cloud service costs by using your existing hardware, making AI more accessible. Seamless Integration: Connect with your applications through an SDK, API endpoints, or the CLI, with easy scaling to Azure AI Foundry as your needs grow. High Level Architecture System Requirements Operating System: Windows 10 (x64), Windows 11 (x64/ARM), macOS. Hardware: Minimum 8GB RAM, 3GB free disk space. Recommended 16GB RAM, 15GB free disk space. Network: Internet connection for initial model download (optional for offline use) Acceleration (optional): NVIDIA GPU (2,000 series or newer), AMD GPU (6,000 series or newer), Qualcomm Snapdragon X Elite (8GB or more of memory), or Apple silicon. Deployment Windows winget install Microsoft.FoundryLocal MacOS brew tap microsoft/foundrylocal brew install foundrylocal Usage Search for all the commands that can be used currently Get a list of all the models that can be used Note : Screenshot is only showing a small subset of the models. There\u0026rsquo;s plenty more :)\nAs mentioned in the intro there are several ways to interact at this point, however for the sake of blog, I am going to show two :\nTerminal / Command Line Open WebUI Terminal Open WebUI Open your terminal and type the following command to find the service URL and PORT. foundry service status \\\\ Shows the port the service is running on However, in my testing, I have found that If you have a remote Open WebUI trying to call your Foundry Model , it has some COR\u0026rsquo;s issues which prevents the connection from happening. So I deployed the Open WebUI docker on the same machine that is running Azure AI Foundry local. Steps to get it working Once Open Web UI has been deployed , click on your name at the bottom left hand corner Click on Settings Click the \u0026lsquo;+\u0026rsquo; sign to add a new connection Based on the port that Foundry is using API and Prefix ID can be any random text - but definitely needs something , so dont leave it blank. Testing Open WebUI Open a new chat and the on the top , you should be able to drop down and see the available models from Foundry being displayed That\u0026rsquo;s it , you should now be able to chat with your model locally, pretty much without the need for Internet Summary Its ideal when:\nYou want to keep sensitive data on your device. You need to operate in environments with limited or no internet connectivity. You want to reduce cloud inference costs. You need low-latency AI responses for real-time applications. You want to experiment with AI models before deploying to a cloud environment. Wishes Ability to deploy like a docker container - Ollama / Hugging Face Ability to Edit the service connection - so can be setup in a headless server Ability to run multiple models at the same time - not super important. Pretty excited , so ya watch this space !\n","permalink":"https://dev.wellytonian.com/posts/ai/foundrylocal/","summary":"Explore how to run Azure AI models locally with Foundry Local—an on-device solution that prioritizes privacy, performance, and cost-efficiency.","title":"Running Azure AI Foundry Locally: A Hands-on Guide"},{"content":"Mastering .NET Installations with dotnet-install.sh - A Comprehensive Guide What is dotnet-install.sh? The dotnet-install.sh script is a powerful, feature-rich tool provided by Microsoft for installing .NET Core SDKs and runtimes across Linux and macOS environments. It\u0026rsquo;s designed for flexibility and automation, making it ideal for CI/CD pipelines and environments where traditional package managers might not be the best fit.\nKey Features of dotnet-install.sh Platform Detection get_current_os_name() { local uname=$(uname) if [ \u0026#34;$uname\u0026#34; = \u0026#34;Darwin\u0026#34; ]; then echo \u0026#34;osx\u0026#34; return 0 elif [ \u0026#34;$uname\u0026#34; = \u0026#34;FreeBSD\u0026#34; ]; then echo \u0026#34;freebsd\u0026#34; return 0 elif [ \u0026#34;$uname\u0026#34; = \u0026#34;Linux\u0026#34; ]; then # Detect specific Linux distributions local linux_platform_name=\u0026#34;\u0026#34; linux_platform_name=\u0026#34;$(get_linux_platform_name)\u0026#34; || true # Handle different scenarios like RHEL 6, musl-based distros # ... fi } The script automatically detects your operating system and architecture, ensuring you get the right binaries for your environment.\nFlexible Installation Options Version Control: Install specific versions, latest releases, or channel-based releases (LTS/STS) Runtime Selection: Choose between SDK, .NET Runtime, or ASP.NET Core Runtime Quality Tiers: Select from daily, signed, validated, or preview builds Architecture Support: x64, arm, arm64, s390x, ppc64le, and loongarch64 Headless Operation # No user interaction needed ./dotnet-install.sh --version 8.0.101 --install-dir ~/dotnet The script is designed for non-interactive environments, making it perfect for automation.\nNo Administrator Rights Required Unlike package managers that often require sudo privileges, dotnet-install.sh installs to user directories by default.\nMultiple Version Support The script allows multiple versions to coexist, enabling testing across different .NET versions.\nHow It Works Version Resolution The script has a sophisticated version resolution system that:\nChecks for explicit versions specified by command line Resolves \u0026ldquo;latest\u0026rdquo; using channel information Reads from global.json if specified Falls back to LTS versions when no version is specified Download Process The script uses a multi-tiered approach to downloads:\ngenerate_download_links() { # Try aka.ms links first generate_akams_links || return # Fall back to other feeds if needed if [[ \u0026#34;${#download_links[@]}\u0026#34; -lt 1 ]]; then for feed in ${feeds[@]} do generate_regular_links $feed || return done fi } First attempts to use Microsoft\u0026rsquo;s aka.ms URL shortening service Falls back to direct Azure feeds if necessary Supports both curl and wget for downloads Validates downloaded packages to ensure integrity Installation After downloading, the script:\nExtracts the package to the specified installation directory Preserves existing non-versioned files if requested Verifies that the installed version matches the expected version Updates PATH if requested Common Usage Examples Install Latest LTS SDK ./dotnet-install.sh Install Specific SDK Version ./dotnet-install.sh --version 8.0.101 Install ASP.NET Core Runtime Only ./dotnet-install.sh --runtime aspnetcore Install to Custom Location ./dotnet-install.sh --install-dir /opt/dotnet Install Preview Version ./dotnet-install.sh --channel 9.0 --quality preview Dry Run (Display Download URLs) ./dotnet-install.sh --version 8.0.100 --dry-run Integration with DevOps Workflows Docker Containerization FROM ubuntu:22.04 WORKDIR /app # Download and run the installer ADD https://dot.net/v1/dotnet-install.sh ./dotnet-install.sh RUN chmod +x ./dotnet-install.sh \u0026amp;\u0026amp; \\ ./dotnet-install.sh --version 8.0.101 \u0026amp;\u0026amp; \\ ln -sf /root/.dotnet/dotnet /usr/bin/dotnet # Build and run application COPY . . RUN dotnet publish -c Release -o out ENTRYPOINT [\u0026#34;dotnet\u0026#34;, \u0026#34;out/MyApp.dll\u0026#34;] CI/CD Pipelines # GitHub Actions workflow example steps: - name: Setup .NET run: | curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --version 8.0.101 echo \u0026#34;$HOME/.dotnet\u0026#34; \u0026gt;\u0026gt; $GITHUB_PATH Advanced Scenarios Air-gapped Environments For environments without internet access:\nDownload the script and desired .NET packages on a connected machine Transfer to the air-gapped environment Use --zip-path to specify the pre-downloaded archive Version Management Use the script alongside the .NET CLI\u0026rsquo;s global.json support:\n# Create a global.json with specific SDK version dotnet new globaljson --sdk-version 8.0.101 # Install the version specified in global.json ./dotnet-install.sh --jsonfile global.json Conclusion The dotnet-install.sh script is a testament to Microsoft\u0026rsquo;s commitment to flexibility and cross-platform support for .NET developers. By understanding how to use this powerful tool, you can create more reliable build processes, consistent development environments, and streamlined deployment pipelines across diverse environments.\nWhether you\u0026rsquo;re managing CI/CD pipelines, containerizing applications, or need specific versions for development, dotnet-install.sh provides the control and flexibility needed for modern .NET development workflows.\n","permalink":"https://dev.wellytonian.com/posts/devops/deployingdotnet/","summary":"This is a summary for this post to be displayed.","title":"Deployingdotnet"},{"content":"Automate Scaling of Azure Container Apps Managing costs while ensuring optimal performance is a critical aspect of running applications in the cloud. Azure Container Apps provide a flexible and scalable way to deploy containerized applications, but without proper automation, costs can quickly spiral out of control.\nIn this guide, we will walk you through the process of creating an automation script to dynamically scale your Azure Container Apps based on business hours. By automating the scaling process, you can ensure that your container apps run with a minimum number of instances during business hours and scale down to zero after hours, thereby optimizing costs without compromising on performance.\nWhether you are a cloud engineer, a DevOps professional, or a developer looking to streamline your cloud operations, this guide will provide you with the necessary steps to implement cost-effective scaling for your Azure Container Apps. Let\u0026rsquo;s dive in and start automating!\nStep 1: Create an Azure Automation Account Go to the Azure portal. Search for \u0026ldquo;Automation Accounts\u0026rdquo; and create a new automation account. Step 2: Install or Update the Azure CLI Extension for Container Apps Before you can use the az containerapp commands, you need to ensure that the Azure CLI extension for Container Apps is installed and up to date.\nOpen your terminal.\nRun the following commands to install or update the extension:\n# Install the Azure CLI extension for Container Apps az extension add --name containerapp # Update the Azure CLI extension for Container Apps az extension update --name containerapp Step 3: Create Runbooks Runbook 1: Scale Up During Business Hours In the Automation Account, go to \u0026ldquo;Runbooks\u0026rdquo; and create a new runbook.\nChoose \u0026ldquo;PowerShell\u0026rdquo; as the runbook type.\nName the runbook ScaleUpRunbook.\nAdd the following PowerShell script:\n# PowerShell script to scale Azure Container Apps to min 1 and max 1 # Connect to Azure Connect-AzAccount -Identity # Define the resource group and container app names $resourceGroupName = \u0026#34;your-resource-group-name\u0026#34; $containerAppNames = @(\u0026#34;container-app-1\u0026#34;, \u0026#34;container-app-2\u0026#34;) # Add your container app names here # Scale each container app to min 1 and max 1 foreach ($appName in $containerAppNames) { Write-Output \u0026#34;Scaling container app to min 1 and max 1: $appName\u0026#34; az containerapp update --name $appName --resource-group $resourceGroupName --set properties.template.scale.minReplicas=1 properties.template.scale.maxReplicas=1 Write-Output \u0026#34;Scaled container app to min 1 and max 1: $appName\u0026#34; } Save and publish the runbook.\nRunbook 2: Scale Down After Hours In the Automation Account, go to \u0026ldquo;Runbooks\u0026rdquo; and create a new runbook.\nChoose \u0026ldquo;PowerShell\u0026rdquo; as the runbook type.\nName the runbook ScaleDownRunbook.\nAdd the following PowerShell script:\n# PowerShell script to scale Azure Container Apps to zero # Connect to Azure Connect-AzAccount -Identity # Define the resource group and container app names $resourceGroupName = \u0026#34;your-resource-group-name\u0026#34; $containerAppNames = @(\u0026#34;container-app-1\u0026#34;, \u0026#34;container-app-2\u0026#34;) # Add your container app names here # Scale each container app to zero foreach ($appName in $containerAppNames) { Write-Output \u0026#34;Scaling container app to zero: $appName\u0026#34; az containerapp update --name $appName --resource-group $resourceGroupName --set properties.template.scale.minReplicas=0 Write-Output \u0026#34;Scaled container app to zero: $appName\u0026#34; } Save and publish the runbook.\nStep 4: Create Schedules In the Automation Account, go to \u0026ldquo;Schedules\u0026rdquo; and create two new schedules: Business Hours Schedule: Set this schedule to run at the start of business hours (e.g., 8:00 AM). After Hours Schedule: Set this schedule to run at the end of business hours (e.g., 6:00 PM). Example Commands for Scheduling # Log in to Azure az login # Create a schedule for business hours az automation schedule create --automation-account-name \u0026lt;automation-account-name\u0026gt; --resource-group \u0026lt;resource-group-name\u0026gt; --name \u0026#34;BusinessHoursSchedule\u0026#34; --start-time \u0026#34;2025-02-14T08:00:00Z\u0026#34; --recurrence \u0026#34;Day\u0026#34; --interval 1 # Create a schedule for after hours az automation schedule create --automation-account-name \u0026lt;automation-account-name\u0026gt; --resource-group \u0026lt;resource-group-name\u0026gt; --name \u0026#34;AfterHoursSchedule\u0026#34; --start-time \u0026#34;2025-02-14T18:00:00Z\u0026#34; --recurrence \u0026#34;Day\u0026#34; --interval 1 # Link the schedules to the runbooks az automation runbook start --automation-account-name \u0026lt;automation-account-name\u0026gt; --resource-group \u0026lt;resource-group-name\u0026gt; --name \u0026#34;ScaleUpRunbook\u0026#34; --schedule-name \u0026#34;BusinessHoursSchedule\u0026#34; az automation runbook start --automation-account-name \u0026lt;automation-account-name\u0026gt; --resource-group \u0026lt;resource-group-name\u0026gt; --name \u0026#34;ScaleDownRunbook\u0026#34; --schedule-name \u0026#34;AfterHoursSchedule\u0026#34; Conclusion By following this guide, you have successfully set up automation to dynamically scale your Azure Container Apps based on business hours. This automation helps you optimize costs by ensuring that your container apps run with the necessary resources during peak hours and scale down to zero during off-hours. Implementing such automation not only saves costs but also ensures that your applications remain performant and responsive to user demands.\nI hope this guide has been helpful in streamlining your cloud operations. Happy automating and saving :) !\n","permalink":"https://dev.wellytonian.com/posts/cloud/containerappsautomaintain/","summary":"This guide will help with cost control of running Container Apps on Azure.","title":"Automation to Help Cost Control Container Apps"},{"content":"Introduction This post is to secure your SSH connection between systems. Instead of using password based authentication, which should not be enabled even in a dev or test environment, but rather to use your Public Key pair to safely authenticate your systems during SSH. This post is dedciated to Windows, however if you are looking for Linux.\nSetting the Stage For the sake of this post, I am going to assume two servers, Server 1 that I will address as control node and Server 2 that I will address as host node. This procedure can be scaled.\nAs you are all aware, as long as you know the username and password, you can ssh from server 1 to server 2. However, passwords should be avoided at all costs, as it is very common for these to be stolen and can lead to vulnerabilities and unauthorized access. To prevent this, you can leverage SSH using Public Key Pair, meaning Server 1 is able to authenticate and connect via SSH using Private and Public Key pairs. Security can be further enhanced using passphrases as well.\nImportant The most important part of this post, is the fact that the Private Key generated should never be shared anywhere.\nFoundation What is an SSH Key Pair? An SSH key pair is a secure access credential used in the Secure Shell (SSH) protocol. It relies on public key infrastructure (PKI) technology, which is the gold standard for digital identity authentication and encryption. The key pair consists of two related but asymmetric keys: a public key and a private key. Public Key and Private Key: Public Key: The public key is freely shared with any SSH server you want to connect to. It is used for encryption. When you connect to a remote server, your public key is sent to the server. The server uses it to encrypt messages that only you can decrypt. For example, if Bob wants to send you a secret message, he encrypts it using your public key. The public key ensures confidentiality. Private Key: The private key is kept secret and known only to you. It is used for decryption. When you receive an encrypted message from the server, you use your private key to decrypt it. The private key remains on your local system. Only you can decrypt messages encrypted with your public key. Private-key cryptography ensures that only authorized parties can read the original message. Deployment Once you\u0026rsquo;ve located a secure location for your private key, generate it using the following command (depending on your requirements and encrytption) ssh-keygen -t rsa -b 4096 -C \u0026#34;your_email@example.com\u0026#34; (must run your terminal as administrator). Your id_rsa and id_rsa.pub files will be placed under C:\\Users\\your_username\\ by default, otherwise you can choose to save them in a specific location, by appending the name of the key with the location.\nChoose not to save a passphrase , if you wish to. Now, we are ready to copy the \u0026lsquo;Public Key\u0026rsquo; over to the server that we would like to connect in the future using this SSH key pair. To do this via the terminal window itself and not using any other tools, complete the following steps.\ntype $env:USERPROFILE\\.ssh\\id_rsa.pub | ssh username@linux_server_ip \u0026#34;mkdir -p ~/.ssh \u0026amp;\u0026amp; cat \u0026gt;\u0026gt; ~/.ssh/authorized_keys\u0026#34; If you have saved your key\u0026rsquo;s in a custom location type LOCATION\\KEY.pub | ssh username@linux_server_ip \u0026#34;mkdir -p ~/.ssh \u0026amp;\u0026amp; cat \u0026gt;\u0026gt; ~/.ssh/authorized_keys\u0026#34; THis will prompt you to ssh into the server using password. Post this , using putty or tools like Termius, you would be now be able to login using SSH Key Pair. Enhance Security Disable Password Authentication: Edit the SSH configuration file on your Linux server (/etc/ssh/sshd_config): PasswordAuthentication no Restart the SSH service: sudo systemctl restart sshd Use Non-Default Port: Change the default SSH port (22) to a custom port in /etc/ssh/sshd_config: Port 2222 Remember to update your firewall rules accordingly. Summary Do not ever COPY your Private key onto a Public Repository - even if it is private ! There are some good strategies around backing up and protecting your private key - Password managers, Vaults, Key Vaults are some of the choices. Set up your SSH using Key Pair - you dont need to setup passwords. ","permalink":"https://dev.wellytonian.com/posts/devops/windowssecuressh/","summary":"This is a summary for this post Secure SSH using Key Pair From Windows.","title":"Windows Secure SSH"},{"content":"Introduction Customizing your Ubuntu server can significantly enhance your productivity and make server management more efficient. In this post, we\u0026rsquo;ll walk you through various steps to customize your Ubuntu server to suit your needs.\nCustomization Available from the Script Update and Upgrade the Server Install zsh \u0026amp; oh-my-zsh plus pokemon-colorscripts for tty Net-Tools Neofetch (Screenshot above) Would you be using it for Azure ? terraform bicep powershell nvim nodejs ansible Deploy Docker , Docker Compose If its a local install - you might want to setup a Local IP ? Modify Git Config? Deployment Clone the repo Github Repo Please READ the entire repo and see if it does not affect your systems. Browse to the folder and use any of the following: bash ubuservertemplate.sh \\\\ to deploy to an Ubunut Server / Desktop bash ubudockerimage.sh \\\\ Building / Developing a new Docker Image ? bash lxcinstaller.sh \\\\ Running proxmox / similar - use this to customize your Ubunut LXC image. All Custom Scripts are located here\nAll Shell Customizations are located here\nWill keep updating them!\n","permalink":"https://dev.wellytonian.com/posts/tools/customizefreshlinux/","summary":"This is a post to show how to customize your Ubunutu Server.","title":"Customize your Ubuntu Server"},{"content":"Automating Azure Container Image Cleanup Managing container images in Azure Container Registry (ACR) can become cumbersome over time, especially when old images accumulate. To maintain a clean and efficient registry, it\u0026rsquo;s essential to periodically remove outdated images. In this post, we\u0026rsquo;ll walk through writing a script to automatically delete container images older than 7 days.\nThis also helps Microsoft Cloud Defender to keep maintaining a vulnerability check on container images that actually matter, reducing noise and effort.\nPrerequisites Before we begin, ensure you have the following:\nAzure CLI installed and configured. Access to your Azure Container Registry. Basic knowledge of shell scripting. Step-by-Step Guide Step 1: List Images in ACR First, we need to list all the images in our Azure Container Registry. We can use the Azure CLI for this purpose.\naz acr repository list --name \u0026lt;your-acr-name\u0026gt; --output table Step 2: Filter Images Older Than 7 Days Next, we\u0026rsquo;ll filter out the images that are older than 7 days. We\u0026rsquo;ll use a combination of Azure CLI and shell scripting to achieve this.\nOption 1 #!/bin/bash ACR_NAME=\u0026lt;your-acr-name\u0026gt; REPOSITORIES=$(az acr repository list --name $ACR_NAME --output tsv) for REPO in $REPOSITORIES; do TAGS=$(az acr repository show-tags --name $ACR_NAME --repository $REPO --output tsv --orderby time_desc) for TAG in $TAGS; do CREATED_TIME=$(az acr repository show-manifests --name $ACR_NAME --repository $REPO --query \u0026#34;[?tags[0]==\u0026#39;$TAG\u0026#39;].timestamp\u0026#34; --output tsv) CREATED_DATE=$(date -d $CREATED_TIME +%s) CURRENT_DATE=$(date +%s) AGE=$(( (CURRENT_DATE - CREATED_DATE) / 86400 )) if [ $AGE -gt 7 ]; then echo \u0026#34;Deleting $REPO:$TAG (Age: $AGE days)\u0026#34; az acr repository delete --name $ACR_NAME --repository $REPO --tag $TAG --yes fi done done Option 2 If you would like to target a particular repository and also leave the last image behind during a clean up , run the following script. #!/bin/bash # Set the ACR name and login server ACR_NAME=ACR_NAME # Replace with your ACR name LOGIN_SERVER=${ACR_NAME}.azurecr.io # Set the repository name REPOSITORY_NAME=REPO_NAME # Replace with your repository name # Set the retention period (7 days) RETENTION_PERIOD=7 # Get the current date and time CURRENT_DATE=$(date +\u0026#34;%Y-%m-%dT%H:%M:%SZ\u0026#34;) # Calculate the date 7 days ago RETENTION_DATE=$(date -d \u0026#34;-$RETENTION_PERIOD days\u0026#34; +\u0026#34;%Y-%m-%dT%H:%M:%SZ\u0026#34;) # Get the list of images older than the retention period images=$(az acr manifest list-metadata --name $REPOSITORY_NAME --registry $ACR_NAME --orderby time_asc -o tsv --query \u0026#34;[?lastUpdateTime \u0026lt; \u0026#39;$RETENTION_DATE\u0026#39;].[digest, lastUpdateTime]\u0026#34;) # Delete the old images, except the last one count=0 while IFS=$\u0026#39;\\t\u0026#39; read -r digest lastUpdateTime; do ((count++)) if [ $count -eq $(echo \u0026#34;$images\u0026#34; | wc -l) ]; then echo \u0026#34;Skipping deletion of last image: $REPOSITORY_NAME@$digest\u0026#34; else tags=$(az acr repository show-tags -n $ACR_NAME --repository $REPOSITORY_NAME --filter $digest --query \u0026#34;[].name\u0026#34;) if [ -n \u0026#34;$tags\u0026#34; ]; then echo \u0026#34;Deleting image: $REPOSITORY_NAME@$digest with tags: $tags\u0026#34; else echo \u0026#34;Deleting image: $REPOSITORY_NAME@$digest (no tags)\u0026#34; fi az acr repository delete -n $ACR_NAME --image $REPOSITORY_NAME@$digest --yes fi done \u0026lt;\u0026lt;\u0026lt; \u0026#34;$images\u0026#34; Github Link\nStep 3: Automate the Script To ensure this script runs periodically, we can set up a cron job (on Linux) or a scheduled task (on Windows).\nAutomation On Linux: Open the crontab editor:\ncrontab -e Add the following line to run the script daily at midnight:\n0 0 * * * /path/to/your/script.sh Automation On Windows: Open Task Scheduler. Create a new task and set the trigger to daily. Set the action to run your script.\nConclusion By following these steps, you can automate the cleanup of old container images in your Azure Container Registry, ensuring your registry remains clean and efficient. Happy automating!\n","permalink":"https://dev.wellytonian.com/posts/cloud/acrmaintain/","summary":"Learn how to write a script to automatically clean up Azure Container Images older than 7 days.","title":"Automating Azure Container Registry Image Cleanup"},{"content":"Introduction This post is to secure your SSH connection between systems. Instead of using password based authentication, which should not be enabled even in a dev or test environment, but rather to use your Public Key pair to safely authenticate your systems during SSH.\nSetting the Stage For the sake of this post, I am going to assume two servers, Server 1 that I will address as control node and Server 2 that I will address as host node. This procedure can be scaled.\nAs you are all aware, as long as you know the username and password, you can ssh from server 1 to server 2. However, passwords should be avoided at all costs, as it is very common for these to be stolen and can lead to vulnerabilities and unauthorized access. To prevent this, you can leverage SSH using Public Key Pair, meaning Server 1 is able to authenticate and connect via SSH using Private and Public Key pairs. Security can be further enhanced using passphrases as well.\nImportant The most important part of this post, is the fact that the Private Key generated should never be shared anywhere.\nFoundation What is an SSH Key Pair? An SSH key pair is a secure access credential used in the Secure Shell (SSH) protocol. It relies on public key infrastructure (PKI) technology, which is the gold standard for digital identity authentication and encryption. The key pair consists of two related but asymmetric keys: a public key and a private key. Public Key and Private Key: Public Key: The public key is freely shared with any SSH server you want to connect to. It is used for encryption. When you connect to a remote server, your public key is sent to the server. The server uses it to encrypt messages that only you can decrypt. For example, if Bob wants to send you a secret message, he encrypts it using your public key. The public key ensures confidentiality. Private Key: The private key is kept secret and known only to you. It is used for decryption. When you receive an encrypted message from the server, you use your private key to decrypt it. The private key remains on your local system. Only you can decrypt messages encrypted with your public key. Private-key cryptography ensures that only authorized parties can read the original message. Deployment Once you\u0026rsquo;ve located a secure location for your private key, generate it using the following command (depending on your requirements and encrytption) ssh-keygen -m PEM -t rsa -b 2048 -C vmName -f LOCATION_TO_PRIVATE_KEY If you are building a new VM, let\u0026rsquo;s say on Azure - then you can follow this Lab to complete the build and testing your connection to the Linux VM. If you are going to connect to an existing VM or host node, then the next steps is to copy the public key over to the host node. This can also be achieved through the terminal, so that it ends up in the right location. ssh-copy-id -i LOCATION_TO_PUBLIC_KEY username@IP_OR_FQDN_HOST_NODE Connecting to your host node can be achieved using the following ssh -i LOCATION_TO_PRIVATE_KEY username@IP_OR_FQDN_HOST_NODE \u0026ldquo;Look Ma no password\u0026rdquo; :)\nIf you are using Windows then use Putty and Puttygen to achieve a similar outcome. Putty can be used to connect using your private key and puttygen can be used to create your Private and Public Key.\nEnhance Security Disable Password Authentication: Edit the SSH configuration file on your Linux server (/etc/ssh/sshd_config): PasswordAuthentication no Restart the SSH service: sudo systemctl restart sshd Use Non-Default Port: Change the default SSH port (22) to a custom port in /etc/ssh/sshd_config: Port 2222 Remember to update your firewall rules accordingly. Summary Do not ever COPY your Private key onto a Public Repository - even if it is private ! There are some good strategies around backing up and protecting your private key - Password managers, Vaults, Key Vaults are some of the choices. Set up your SSH using Key Pair - you dont need to setup passwords. ","permalink":"https://dev.wellytonian.com/posts/devops/linuxsecuressh/","summary":"This is a summary for this post that Secure SSH using Key Pair.","title":"Secure SSH on Linux"},{"content":"Introduction This post is part of a series of deep dives into the awesomeness that is Ansible. Ansible as a tool can be explained and configured in a few ways, but in its true form, it is a tool that can be used to complete frequent, repeatable tasks such as configuration, that need to be executed to achieve a pre-defined and controlled outcome. The destination, could be servers running Anywhere , Hypervisors and one of my favorites Network Devices.\nSetting up Ansible Control Node The brains of the operation is hosted on the Control Node. Depending on your particular use case, this could be On-prem or in the cloud. Key element to remember here, at least for repeating the steps in this post, is to have line of sight to your destination.\nFor a change, I am going to have my control node sit within my home lab on my proxmox server. The control node is going to be a vanilla Ubuntu Container running on my lab hypervisor. For this first post, my intention is to get the Ansible Control Node up and running. Provision two more additional Ubuntu Containers (Vanilla) Use Ansible to connect, provision Terraform, Bicep and Azure CLI onto those containers so that they can be used as Cloud Development Workstations. Installing Ansible on Ubuntu Installation is pretty straight forward\n# Install Ansible sudo apt-add-repository ppa:ansible/ansible sudo apt update sudo apt install ansible Confirm the installation has succeeded by running\nansible --version That\u0026rsquo;s it you have you first \u0026lsquo;Control Node\u0026rsquo; ready for some automation !!\nCreating Hosts Entry Host file tells your control node, all the destination devices / servers / nodes that Ansible needs to work with. In my case, the host file is located within /etc/ansible Screenshot 2 There are several ways to start grouping your host servers and we will look at more clever ways of doing the same as we go through the series. In my case, I am going to enter the \u0026lsquo;Local IP\u0026rsquo; of the two new Ubuntu Containers hosted on my proxmox server. Screenshot 3 Let\u0026rsquo;s do a quick check to see if we are able to reach those servers from Ansible via a simple ping Screenshot of the ping Brilliant you\u0026rsquo;ve now got a control node that is just about ready to do some automation magic on these two host machines. Building your first Ansible Playbook An ansible playbook, is as the name suggests a step by step instruction for Ansible to do a set of executions, configurations, updates ( whatever you would do on those hosts manually).\nFor our first playbook, we are going to keep it simple and setup it up to do some initial updates and patches. Once completed, we are going to execute a bash script that installs Terraform, Bicep and Azure CLI.\nSave the following ctsetup.sh script in the same folder /etc/ansible\n# Install oh-my-zsh sudo apt install zsh -y sudo sh -c \u0026#34;$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\u0026#34; echo \u0026#34;Oh-My-Zsh has been installed!\u0026#34; Our objective is to get the Oh-my-zsh script executed on our freshly minted Containers.\nNow save the following script ctsetupviaansible.yml in the same folder as well /etc/ansible.\n--- hosts: all strategy: debug become: false tasks: - name: Update all host/vm packages ansible.builtin.apt: update_cache: true cache_valid_time: 3600 name: \u0026#34;*\u0026#34; state: latest - name: Copy ctsetup script ansible.builtin.copy: src: ctsetup.sh dest: ctsetup.sh mode: 0770 - name: Run ctsetup.sh command: bash ctsetup.sh This is a very basic Ansible Playbook to get you started\nWithin Tasks, the playbook tries to do the following: Update the host first Copy ctsetup.sh script over to the host machine. This would result in the file being copied to home directory of the user. It then runs ctsetup.sh as the connected user. Ansible achieves all this via SSH. So this goes back to our line of sight between the control node and the host (which is where we can get creative). Building the Ansible Configuration File We are just about ready to execute on Ansible, but we need to get our Ansible Configuration File ready. This requires a \u0026lsquo;few\u0026rsquo; posts to go through, however let\u0026rsquo;s get a basic config file going to start off with and tweak it as we go along.\nIf you head down to official github for Ansible here and grab the content and save it as ansible.cfg within /etc/ansible.\nThere are lot of options here, but the only one we are going to edit / uncomment is this line \u0026lsquo;SSH key host checking\u0026rsquo;\n# uncomment this to disable SSH key host checking # host_key_checking = False to\n# uncomment this to disable SSH key host checking host_key_checking = False ","permalink":"https://dev.wellytonian.com/posts/devops/ansiblepart1/","summary":"This is a summary for this post that is Part 1 of an Ansible Series.","title":"Ansible Series Part 1"},{"content":"Introduction This post is to share a quick and secure way of connecting Github to your Azure Tenancy. Once connected, Github Actions workflows can deploy onto Azure in a seamless and secure manner. There are quite a few ways to connect and they are well documented. However I wanted to share a script that can be used to create a Service Principal on Azure Entra ID and then go onto build a federated credential.\nBuilding the Service Principal Azure Login Let\u0026rsquo;s quickly build a service principal on Entra ID. First and foremost, from your terminal of choice, let\u0026rsquo;s connect to your Azure tenant. For the sake of simplicity, I am going to take the approach of device login - since it would prompt for you to copy the code and login via browser ( This method can be used on a variety of OS\u0026rsquo;s / Devices)\naz login -use-device-login Copy the code that is displayed on the terminal and open a browser to browse to microsoft.com/devicelogin. To make the login seamless, you could open https://portal.azure.com on another tab and have it ready.\nType the code in the prompt and it should start the authentication process. This should complete the login process back in the terminal as well. Create Service Principal on Azure You can execute this part as single script from your terminal, once edited with your custom variables\n# Script to deploy Entra ID Service Principal $NAME_OF_APP = \u0026#34;NAME_OF_THE_SP\u0026#34; # Provide a custom name for SP app=$(az ad app create --display-name $NAME_OF_APP -o json) appId=$(echo $app | jq -r \u0026#39;.appId\u0026#39;) objectId=$(echo $app | jq -r \u0026#39;.id\u0026#39;) sp=$(az ad sp create --id $appId -o json) assigneeObjectId=$(echo $sp | jq -r \u0026#39;.id\u0026#39;) # Creating the Federated Credentials credentialName=github-deploy # Give a Unique Name for the Credential subject=repo:GITHUB_REPO_NAME/NAME_GITHUB_ORGANIZATION.github.io:environment:NAME_OF_GITHUB_BRANCH az rest --method POST --uri \u0026#34;https://graph.microsoft.com/beta/applications/$objectId/federatedIdentityCredentials\u0026#34; --body \u0026#34;{\\\u0026#34;name\\\u0026#34;:\\\u0026#34;$credentialName\\\u0026#34;,\\\u0026#34;issuer\\\u0026#34;:\\\u0026#34;https://token.actions.githubusercontent.com\\\u0026#34;,\\\u0026#34;subject\\\u0026#34;:\\\u0026#34;repo:organization/repository:environment:main\\\u0026#34;,\\\u0026#34;description\\\u0026#34;:\\\u0026#34;Deploy from GitHub Actions\\\u0026#34;,\\\u0026#34;audiences\\\u0026#34;:[\\\u0026#34;api://AzureADTokenExchange\\\u0026#34;]}\u0026#34; Let\u0026rsquo;s breakdown what is happening with this script:\nFirst we create a service principal on Entra ID Then within that SP, we are creating a Federated Credential with details of your gitub repository, github organization and name of the branch that is allowed to execute. You can also edit some of the variables in here as well. Copy the Client ID , Tenant ID from the overview page for your Service Principal. You could also get the Subscription ID at this point for the next steps. Note\nEnsure that you use your Service Principal to have the right permissions and access at a Management Group / Subscription / Resource Group or Resource Level !\nConnecting with Github Browse to your github repository Secrets and Variables sections to add some secrets as shown below. This is available at https://github.com/ORG_NAME/REPO_NAME/settings/secrets/actions Enter the secrets for AZURE_CLIENT_ID, AZURE_SUBSCRIPTION_ID,AZURE_TENANT_ID ( you can use any variable name as long as the secrets are copied properly)\nLet\u0026rsquo;s tweak your github actions workflow. Below is a sample code, that logs onto azure using the Repository Secrets from the last step and displays Resource Groups that are hosted within this subscription\nname: azure_github_deployment_pipeline on: [push] permissions: id-token: write contents: read jobs: build-and-deploy: runs-on: ubuntu-latest steps: - name: \u0026#39;Az CLI login\u0026#39; uses: azure/login@v1 with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - name: \u0026#39;Run Azure CLI commands\u0026#39; run: | az account show az group list pwd Next Steps: That\u0026rsquo;s pretty much it. This can also be achieved by creating a secret token for the SP. However this would mean expiring tokens. The Github Workflow can be used to do a lot more within your Azure tenant. For example, if you want the deployment across multiple Subscriptions, you can get more Subscription ID\u0026rsquo;s within your repository secrets and execute against them. ","permalink":"https://dev.wellytonian.com/posts/cloud/azwtgithub/","summary":"This is a summary for this post on connecting Github Actions to Azure.","title":"Connecting Azure with Github Actions"},{"content":"Introduction This is part 2 of the series on publishing a Hugo Website on Azure.\nPart 1 - Building your Hugo Website Locally\nPart 2 - Publishing to Github and Azure SWA\nVersion Control to Github Now that the first post is ready, I want to version control my website. For the sake of this example I am using github, but you can use any. I am going to use VSCode with some extentions. Github Azure The next steps assume, that you\u0026rsquo;ve logged onto Github and Azure from VScode or atleast on the browser as the sync process will initiate the authentications. The following screenshots show how to publish this to github. Depending on your use case, you could choose to use Private or Public Repository. Once the first commit has been made to Github, we want this site now published to Azure Static Websites. Publishing to Azure The following screenshots show how to publish this to Azure. Depending on your use case, choose between Free and Standard. If you wish to put this website behind an auth provider like Entra ID or Github ( Internal Consumption) then choose Standard Choose Hugo In a matter of minutes, your website should now be completely published to Azure There should be a new folder within your repository called .github/workflows. This stores the workflow that publishes your repository (upon any change) to Azure SWA. The actions tab will always display all the latest runs of the workflow Open Azure Static Webpages and browse to your new website and click on the URL displayed. Welcome to your new and shiny Hugo Website running on Azure Let\u0026rsquo;s confirm the workflow is working properly. Let\u0026rsquo;s create a new post as shown below Let\u0026rsquo;s edit the post I am going to commit the changes via the terminal or via VSCode using Push \u0026amp; Sync Workflow on Github kicked off and ran properly And our second post is live now on our website You can always tweak if your posts should be in draft state and not be visible from both hugo.yaml and your blog post config itself. What\u0026rsquo;s next? Start tweaking your Hugo.yaml to get Search Navigation - add an about me page or projects Fix Base URL Or try a new theme all together :) Well if you would like to customize a little bit, go and get yourself a domain name. Within your domain registrar, set up a DNS CName pointed to your new SWA. Free version of SWA allows for custom domain name - so its completely free to host and publish your website. You only pay for your Annual Domain Registration. ","permalink":"https://dev.wellytonian.com/posts/cloud/hugoonazurepart2/","summary":"This is a post to help deploy a Hugo Website on Azure.","title":"Hugo Website on Azure - Part 2"},{"content":"You can contact us here!\nName\rE-mail address\rMessage\rSend\r(Powered by Un-static Forms)\n","permalink":"https://dev.wellytonian.com/contact/","summary":"\u003cp\u003eYou can contact us here!\u003c/p\u003e\n\u003cform method=\"post\" action=\"https://forms.un-static.com/forms/63ee4874681fbbf988d4d88ff73dfcf63e8fdbc9\"\u003e\r\n  \u003cdiv class=\"form-group row\"\u003e\r\n    \u003clabel for=\"name\" class=\"col-4 col-form-label\"\u003eName\u003c/label\u003e\r\n    \u003cdiv class=\"col-8\"\u003e\r\n      \u003cdiv class=\"input-group\"\u003e\r\n        \u003cdiv class=\"input-group-addon\"\u003e\r\n          \u003ci class=\"fa fa-user\"\u003e\u003c/i\u003e\r\n        \u003c/div\u003e\r\n        \u003cinput id=\"name\" name=\"name\" placeholder=\"Please enter your name\" type=\"text\" required=\"required\" class=\"form-control\"\u003e\r\n      \u003c/div\u003e\r\n    \u003c/div\u003e\r\n  \u003c/div\u003e\r\n  \u003cdiv class=\"form-group row\"\u003e\r\n    \u003clabel for=\"email\" class=\"col-4 col-form-label\"\u003eE-mail address\u003c/label\u003e\r\n    \u003cdiv class=\"col-8\"\u003e\r\n      \u003cdiv class=\"input-group\"\u003e\r\n        \u003cdiv class=\"input-group-addon\"\u003e\r\n          \u003ci class=\"fa fa-envelope\"\u003e\u003c/i\u003e\r\n        \u003c/div\u003e\r\n        \u003cinput id=\"email\" name=\"email\" placeholder=\"Your e-mail address\" type=\"text\" required=\"required\" class=\"form-control\"\u003e\r\n      \u003c/div\u003e\r\n    \u003c/div\u003e\r\n  \u003c/div\u003e\r\n  \u003cdiv class=\"form-group row\"\u003e\r\n    \u003clabel for=\"message\" class=\"col-4 col-form-label\"\u003eMessage\u003c/label\u003e\r\n    \u003cdiv class=\"col-8\"\u003e\r\n      \u003ctextarea id=\"message\" name=\"message\" cols=\"40\" rows=\"10\" required=\"required\" class=\"form-control\"\u003e\u003c/textarea\u003e\r\n    \u003c/div\u003e\r\n  \u003c/div\u003e\r\n  \u003cdiv class=\"form-group row\"\u003e\r\n    \u003cdiv class=\"offset-4 col-8\"\u003e\r\n      \u003cbutton name=\"submit\" type=\"submit\" class=\"btn btn-primary\"\u003eSend\u003c/button\u003e\r\n    \u003c/div\u003e\r\n  \u003c/div\u003e\r\n  \u003cdiv class=\"text-center\"\u003e\r\n    \u003cp\u003e\u003csmall\u003e(Powered by \u003ca rel=\"nofollow\" href=\"Un-static Forms\"\u003eUn-static Forms\u003c/a\u003e)\u003c/small\u003e\u003c/p\u003e\r\n  \u003c/div\u003e\r\n\u003c/form\u003e","title":"Contact"},{"content":"Introduction I used to be a wordpress fan. I had a lot of plugins to do a lot of things (that I thought I needed). However Static Web Sites (SWA) has made me a convert. Its simple, I can write from my fav IDE or for that matter any device and version control my posts and website configuration. I think the freedom it gives in not being dependent on 3rd party plugins - is a game changer for me personally. There are a few flavours to choose from, however today I am with Hugo. I wanted to share my experience for the past month a bit that I have spent getting it to work on Azure.\nI have split this into two posts / parts.\nPart 1 - Building your Hugo Website Locally\nPart 2 - Publishing to Github and Azure SWA\nHugo Build Locally Linux Deployment Installation of Hugo on your development box can be completed in the following manner\nhttps://github.com/gohugoio/hugo/releases \\\\ get the latest version of hugo wget https://github.com/gohugoio/hugo/releases/download/v0.122.0/hugo_0.122.0_linux-amd64.deb sudo dpkg - i hugo_0.122.0_linux-amd64.deb Windows Deployment Installation of Hugo on your development box can be completed in the following manner \\\\ Using Winget winget install Hugo.Hugo.Extended \\\\ Using Chocolate choco install hugo-extended Website Deployment Post installation choose the location for hosting your files.\nhugo new site MyFreshWebsite --format yaml # replace MyFreshWebsite with name of your website cd MyFreshWebsite git init git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod git submodule update --init --recursive # needed when you reclone your repo (submodules may not get cloned automatically) git submodule update --remote --merge Now that you\u0026rsquo;ve got the hugo platform build within the folder, browse into it and let\u0026rsquo;s start tweaking by opening hugo.yaml on your fav editor.\nbaseURL: https://example.org/ languageCode: en-us title: My New Hugo Site theme: [\u0026#34;PaperMod\u0026#34;] You can now choose to run the following commands to get a feel for the website\nhugo -D \\\\ if you have any drafts in the content - it would build those as well hugo serve \\\\ will server the website using localhost and a port Yay ! You have a working Hugo Website. There are plenty of Themes to choose from. Based on your requirements try a few and see which one appeals to you. First Blog Post Let\u0026rsquo;s now get cracking with creating your first post. So posts are stored under the content folder within your hugo website. To create your first post, using the default post template (look inside archetypes to make new ones) hugo new posts/NameOfTheNewPost.md The new post (Markdown file) will now show up within the content folder. Edit your blog post from your fav IDE Some small tweaks to add some navigation to our website Edit hugo.yaml with the following code. This is engine of your website. There is so much to tweak and get the best out of hugo from here. This is just a base config to get you going. --- baseURL: https://example.org/ languageCode: en-us title: My New Hugo Site theme: [\u0026#34;PaperMod\u0026#34;] paginate: 4 defaultContentLanguage: en enableRobotsTXT: true buildDrafts: true # minify: disableXML: true minifyOutput: true outputs: home: - HTML - RSS - JSON # necessary for search menu: main: - identifier: home name: home url: / weight: 1 - identifier: posts name: posts url: /posts/ weight: 3 Let\u0026rsquo;s get a preview of our website locally, before we are ready to publish this to the world! Part 2 - Publishing to Github and Azure SWA\n","permalink":"https://dev.wellytonian.com/posts/cloud/hugoonazure/","summary":"This is a post to help deploy a Hugo Website on Azure.","title":"Hugo Website on Azure - Part 1"},{"content":"Introduction Terraform as a Infrastructure as Code tool is incredibly powerful. However, time and time again, I have seen environments, drift away from being completely built via code, to either being built via GUI or code that is not part of version control like its predecessors. This is usually code that has been executed from someone\u0026rsquo;s laptop.\nConsequences are many, but to highlight a key issue - if attempting to run the source code, we get the dreaded state file not having the current information. This creates unwanted wastage of time and resources to match the Terraform with the current state of your infrastructure platform.\nHow Download the latest version of aztfexport from below https://github.com/Azure/aztfexport # can be used to find the source and the installers for your OS. On windows , you can use winget to get it installed quickly Before executing aztfexport please ensure you are in the right working directory. If this is your first export of a particular resource, it is recommended to start in an empty directory. The screenshot below assumes that you\u0026rsquo;ve used az login to login to azure. Post login do not forget to set the subscription to the desired subscription. Once logged in , you can use the following command to begin the export aztfexport resource-group NAME_OF_THE_RESOURCE_GROUP This should begin the export of the resources targetted against that particular resource group. You can also choose to export a particular resource contained within a resource group as well. The first step post export is that aztfexport will now display all the resources that it has managed to export. Use your Left and Right arrow key to browse through the various exports In this example, I have exported a resource group that contains an NSG with about 24 NSG rules and a Virtual Network with 2 subnets. Press \u0026lsquo;w\u0026rsquo; to start the import process. The process has a dashboard (sort off) that displays progress and the type of resource being exported. Successful export will display the message with a link to the working folder. A quick look into the folder displays the various files that are now occupying an empty directory that we started with. main.tf - contains the terraform resource files for the various resources - resource group, nsg rules, nsg etc. terraform.tfstate - contains the state file which would be populated with the imported resources. Later in this post, the tfstate file is updated with new resources that did not exist during the first import. Let\u0026rsquo;s confirm that all resources / services have been imported onto that folder. During a terraform plan execution, Terraform would go and compare the state file to your existing cloud deployment. In our case, as it is just after an export, no changes are expected. Let\u0026rsquo;s say post export, we need a new subnet. Instead of doing the change from the GUI, add the resource onto the main.tf file as show below A new terraform plan will display the change that is being asked to be completed. terraform apply will begin the implementation of \u0026lsquo;said\u0026rsquo; changes As per the requested change, a new \u0026lsquo;cache-sub\u0026rsquo; is added to the existing Virtual Network. What\u0026rsquo;s next ? Move the terraform code base to your existing pipeline / or build a new pipeline to maintain these services going forward. Move the terraform state file to either azure blog storage or use terraform cloud to maintain your state file going forward. Future changes are implemented through the your \u0026rsquo;now\u0026rsquo; mature devops practices and methods. Stop \u0026lsquo;folks\u0026rsquo; from having GUI access for their day today operations. Keep it \u0026lsquo;read\u0026rsquo; only. Why ? Super powerful and very simple to use. Get your drifts in control and bring back code compliance. Build something from the GUI and then being able to import it into code for repeatability and ongoing code based deployment. Bicep to Terraform - should you :) ? ","permalink":"https://dev.wellytonian.com/posts/cloud/tfexportdev/","summary":"This post shows how to export existing Azure Resources back into Terraform","title":"Building Terraform Code from Existing Azure Services"},{"content":"Welcome to Wellytonian.com! Thank you for visiting my blog. I hope you find the articles here insightful and engaging.\nA Bit of History This is version 2 of the Wellytonian Blog. The name is a nod to my time living in Wellington, NZ, where I first started blogging back in 2009. However, around 2017, when I became a father, I had to step back from much of the community work I was involved in, including blogging, meetups, and the Azure Global Bootcamp, to focus on my new role.\nThe Phoenix Rises Now, having recently become a dad for the second time and feeling more settled in my parental responsibilities, I\u0026rsquo;m eager to re-engage with the community. The first step in this journey is rebuilding the blog from the ground up. Out goes WordPress and its myriad plugins that kept the old site alive, and in comes a static website, namely Hugo.\nWhat to Expect Over the past 11 years (as of Feb 2024), I\u0026rsquo;ve immersed myself in the Cloud Space, starting with engineering, building cloud practices, and helping customers with their cloud journey and maturity. Despite the years of experience, I still encounter something new almost every day. In the fast-paced world of IT, if you\u0026rsquo;re not pushing the boundaries regularly, you risk getting left behind. This blog is my platform to share my personal journey in this ever-evolving field.\nRoadmap Regular, insightful posts. Newsletter Contact Me Page Website Improvements: Ability to comment on posts. Enhanced analytics. Addressing theme issues. Contact me through some of the channels - love to hear from you !\nTwitter\nLinkedIn\nFeb 2024\nDisclaimer: Before you continue: I take no responsibility for wrongly configured services, exposed personal data or incorrect setup causing data-loss. I wrote these posts as a good deed, to help whoever who needed help and as documentation for myself.\nI strongly recommend you go through the commands, the configuration and audit that there are no dangerous mistakes or changes happening.\n","permalink":"https://dev.wellytonian.com/about/","summary":"\u003ch1 id=\"welcome-to-wellytoniancom\"\u003eWelcome to Wellytonian.com!\u003c/h1\u003e\n\u003cp\u003eThank you for visiting my blog. I hope you find the articles here insightful and engaging.\u003c/p\u003e\n\u003ch2 id=\"a-bit-of-history\"\u003eA Bit of History\u003c/h2\u003e\n\u003cp\u003eThis is version 2 of the Wellytonian Blog. The name is a nod to my time living in Wellington, NZ, where I first started blogging back in 2009. However, around 2017, when I became a father, I had to step back from much of the community work I was involved in, including blogging, meetups, and the Azure Global Bootcamp, to focus on my new role.\u003c/p\u003e","title":""},{"content":"AI agents generate code faster than humans can review it. That’s a problem.\nWe’ve all seen the promise: “10x developer velocity with AI.” But when a whole team uses agents to sprint, you don’t just get 10x features—you get 10x integration chaos.\nThe Concurrency Paradox is real: as velocity increases, coordination costs skyrocket. Without guardrails, agentic development becomes a “denial‑of‑service” attack on your own main branch.\nWe’re moving from “agile chaos” to Spec‑Driven Development (SDD). It’s the only way to put guardrails on agentic speed.\nHere are the 3 pillars:\n1️⃣ The Spec is the Prompt Agents are stochastic. Without a clear spec, three agents will build the same feature three different ways. Treat the spec as a contract and prompt context to constrain the solution space before code is generated.\n2️⃣ Aggressive Synchronization Agents don’t feel merge‑conflict pain—you do. Mandate a daily rebase ritual. Trade weekly “hallucinated merge conflicts” for small daily syncs.\n3️⃣ Strict Architectural Zoning Agents don’t know that utils/helpers.ts is shared by multiple teams—they just see a file to change. Enforce strict module ownership to prevent changes outside designated zones.\nThe secret to agentic engineering isn’t just speed—it’s control.\nWant the deeper dive? Read the full post: The Concurrency Paradox\n#SoftwareEngineering #DevOps #AI #AgenticWorkflow #SpecDrivenDevelopment #EngineeringManagement #CTO\n","permalink":"https://dev.wellytonian.com/posts/linkedin/linkedin-post-spec-driven-dev/","summary":"\u003cp\u003e\u003cstrong\u003eAI agents generate code faster than humans can review it. That’s a problem.\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eWe’ve all seen the promise: “10x developer velocity with AI.” But when a whole team uses agents to sprint, you don’t just get 10x features—you get 10x integration chaos.\u003c/p\u003e\n\u003cp\u003eThe \u003cstrong\u003eConcurrency Paradox\u003c/strong\u003e is real: as velocity increases, coordination costs skyrocket. Without guardrails, agentic development becomes a “denial‑of‑service” attack on your own main branch.\u003c/p\u003e\n\u003cp\u003eWe’re moving from “agile chaos” to \u003cstrong\u003eSpec‑Driven Development (SDD)\u003c/strong\u003e. It’s the only way to put guardrails on agentic speed.\u003c/p\u003e","title":""}]