<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Tosin Amuda — Blog</title>
  <subtitle>Software Engineer, Product Engineer, and AI Engineer building digital products and practical technical writing.</subtitle>
  <link rel="self" type="application/atom+xml" href="https://www.tosinamuda.com/feed.xml" />
  <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/" />
  <id>https://www.tosinamuda.com/</id>
  <updated>2026-05-13T05:12:43.040Z</updated>
  <author><name>Tosin Amuda</name></author>
  <entry>
    <title>How the Global South Can Enter the AI Value Chain: Nigeria’s Case</title>
    <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/how-the-global-south-can-enter-the-ai-value-chain-nigerias-case.html" />
    <id>https://www.tosinamuda.com/blog/how-the-global-south-can-enter-the-ai-value-chain-nigerias-case.html</id>
    <updated>2026-05-13T00:00:00.000Z</updated>
    <published>2026-05-13T00:00:00.000Z</published>
    <summary>A Nigeria-focused strategy for entering the AI value chain through open-source models, local data, talent, compute, and diaspora transfer.</summary>
    <content type="html">&lt;p&gt;A Nigeria-focused strategy for entering the AI value chain through open-source models, local data, talent, compute, and diaspora transfer.&lt;/p&gt;&lt;p&gt;I will answer from Nigeria&apos;s perspective, though the same logic applies to countries with similar constraints: limited frontier AI capital, shallow advanced research depth, and large populations entering an AI-shaped labour market. Nigeria&apos;s AI strategy should be value-chain entry. The country should build the layers of the AI economy it can realistically own now, then use them to move upstream over time.&lt;/p&gt;

&lt;p&gt;The first reachable layer is open-source and small-model capability. With open-weight models, Nigerian teams can fine-tune, compress, evaluate, and serve useful systems without frontier-scale compute. Around that layer, Nigeria should build local datasets, evaluation benchmarks, applied AI talent, targeted compute, and diaspora knowledge transfer. The goal is to become production-adjacent now and selectively productive over the decade.&lt;/p&gt;

&lt;h2 id=&quot;start-with-open-source-and-small-models&quot;&gt;&lt;a href=&quot;#start-with-open-source-and-small-models&quot; class=&quot;heading-link&quot;&gt;Start with open-source and small models&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Open-source and small models matter because they give countries outside the frontier a practical production surface. A frontier model may require capital, chips, electricity, and research density that Nigeria does not yet have. A small domain model requires a narrower but reachable stack: good task data, capable engineers, evaluation discipline, inference infrastructure, and enough compute for fine-tuning. That is where Nigeria can start producing capability rather than only watching the frontier move.&lt;/p&gt;

&lt;p&gt;The unit of progress should be concrete: a compressed speech model, a curriculum benchmark, a legal retrieval model, a Nigerian-language evaluation suite, a fine-tuned agricultural advisory model, or a low-cost inference service. Each artifact trains people, creates reusable infrastructure, and pushes the country further into the AI value chain.&lt;/p&gt;

&lt;h2 id=&quot;create-a-national-ai-value-chain-agenda&quot;&gt;&lt;a href=&quot;#create-a-national-ai-value-chain-agenda&quot; class=&quot;heading-link&quot;&gt;Create a National AI Value-Chain Agenda&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;The first move is a National AI Value-Chain Agenda. This should not be a broad digital transformation plan. It should map the specific layers where Nigeria can capture value: open-source model adaptation, small-model training, dataset creation, evaluation infrastructure, inference deployment, AI tooling, and applied research.&lt;/p&gt;

&lt;p&gt;The agenda should identify which institutions own each layer, how funding flows into them, and what measurable outputs count as progress. A National AI Adviser should coordinate ministries, universities, regulators, cloud providers, research institutes, and private builders, with legislation within the year so the structure survives electoral cycles.&lt;/p&gt;

&lt;h2 id=&quot;fund-an-open-source-and-small-model-programme&quot;&gt;&lt;a href=&quot;#fund-an-open-source-and-small-model-programme&quot; class=&quot;heading-link&quot;&gt;Fund an Open-Source and Small-Model Programme&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;The second move is an Open-Source and Small-Model Programme. Nigeria should support teams that can adapt open-weight models, compress them, evaluate them, and serve them cheaply under local infrastructure constraints. This is not a side project. It is the first production layer available to the country.&lt;/p&gt;

&lt;p&gt;The programme should fund model adaptation labs in universities, startup teams building narrow models, and public-interest projects that produce reusable tooling. Success should not be measured by announcements. It should be measured by released models, documented evaluations, lower inference costs, reproducible training pipelines, and engineers who can repeat the work.&lt;/p&gt;

&lt;h2 id=&quot;treat-data-and-evaluation-as-national-infrastructure&quot;&gt;&lt;a href=&quot;#treat-data-and-evaluation-as-national-infrastructure&quot; class=&quot;heading-link&quot;&gt;Treat data and evaluation as national infrastructure&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;The third move is a Nigerian Data and Evaluation Mission. Data and benchmarks are economic assets, not merely research inputs. Foreign labs have little incentive to curate Yoruba, Hausa, Igbo, Pidgin, and Nigerian English speech data at the quality Nigeria needs. They will not build serious benchmarks for Nigerian curricula, legal procedure, agricultural conditions, clinical workflows, or local administrative tasks unless there is commercial pressure to do so.&lt;/p&gt;

&lt;p&gt;Nigeria should therefore fund these datasets and benchmarks as national infrastructure. A country without local data cannot adapt models deeply. A country without local benchmarks cannot tell whether its systems work. A country with both can train, evaluate, negotiate, and build from a position of greater leverage.&lt;/p&gt;

&lt;h2 id=&quot;build-an-applied-ai-talent-pipeline&quot;&gt;&lt;a href=&quot;#build-an-applied-ai-talent-pipeline&quot; class=&quot;heading-link&quot;&gt;Build an applied AI talent pipeline&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;The fourth move is an Applied AI Talent Pipeline. Nigeria&apos;s short-term priority should be applied AI engineers and applied researchers: people who can fine-tune models, build retrieval systems, curate datasets, design evaluations, compress models, deploy inference, and monitor failure modes. This group is more urgent than a small number of frontier theorists because it builds the working base on which deeper research depends.&lt;/p&gt;

&lt;p&gt;In the medium term, universities should teach discipline-specific AI in fields where the technology will reshape professional work, including medicine, agriculture, education, law, finance, and engineering. In the long term, Nigeria needs PhD-level researchers in machine learning, optimisation, systems, safety, and model architecture. The order matters. Applied work creates the datasets, failures, research questions, and institutional demand that make serious doctoral research viable locally.&lt;/p&gt;

&lt;h2 id=&quot;negotiate-targeted-compute-access&quot;&gt;&lt;a href=&quot;#negotiate-targeted-compute-access&quot; class=&quot;heading-link&quot;&gt;Negotiate targeted compute access&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;The fifth move is targeted compute access. Nigeria should not begin by trying to match hyperscale training clusters. It needs compute for inference, fine-tuning, evaluation, synthetic data generation, and small-model training. The immediate step is to negotiate cloud credit pools with major cloud providers for accredited researchers, startups, and public-interest teams.&lt;/p&gt;

&lt;p&gt;In parallel, Nigeria should build one reliable, independently powered GPU cluster at a federal university or national research centre, sized for fine-tuning and inference rather than frontier pretraining. Over five years, that cluster can grow into a small national research compute network, located only where power, fibre, cooling, security, and environmental conditions are credible.&lt;/p&gt;

&lt;h2 id=&quot;use-diaspora-knowledge-transfer-deliberately&quot;&gt;&lt;a href=&quot;#use-diaspora-knowledge-transfer-deliberately&quot; class=&quot;heading-link&quot;&gt;Use diaspora knowledge transfer deliberately&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;The sixth move is diaspora knowledge transfer. Nigerians working in frontier labs, cloud companies, AI startups, and research universities abroad are one of the country&apos;s fastest routes to frontier exposure. The mechanism should be practical: paid sabbaticals, remote mentorship, joint research, visiting residencies, and later repatriation offers tied to real authority, compute access, and funded teams.&lt;/p&gt;

&lt;p&gt;Symbolic homecoming campaigns will not matter if there is no serious infrastructure to join. Diaspora transfer should plug into the open-source programme, data mission, talent pipeline, and compute network.&lt;/p&gt;

&lt;h2 id=&quot;own-reachable-layers-then-climb&quot;&gt;&lt;a href=&quot;#own-reachable-layers-then-climb&quot; class=&quot;heading-link&quot;&gt;Own reachable layers, then climb&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Once these foundations compound, Nigeria can move from production-adjacent capability to selective production. A technically insulated National AI Agency could then coordinate strong small and domain-specific models in areas where Nigeria has data depth, engineering capacity, and sustained demand. Its job would not be to imitate OpenAI. Its job would be to own the parts of the stack where Nigeria can build advantage, then climb from there.&lt;/p&gt;

&lt;p&gt;Nigeria will not be sidestepped because it failed to build a frontier model in 2026. It will be sidestepped if it owns no layer of the AI economy: not the datasets, not the benchmarks, not the model adaptation labs, not the inference infrastructure, not the applied talent pipeline, and not the research institutions that turn today&apos;s tools into tomorrow&apos;s capability. The first task is to own the layers within reach. Then climb.&lt;/p&gt;

&lt;source-note id=&quot;origin-note&quot; heading=&quot;Origin note&quot;&gt;
  &lt;p&gt;This essay began with an &lt;a href=&quot;https://x.com/tosinamuda/status/1846446706100961512?s=20&quot;&gt;October 16, 2024 tweet&lt;/a&gt; where I argued for the baby steps Nigeria can take in AI R&amp;amp;D despite its power challenges.&lt;/p&gt;

  &lt;p&gt;In May 2026, I adapted that thought into an answer to one of the questions in Dwarkesh Patel&apos;s &lt;a href=&quot;https://www.dwarkesh.com/p/blog-prize&quot;&gt;Blog prize for the big questions about AI&lt;/a&gt;: what countries outside the AI production chain should do to avoid being sidestepped by transformative AI.&lt;/p&gt;
&lt;/source-note&gt;</content>
    <author><name>Tosin Amuda</name></author>
  </entry>
  <entry>
    <title>Building a Generative UI Agent for Bob, with Bob, by Bob</title>
    <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/building-a-generative-ui-agent-for-bob-with-bob-by-bob.html" />
    <id>https://www.tosinamuda.com/blog/building-a-generative-ui-agent-for-bob-with-bob-by-bob.html</id>
    <updated>2026-05-09T00:00:00.000Z</updated>
    <published>2026-05-09T00:00:00.000Z</published>
    <summary>How I built a task-specific harness around Bob that generated, bundled, and sandboxed live UI apps for IBM Think 2026.</summary>
    <content type="html">&lt;p&gt;How I built a task-specific harness around Bob that generated, bundled, and sandboxed live UI apps for IBM Think 2026.&lt;/p&gt;&lt;p&gt;At IBM Think 2026, a visitor could come up with an idea, watch Bob plan and write the code, and see the app running on the booth screen two minutes later. IBM had just unveiled Bob, its new coding agent, at the keynote, and the booth was where conference visitors got to try it. Bob is built for complex enterprise development, and my job was to demonstrate those capabilities inside a strict two-minute window.&lt;/p&gt;

    &lt;p&gt;To deliver that, I built a generative UI agent for the booth. Visitors could describe an app from scratch, or pick an existing example and replay the flow.&lt;/p&gt;

    &lt;p&gt;This is generative UI in practice: software generated on demand, shaped entirely by a user&apos;s prompt rather than served from a pre-built library. It offers a glimpse of a future where interfaces are personalized and ephemeral, created in the moment of the visit to match a visitor&apos;s specific intent.&lt;/p&gt;

    &lt;p&gt;The experience ran on a task-specific harness I built around Bob. In agentic AI vocabulary, a harness covers everything except the model itself: the tools, prompts, modes, and the loop that runs them. Bob already has its native harness. The task-specific harness I added sits on top, wrapping Bob&apos;s open-ended generation in deterministic input, build, and render layers.&lt;/p&gt;

    &lt;p&gt;The experience was built for Bob, the harness that made it possible was built with Bob, and every app a visitor saw was authored by Bob. In the rest of this article, I will share how I designed the architecture to handle the booth constraints, what I learned from the execution, and where there is room for improvement.&lt;/p&gt;

    &lt;h2 id=&quot;design-goals&quot;&gt;&lt;a href=&quot;#design-goals&quot; class=&quot;heading-link&quot;&gt;Design goals&lt;/a&gt;&lt;/h2&gt;

    &lt;p&gt;The loop had to complete while a visitor was still standing there. That single constraint gave the generative UI agent five design goals.&lt;/p&gt;

    &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Two-minute cycle.&lt;/strong&gt; The system had to move from prompt to rendered UI in roughly two minutes. Anything longer would turn the experience from a live demo into a waiting screen.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Predictable structure.&lt;/strong&gt; Bob could generate the app, but the task-specific harness needed to know where the entry file lived, which files belonged to the app, and what to bundle. The output needed a known shape, not just a pile of generated files.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Predictable dependencies.&lt;/strong&gt; Generated code could only import what the host had already declared. Surprise modules at runtime would make the app harder to bundle, harder to debug, and harder to trust.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Sandboxing.&lt;/strong&gt; The generated app needed to render without sharing the host page&apos;s styles, globals, or storage surface. The harness had to let the code run while keeping it inside a controlled browser boundary.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Iteration support.&lt;/strong&gt; A visitor could ask for changes after the first render. Continuing the app needed to be a storage lookup against the same conversation workspace, not a fresh bootstrap from scratch.&lt;/li&gt;
  &lt;/ul&gt;

    &lt;p&gt;Those goals shaped the task-specific harness around BobShell: a context builder to constrain Bob&apos;s input, a conversation workspace for predictable file structure, a BobShell subprocess for the generation step, an esbuild bundler for deterministic build, an HTML wrapper for safe import resolution, and a sandboxed iframe for isolation.&lt;/p&gt;

    &lt;h2 id=&quot;the-task-specific-harness&quot;&gt;&lt;a href=&quot;#the-task-specific-harness&quot; class=&quot;heading-link&quot;&gt;The task-specific harness&lt;/a&gt;&lt;/h2&gt;

    &lt;p&gt;The generative UI agent is BobShell wrapped in a task-specific harness. The task-specific harness compressed Bob&apos;s coding-agent capability into a loop that could run in front of a visitor. Because Bob did not yet have an agent SDK, the task-specific harness invoked BobShell, Bob&apos;s CLI, as a non-interactive subprocess.&lt;/p&gt;

    &lt;p&gt;From there, the pipeline was straightforward: a prompt entered through the chat panel, the context builder assembled the right input, BobShell generated files, esbuild produced a browser-runnable bundle, and the host UI mounted the iframe preview.&lt;/p&gt;

    &lt;figure&gt;
    &lt;img src=&quot;/images/blog/generative-ui-agent-for-bob-with-bob-by-bob/agent-architecture.jpg&quot; alt=&quot;Agent architecture: a host UI with a chat panel and preview area sits above the backend pipeline of context builder, BobShell subprocess, conversation workspace, esbuild bundler, and bundle, plus an HTML wrapper that the iframe loads to render the generated app.&quot;&gt;
    &lt;figcaption&gt;Figure 1: the agent, end to end.&lt;/figcaption&gt;
  &lt;/figure&gt;

    &lt;p&gt;The harness separates four concerns: input, generation, bundling, and rendering.&lt;/p&gt;

&lt;h3 id=&quot;1-context-builder&quot;&gt;&lt;a href=&quot;#1-context-builder&quot; class=&quot;heading-link&quot;&gt;1. Context Builder&lt;/a&gt;&lt;/h3&gt;

    &lt;p&gt;The user prompt does not go straight to BobShell. It first passes through a context builder, a backend module that assembles the input BobShell needs for the current turn.&lt;/p&gt;

    &lt;p&gt;That input depends on mode. The user selects &lt;strong&gt;Plan mode&lt;/strong&gt; or &lt;strong&gt;Code mode&lt;/strong&gt; from the frontend, and the context builder assembles the matching prompt. The booth experience ran plan to code: a visitor generated a plan, approved it, then triggered Code mode.&lt;/p&gt;

    &lt;p&gt;In &lt;strong&gt;Plan mode&lt;/strong&gt;, the prompt includes the user&apos;s request, the workspace path, and a custom instruction that asks Bob to produce a plan document with four sections:&lt;/p&gt;

    &lt;code-block language=&quot;text&quot;&gt;
    &lt;pre&gt;&lt;code&gt;1. Overview
   What the app should do and what experience it should create.

2. Architecture
   The high-level structure of the app.

3. Component breakdown
   The main UI components and what each one owns.

4. Manifest
   The file list, file roles, and entry point esbuild will use.&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

    &lt;p&gt;The planning prompt tells Bob to split larger apps into smaller files first, and the manifest then declares those files explicitly so the harness knows what to bundle.&lt;/p&gt;

    &lt;p&gt;&lt;strong&gt;Design Note: The 600-line limit.&lt;/strong&gt; In testing, a single &lt;code&gt;write_to_file&lt;/code&gt; call struggled once it grew past roughly 600 lines. That failure is why the manifest exists.&lt;/p&gt;

    &lt;p&gt;The manifest:&lt;/p&gt;

    &lt;code-block language=&quot;json&quot;&gt;
    &lt;pre&gt;&lt;code&gt;{
  &quot;files&quot;: [
    { &quot;path&quot;: &quot;src/App.jsx&quot;,      &quot;role&quot;: &quot;entry&quot;,     &quot;purpose&quot;: &quot;...&quot; },
    { &quot;path&quot;: &quot;src/Scenario.jsx&quot;, &quot;role&quot;: &quot;component&quot;, &quot;purpose&quot;: &quot;...&quot; },
    { &quot;path&quot;: &quot;src/Summary.jsx&quot;,  &quot;role&quot;: &quot;component&quot;, &quot;purpose&quot;: &quot;...&quot; }
  ],
  &quot;entryPoint&quot;: &quot;src/App.jsx&quot;
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

    &lt;p&gt;The manifest is the interface between Bob&apos;s open-ended generation and the harness&apos;s deterministic build step. It gives both sides a shared file contract before code generation starts: Bob knows what to create, and esbuild knows where to start.&lt;/p&gt;

    &lt;p&gt;In &lt;strong&gt;Code mode&lt;/strong&gt;, the prompt includes the approved plan, workspace path, conversation history, and any existing files in &lt;code&gt;src/&lt;/code&gt;. That lets Bob edit in place during iteration rather than regenerate the app from scratch.&lt;/p&gt;

    &lt;p&gt;The Code-mode prompt also carries runtime constraints. Because the generated app runs inside an iframe, the prompt tells Bob not to assume access to the parent page, cookies, &lt;code&gt;localStorage&lt;/code&gt;, or direct cross-origin APIs. The browser boundary becomes a generation constraint before Bob writes any code.&lt;/p&gt;

    &lt;h3 id=&quot;2-conversation-workspace&quot;&gt;&lt;a href=&quot;#2-conversation-workspace&quot; class=&quot;heading-link&quot;&gt;2. Conversation Workspace&lt;/a&gt;&lt;/h3&gt;

    &lt;p&gt;Each session gets a conversation ID, and that ID owns the files Bob works with:&lt;/p&gt;

    &lt;code-block language=&quot;text&quot;&gt;
    &lt;pre&gt;&lt;code&gt;generated/conversations/{conversation_id}/
  src/    # source files Bob writes
  build/  # bundled output from esbuild
  logs/   # agent traces
  docs/   # plan documents&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

    &lt;p&gt;The workspace sits on a volume mount backed by object storage. A database would have been overkill for a handful of JSX and markdown files per conversation, and ephemeral Docker storage would have lost everything on container restart. The volume mount sits between those: files survive container restarts without requiring a schema layer.&lt;/p&gt;

    &lt;p&gt;The workspace also makes iteration cheap. When a visitor asks for a change, the harness reloads the workspace, sends Bob the plan and existing files, and lets Bob edit in place. Continuing becomes a storage lookup, not a full restart.&lt;/p&gt;

&lt;h3 id=&quot;3-bobshell-subprocess&quot;&gt;&lt;a href=&quot;#3-bobshell-subprocess&quot; class=&quot;heading-link&quot;&gt;3. BobShell Subprocess&lt;/a&gt;&lt;/h3&gt;

    &lt;p&gt;Once the context builder assembles the prompt, the harness launches BobShell as a non-interactive subprocess: one invocation per turn, prompt in, output out, wait for completion.&lt;/p&gt;

    &lt;p&gt;The command shape looked like this:&lt;/p&gt;

    &lt;code-block language=&quot;shell&quot;&gt;
    &lt;pre&gt;&lt;code&gt;export BOBSHELL_API_KEY=&quot;your-api-key-here&quot;

bob \
  --auth-method api-key \
  --chat-mode={mode} \
  --yolo \
  -p &quot;{prompt}&quot;&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

    &lt;p&gt;The &lt;code&gt;{prompt}&lt;/code&gt; comes from the context builder. The &lt;code&gt;{mode}&lt;/code&gt; comes from the user&apos;s selection in the frontend: usually &lt;code&gt;plan&lt;/code&gt; or &lt;code&gt;code&lt;/code&gt;, with room for custom modes.&lt;/p&gt;

    &lt;p&gt;In Node.js, the harness can spawn that command as a child process:&lt;/p&gt;

    &lt;code-block language=&quot;typescript&quot;&gt;
    &lt;pre&gt;&lt;code&gt;import { spawn } from &quot;node:child_process&quot;;

type RunBobShellOptions = {
  mode: &quot;plan&quot; | &quot;code&quot; | string;
  prompt: string;
  apiKey: string;
  cwd: string;
  onStdout?: (chunk: string) =&amp;gt; void;
  onStderr?: (chunk: string) =&amp;gt; void;
};

export function runBobShell({
  mode,
  prompt,
  apiKey,
  cwd,
  onStdout,
  onStderr,
}: RunBobShellOptions): Promise&amp;lt;void&amp;gt; {
  return new Promise((resolve, reject) =&amp;gt; {
    const child = spawn(
      &quot;bob&quot;,
      [
        &quot;--auth-method&quot;,
        &quot;api-key&quot;,
        `--chat-mode=${mode}`,
        &quot;--yolo&quot;,
        &quot;-p&quot;,
        prompt,
      ],
      {
        cwd,
        env: {
          ...process.env,
          BOBSHELL_API_KEY: apiKey,
        },
        stdio: [&quot;ignore&quot;, &quot;pipe&quot;, &quot;pipe&quot;],
      }
    );

    child.stdout.setEncoding(&quot;utf8&quot;);
    child.stderr.setEncoding(&quot;utf8&quot;);

    child.stdout.on(&quot;data&quot;, (chunk) =&amp;gt; {
      onStdout?.(chunk);
    });

    child.stderr.on(&quot;data&quot;, (chunk) =&amp;gt; {
      onStderr?.(chunk);
    });

    child.on(&quot;error&quot;, reject);

    child.on(&quot;close&quot;, (code) =&amp;gt; {
      if (code === 0) {
        resolve();
        return;
      }

      reject(new Error(`BobShell exited with code ${code}`));
    });
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

    &lt;p&gt;The trick is operational: the Node.js process must run somewhere &lt;code&gt;bob&lt;/code&gt; is installed and available on &lt;code&gt;PATH&lt;/code&gt;. In this implementation, the backend ran inside a container image that already had BobShell installed. Without that, &lt;code&gt;spawn(&quot;bob&quot;, ...)&lt;/code&gt; fails before Bob receives the prompt.&lt;/p&gt;

    &lt;p&gt;The &lt;code&gt;--yolo&lt;/code&gt; flag deserves explicit framing. It auto-approves tool calls, which removed the human-in-loop step that would have blown the booth&apos;s time budget. The flag was acceptable here only because the agent ran in a scoped workspace inside a sandboxed preview. In ordinary development, where the agent has access to your real environment, this flag is a security risk and I would not use it.&lt;/p&gt;

    &lt;p&gt;While BobShell runs, the harness parses its output and streams intermediate results back to the chat panel through Server-Sent Events. The visitor sees progress instead of staring at an empty preview.&lt;/p&gt;

    &lt;p&gt;We tried staged generation: skeleton first, then components, so the visitor would see partial output as soon as Bob started writing. It looked useful for live UX, but the bundler cannot tell a partially written file from a complete one. Detecting incompleteness added complexity, and waiting for completion added latency.&lt;/p&gt;

    &lt;p&gt;For this version, single-shot generation won. Bob writes the app in one Code-mode run, then the backend bundles after BobShell exits.&lt;/p&gt;

&lt;h3 id=&quot;4-esbuild-bundler&quot;&gt;&lt;a href=&quot;#4-esbuild-bundler&quot; class=&quot;heading-link&quot;&gt;4. esbuild Bundler&lt;/a&gt;&lt;/h3&gt;

    &lt;p&gt;After BobShell finishes, the files in &lt;code&gt;src/&lt;/code&gt; still need to become something the browser can run. esbuild handles that bundling step.&lt;/p&gt;

    &lt;p&gt;The first version ran &lt;code&gt;esbuild-wasm&lt;/code&gt; inside the iframe so the bundle could be built in the browser, near the render. CSP rules in the host environment made that path awkward: the iframe could not reliably load the WASM module under the security headers we needed.&lt;/p&gt;

    &lt;p&gt;Moving esbuild to the server simplified the harness. BobShell writes files, exits, and the backend runs esbuild against the manifest&apos;s entry point:&lt;/p&gt;

    &lt;code-block language=&quot;javascript&quot;&gt;
    &lt;pre&gt;&lt;code&gt;await esbuild.build({
  entryPoints: [`${workspace}/${plan.entryPoint}`],
  outfile:     `${workspace}/build/bundle.js`,
  bundle:      true,
  format:      &quot;esm&quot;,
  jsx:         &quot;automatic&quot;,
  external:    [&quot;react&quot;, &quot;react-dom/client&quot;],
});&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

    &lt;p&gt;React and &lt;code&gt;react-dom/client&lt;/code&gt; stay external, so the generated bundle does not ship its own copy. Instead, the HTML wrapper declares an import map, and the browser resolves those imports at load time. That keeps the bundle small enough to load quickly on the booth display, and gives the host control over which React version the generated app runs against.&lt;/p&gt;

    &lt;p&gt;The cost is feedback. Because bundling happens after BobShell exits, Bob does not see build errors. If esbuild fails, the backend reports it to the host UI, but Bob cannot read the diagnostic and patch the files in the same turn.&lt;/p&gt;

    &lt;h3 id=&quot;5-bundle&quot;&gt;&lt;a href=&quot;#5-bundle&quot; class=&quot;heading-link&quot;&gt;5. Bundle&lt;/a&gt;&lt;/h3&gt;

    &lt;p&gt;The bundle is the handoff artifact:&lt;/p&gt;

    &lt;code-block language=&quot;text&quot;&gt;
    &lt;pre&gt;&lt;code&gt;build/bundle.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

    &lt;p&gt;It is the generated app after the backend has turned Bob&apos;s source files into browser-runnable JavaScript.&lt;/p&gt;

    &lt;p&gt;The host UI does not mount the preview just because Bob wrote files. It mounts after the backend produces the bundle and sends a bundle-ready notification. The bundle is the artifact; the notification tells the preview area to load the iframe.&lt;/p&gt;

&lt;h3 id=&quot;6-html-wrapper&quot;&gt;&lt;a href=&quot;#6-html-wrapper&quot; class=&quot;heading-link&quot;&gt;6. HTML Wrapper&lt;/a&gt;&lt;/h3&gt;

    &lt;p&gt;The iframe does not load &lt;code&gt;bundle.js&lt;/code&gt; directly. It loads an API-served HTML wrapper.&lt;/p&gt;

    &lt;p&gt;The host UI points the iframe&apos;s &lt;code&gt;src&lt;/code&gt; at an API endpoint for the conversation. That endpoint returns a small HTML document with four jobs: declare the import map, load Tailwind for this version, load the error bridge, and import the generated bundle.&lt;/p&gt;

    &lt;code-block language=&quot;html&quot;&gt;
    &lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;script type=&quot;importmap&quot;&amp;gt;
      {
        &quot;imports&quot;: {
          &quot;react&quot;: &quot;https://esm.sh/react@19&quot;,
          &quot;react-dom/client&quot;: &quot;https://esm.sh/react-dom@19/client&quot;
        }
      }
    &amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;https://cdn.tailwindcss.com&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;/runtime/error-bridge.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div id=&quot;root&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;script
      type=&quot;module&quot;
      src=&quot;/api/conversations/{id}/build/bundle.js&quot;&amp;gt;
    &amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

    &lt;p&gt;The import map controls module resolution for external imports like &lt;code&gt;react&lt;/code&gt; and &lt;code&gt;react-dom/client&lt;/code&gt;. Tailwind is different: it loads as a script tag in this implementation because import maps do not govern ordinary script URLs.&lt;/p&gt;

    &lt;p&gt;That Tailwind choice was pragmatic. Bob writes clean Tailwind classes, and utility-class strings are compact in prompts. A production version should generate Tailwind CSS server-side rather than depend on the browser CDN.&lt;/p&gt;

    &lt;p&gt;The HTML wrapper belongs to the render path, not the backend pipeline. After the backend produces the bundle, the preview receives a bundle-ready notification. The iframe then loads the wrapper, which loads the bundle.&lt;/p&gt;

    &lt;h3 id=&quot;7-sandboxed-iframe-preview&quot;&gt;&lt;a href=&quot;#7-sandboxed-iframe-preview&quot; class=&quot;heading-link&quot;&gt;7. Sandboxed iframe preview&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;The first version rendered generated components directly inside the host page. That put the generated app in the same DOM, CSS cascade, and JavaScript surface as the product UI. A bad selector could restyle the host, and generated code could overwrite assumptions the host depended on.&lt;/p&gt;

  &lt;p&gt;The harness needed to isolate generated code, styles, build output, and failures. A bundling error should stop the preview, not the host UI. A script error in the generated bundle should be reported by the preview, not treated as a product-shell crash.&lt;/p&gt;

  &lt;p&gt;The second version moved the generated app into an iframe. We considered web components with Shadow DOM, but Shadow DOM only isolates DOM and CSS. It does not create a separate JavaScript execution environment. With &lt;code&gt;sandbox=&quot;allow-scripts allow-forms&quot;&lt;/code&gt;, the iframe gives the preview its own browser boundary for scripts, styles, storage, and execution failures.&lt;/p&gt;

  &lt;p&gt;That boundary shapes prompt design too. Bob is told to keep state in memory, avoid cross-origin fetches, and not assume access to the parent page. If the generated app needs to report status outward, it crosses a narrow bridge.&lt;/p&gt;

  &lt;p&gt;The bridge uses &lt;code&gt;postMessage&lt;/code&gt; for two states: the wrapper finished loading, or the generated app hit an execution error. The host listens for both and updates the chat or preview panel without exposing the rest of the product to the generated app.&lt;/p&gt;

  &lt;code-block language=&quot;tsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;// Inside the wrapper, before the bundle loads
window.addEventListener(&quot;load&quot;, () =&amp;gt; {
  parent.postMessage({
    type: &quot;generated-app-loaded&quot;,
  }, &quot;*&quot;);
});

window.addEventListener(&quot;error&quot;, (event) =&amp;gt; {
  parent.postMessage({
    type:    &quot;generated-app-error&quot;,
    message: event.message,
    source:  event.filename,
    line:    event.lineno,
  }, &quot;*&quot;);
});

// On the host side
function PreviewPane({ previewUrl }: { previewUrl: string }) {
  useEffect(() =&amp;gt; {
    const handleMessage = (event: MessageEvent) =&amp;gt; {
      if (event.data?.type === &quot;generated-app-loaded&quot;) {
        markPreviewReady();
      }
      if (event.data?.type === &quot;generated-app-error&quot;) {
        showRuntimeError(event.data);
      }
    };
    window.addEventListener(&quot;message&quot;, handleMessage);
    return () =&amp;gt; window.removeEventListener(&quot;message&quot;, handleMessage);
  }, []);

  return (
    &amp;lt;iframe
      src={previewUrl}
      sandbox=&quot;allow-scripts allow-forms&quot;
      title=&quot;Generated app preview&quot;
    /&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

    &lt;h2 id=&quot;lessons-and-next-steps&quot;&gt;&lt;a href=&quot;#lessons-and-next-steps&quot; class=&quot;heading-link&quot;&gt;Lessons and next steps&lt;/a&gt;&lt;/h2&gt;

    &lt;p&gt;The Think 2026 implementation made one thing clear: Bob already has the primitives. It reads and writes files, runs commands, and generates working React and Tailwind. The work was in the task-specific harness: pointing those primitives at a predictable flow, where to write, what context to use, when to bundle, and where to render.&lt;/p&gt;

    &lt;p&gt;Without that harness, the output is code in a folder. With it, the visitor gets a browser-runnable app to test.&lt;/p&gt;

    &lt;p&gt;The first improvement is prompt and harness efficiency. Every second matters in a booth, and every token and setup step has a cost in production. The goal is to design the prompt, context, tools, and workflow so Bob reaches a useful result faster. Interactive BobShell could help: a warm session across turns reduces latency while the harness keeps controlling workspace and output shape.&lt;/p&gt;

    &lt;p&gt;The second improvement is to put the build step, linting, and security scanning inside the same Bob loop. We had this and removed it for latency, since Bob writes compilable code in one pass often enough to skip validation. Once the first improvement frees up time budget, validation comes back: Bob runs esbuild and the scanners, reads diagnostics, patches the offending file, and retries before the preview reaches the user.&lt;/p&gt;

    &lt;p&gt;The third improvement is the approved frontend surface. The current harness exposed only React and Tailwind to generated code. A polished version should add richer approved ESM modules, including something like Carbon React, so generated apps do not make Bob recreate every UI primitive.&lt;/p&gt;

    &lt;p&gt;The Think 2026 version proved the core loop: prompt, context, BobShell, workspace, bundle, wrapper, iframe. The next version should make it more self-correcting, safer, and more efficient.&lt;/p&gt;

    &lt;p&gt;Bob brings the coding agent. The task-specific harness gives it a job.&lt;/p&gt;

    &lt;source-note heading=&quot;Disclaimer&quot;&gt;
      &lt;p&gt;The views in this essay are personal. They do not represent IBM, the Bob team, or any of my employers.&lt;/p&gt;
    &lt;/source-note&gt;</content>
    <author><name>Tosin Amuda</name></author>
  </entry>
  <entry>
    <title>Skills Are Prompts, But Not All Prompts Are Equal</title>
    <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/skills-are-just-markdown.html" />
    <id>https://www.tosinamuda.com/blog/skills-are-just-markdown.html</id>
    <updated>2026-04-28T00:00:00.000Z</updated>
    <published>2026-04-28T00:00:00.000Z</published>
    <summary>What&apos;s new about a Skill isn&apos;t any single property. It is that the properties live together in one named, loadable package.</summary>
    <content type="html">&lt;p&gt;What&apos;s new about a Skill isn&apos;t any single property. It is that the properties live together in one named, loadable package.&lt;/p&gt;&lt;p&gt;A Skill is a prompt. Anything that enters an LLM&apos;s context shapes what comes out, and a &lt;code&gt;SKILL.md&lt;/code&gt; file enters the context like any user instruction or system prompt. Mechanically, the skeptic is right.&lt;/p&gt;

  &lt;p&gt;Each individual property of a Skill can already be done some other way. A narrowly written system prompt can function as task-scoped. A shared template can be reusable across people. Retrieval can load context only when relevant. A folder can package a prompt with examples and helper scripts. None of these capabilities is new on its own.&lt;/p&gt;

  &lt;p&gt;What is new is the combination, as a single package.&lt;/p&gt;

  &lt;p&gt;A Skill is the prompt-shaped package where four properties live together. It is task-scoped rather than project-scoped or session-scoped. The system loads it selectively when the task calls for it, instead of the user pasting it in. It can be reused across people, rather than living inside one person&apos;s session.&lt;a href=&quot;#fn1&quot; class=&quot;skills-fnref&quot;&gt;1&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;And it bundles its full payload, instructions plus examples plus scripts plus references, as one named unit that can be versioned, installed, and uninstalled.&lt;/p&gt;

  &lt;figure class=&quot;skills-visual&quot;&gt;
    &lt;table class=&quot;skills-compare-table&quot; role=&quot;table&quot; aria-label=&quot;Comparison of prompt-shaped artifacts&quot;&gt;
      &lt;thead&gt;
        &lt;tr&gt;
          &lt;th&gt;&lt;/th&gt;
          &lt;th&gt;Handwritten&lt;br&gt;prompt&lt;/th&gt;
          &lt;th&gt;System&lt;br&gt;prompt&lt;/th&gt;
          &lt;th&gt;Custom&lt;br&gt;instruction&lt;/th&gt;
          &lt;th&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/th&gt;
          &lt;th class=&quot;skills-skill-col&quot;&gt;Skill&lt;/th&gt;
        &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
        &lt;tr&gt;
          &lt;th scope=&quot;row&quot;&gt;Task-scoped&lt;/th&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-yes&quot;&gt;●&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-partial&quot;&gt;if narrow&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-no&quot;&gt;○&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-no&quot;&gt;○&lt;/span&gt;&lt;/td&gt;
          &lt;td class=&quot;skills-skill-col&quot;&gt;&lt;span class=&quot;skills-mark-yes&quot;&gt;●&lt;/span&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;th scope=&quot;row&quot;&gt;Selectively loaded&lt;/th&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-no&quot;&gt;○&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-no&quot;&gt;○&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-no&quot;&gt;○&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-no&quot;&gt;○&lt;/span&gt;&lt;/td&gt;
          &lt;td class=&quot;skills-skill-col&quot;&gt;&lt;span class=&quot;skills-mark-yes&quot;&gt;●&lt;/span&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;th scope=&quot;row&quot;&gt;Reusable across people&lt;/th&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-no&quot;&gt;○&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-partial&quot;&gt;if shared&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-no&quot;&gt;○&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-yes&quot;&gt;●&lt;/span&gt;&lt;/td&gt;
          &lt;td class=&quot;skills-skill-col&quot;&gt;&lt;span class=&quot;skills-mark-yes&quot;&gt;●&lt;/span&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;th scope=&quot;row&quot;&gt;Bundled payload&lt;/th&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-no&quot;&gt;○&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-no&quot;&gt;○&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-no&quot;&gt;○&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;&lt;span class=&quot;skills-mark-partial&quot;&gt;partial&lt;/span&gt;&lt;/td&gt;
          &lt;td class=&quot;skills-skill-col&quot;&gt;&lt;span class=&quot;skills-mark-yes&quot;&gt;●&lt;/span&gt;&lt;/td&gt;
        &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
    &lt;figcaption class=&quot;skills-visual-caption&quot;&gt;No single existing artifact carries all four properties. The Skill is the form that ships with them combined.&lt;/figcaption&gt;
  &lt;/figure&gt;

  &lt;p&gt;Each property, on its own, is reachable with what you already have. The combination is what&apos;s harder to assemble, because it requires the package to be a first-class unit the system loads, addresses, and unloads on its own. You can build that yourself, with a routing layer and a prompt library and some glue. Skills are the form in which the combination ships as a default, with the system handling the loading instead of the user.&lt;/p&gt;

  &lt;p&gt;The claim is not that this is unprecedented. The claim is that it is now the default form, and the default form is what determines whether most users will ever benefit from it. What unification enables is why that matters.&lt;/p&gt;

  &lt;h2 id=&quot;what-unification-makes-possible&quot;&gt;&lt;a href=&quot;#what-unification-makes-possible&quot; class=&quot;heading-link&quot;&gt;What Unification Makes Possible&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Two consequences follow from the same property. Both depend on the package being named, selectively loaded, and reusable. Each one solves a different problem.&lt;/p&gt;

  &lt;figure class=&quot;skills-visual&quot;&gt;
    &lt;div class=&quot;skills-consequences-wrapper&quot;&gt;
      &lt;div class=&quot;skills-consequences&quot;&gt;
        &lt;div class=&quot;skills-consequence-panel&quot;&gt;
          &lt;div class=&quot;skills-consequence-label&quot;&gt;Consequence 1&lt;/div&gt;
          &lt;div class=&quot;skills-consequence-title&quot;&gt;Expert knowledge becomes transferable across domains&lt;/div&gt;
          &lt;div class=&quot;skills-consequence-row&quot;&gt;
            &lt;div class=&quot;skills-consequence-marker&quot;&gt;Before&lt;/div&gt;
            &lt;div class=&quot;skills-consequence-text&quot;&gt;A lawyer&apos;s working knowledge stays with the lawyer. Useful once.&lt;/div&gt;
          &lt;/div&gt;
          &lt;div class=&quot;skills-consequence-row&quot;&gt;
            &lt;div class=&quot;skills-consequence-marker skills-after&quot;&gt;After&lt;/div&gt;
            &lt;div class=&quot;skills-consequence-text&quot;&gt;The same knowledge is loadable by a founder who has never read a contract carefully.&lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;skills-consequence-panel&quot;&gt;
          &lt;div class=&quot;skills-consequence-label&quot;&gt;Consequence 2&lt;/div&gt;
          &lt;div class=&quot;skills-consequence-title&quot;&gt;Detailed refusals become viable&lt;/div&gt;
          &lt;div class=&quot;skills-consequence-row&quot;&gt;
            &lt;div class=&quot;skills-consequence-marker&quot;&gt;Before&lt;/div&gt;
            &lt;div class=&quot;skills-consequence-text&quot;&gt;The model drifts to its training average: AI slop, generic and machine-made.&lt;/div&gt;
          &lt;/div&gt;
          &lt;div class=&quot;skills-consequence-row&quot;&gt;
            &lt;div class=&quot;skills-consequence-marker skills-after&quot;&gt;After&lt;/div&gt;
            &lt;div class=&quot;skills-consequence-text&quot;&gt;A long, domain-specific list of patterns to refuse is loaded only when needed.&lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;skills-consequence-bridge&quot;&gt;Both come back to the same property: the Skill is selectively loaded and named.&lt;/div&gt;
    &lt;/div&gt;
    &lt;figcaption class=&quot;skills-visual-caption&quot;&gt;One package, two jobs at once. The same structural property that makes long-form expertise portable also makes long-form refusals affordable.&lt;/figcaption&gt;
  &lt;/figure&gt;

  &lt;p&gt;The first thing it enables is that expert knowledge becomes transferable across domains. A handwritten prompt encoding what a senior contracts lawyer would check is useful exactly once, to the person who wrote it. The same instructions in a Skill, named and addressable, can be loaded by a founder who has never read a contract carefully.&lt;/p&gt;

  &lt;p&gt;The lawyer&apos;s working knowledge becomes a passable substitute for the lawyer, accessible to anyone whose task calls for it. Before Skills, this transfer required the recipient to know enough to copy the right prompt at the right time. Now the system handles the loading.&lt;/p&gt;

  &lt;figure class=&quot;skills-visual&quot;&gt;
    &lt;div class=&quot;skills-flow-diagram&quot;&gt;
      &lt;div class=&quot;skills-flow-steps&quot;&gt;
        &lt;div class=&quot;skills-flow-step&quot;&gt;
          &lt;div class=&quot;skills-flow-step-num&quot;&gt;1&lt;/div&gt;
          &lt;div class=&quot;skills-flow-step-text&quot;&gt;User asks for a slide deck&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;skills-flow-arrow&quot;&gt;&amp;rarr;&lt;/div&gt;
        &lt;div class=&quot;skills-flow-step&quot;&gt;
          &lt;div class=&quot;skills-flow-step-num&quot;&gt;2&lt;/div&gt;
          &lt;div class=&quot;skills-flow-step-text&quot;&gt;System scans installed Skills&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;skills-flow-arrow&quot;&gt;&amp;rarr;&lt;/div&gt;
        &lt;div class=&quot;skills-flow-step skills-highlight&quot;&gt;
          &lt;div class=&quot;skills-flow-step-num&quot;&gt;3&lt;/div&gt;
          &lt;div class=&quot;skills-flow-step-text&quot;&gt;pptx Skill matches and loads&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;skills-flow-arrow&quot;&gt;&amp;rarr;&lt;/div&gt;
        &lt;div class=&quot;skills-flow-step&quot;&gt;
          &lt;div class=&quot;skills-flow-step-num&quot;&gt;4&lt;/div&gt;
          &lt;div class=&quot;skills-flow-step-text&quot;&gt;Model responds with the Skill in context&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;figcaption class=&quot;skills-visual-caption&quot;&gt;Selective loading. The Skill enters context only when the task calls for it, then leaves.&lt;/figcaption&gt;
  &lt;/figure&gt;

  &lt;p&gt;The second thing it enables is that detailed refusals become viable. The model tends to produce something close to the average response in its training distribution. For factual queries, the average is usually correct. For creative or aesthetic work, the average is what people recognize as AI slop: generic, bland, machine-made.&lt;/p&gt;

  &lt;p&gt;Pushing the model off the average requires telling it specifically what to avoid, not just what to produce. The list of patterns to refuse is often long and domain-specific. A system prompt is the wrong place for it because most conversations don&apos;t need the list. A custom instruction is the wrong place because the scope is global.&lt;/p&gt;

  &lt;p&gt;A Skill loads only when the relevant task is at hand, so it can carry the full refusal list without paying a cost on every other interaction.&lt;/p&gt;

  &lt;h2 id=&quot;an-example-that-shows-both-at-once&quot;&gt;&lt;a href=&quot;#an-example-that-shows-both-at-once&quot; class=&quot;heading-link&quot;&gt;An Example That Shows Both at Once&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Anthropic&apos;s &lt;code&gt;pptx&lt;/code&gt; Skill is built for slide decks, and it shows both consequences working in a single package.&lt;a href=&quot;#fn2&quot; class=&quot;skills-fnref&quot;&gt;2&lt;/a&gt; Asked to make a deck about quarterly results, a model with no Skill produces what people now recognize as AI slop: title plus three bullets per slide, generic styling, the same look every time.&lt;/p&gt;

  &lt;p&gt;The Skill changes the result. It tells the model to pick a content-informed color palette and reject default blue, to commit to a single visual motif and repeat it across the deck, to treat text-only slides as failures, and to vary layouts. It also names specific AI-generated tells and refuses them: accent lines under titles, full-width colored bars, cream backgrounds.&lt;/p&gt;

  &lt;figure class=&quot;skills-visual&quot;&gt;
    &lt;div class=&quot;skills-code-card&quot; role=&quot;figure&quot; aria-label=&quot;Excerpt from the pptx SKILL.md file&quot;&gt;
      &lt;div class=&quot;skills-code-filename&quot;&gt;pptx/SKILL.md (excerpt)&lt;/div&gt;
&lt;pre&gt;&lt;span class=&quot;skills-code-comment&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;skills-code-key&quot;&gt;name&lt;/span&gt;: pptx
&lt;span class=&quot;skills-code-key&quot;&gt;description&lt;/span&gt;: &lt;span class=&quot;skills-code-string&quot;&gt;&quot;Use this skill any time a .pptx file is involved...&quot;&lt;/span&gt;
&lt;span class=&quot;skills-code-comment&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;skills-code-heading&quot;&gt;## Design Ideas&lt;/span&gt;

&lt;span class=&quot;skills-code-heading&quot;&gt;### Before Starting&lt;/span&gt;

- &lt;span class=&quot;skills-code-key&quot;&gt;Pick a bold, content-informed color palette&lt;/span&gt;:
  the palette should feel designed for THIS topic.
- &lt;span class=&quot;skills-code-key&quot;&gt;Dominance over equality&lt;/span&gt;: one color
  should dominate (60-70% visual weight).
- &lt;span class=&quot;skills-code-key&quot;&gt;Commit to a visual motif&lt;/span&gt;: pick ONE
  distinctive element and repeat it across every slide.

&lt;span class=&quot;skills-code-heading&quot;&gt;### Avoid (Common Mistakes)&lt;/span&gt;

- &lt;span class=&quot;skills-code-key&quot;&gt;Don&apos;t default to blue&lt;/span&gt; - pick colors
  that reflect the specific topic.
- &lt;span class=&quot;skills-code-key&quot;&gt;Don&apos;t create text-only slides&lt;/span&gt; - add
  images, icons, charts, or visual elements.
- &lt;span class=&quot;skills-code-key&quot;&gt;NEVER use accent lines under titles&lt;/span&gt; -
  these are a hallmark of AI-generated slides.
- &lt;span class=&quot;skills-code-key&quot;&gt;Don&apos;t add full-width colored bars&lt;/span&gt; -
  they read as AI slop unless explicitly requested.
- &lt;span class=&quot;skills-code-key&quot;&gt;Don&apos;t default to cream/beige backgrounds&lt;/span&gt;
  - use white or the user&apos;s brand palette.

&lt;span class=&quot;skills-code-heading&quot;&gt;## QA (Required)&lt;/span&gt;

Convert slides to images, then run a verification loop:
overflow, low contrast, overlapping elements, leftover
placeholder text. Fix and re-verify.&lt;/pre&gt;
    &lt;/div&gt;
    &lt;figcaption class=&quot;skills-visual-caption&quot;&gt;The bundled payload: instructions, named refusals, and a verification loop, in one package the system loads on demand.&lt;/figcaption&gt;
  &lt;/figure&gt;

  &lt;p&gt;Two things came together in that one package. The user who asked for the deck did not need to know what makes a deck good. That knowledge came from a designer, packaged once, addressable from then on.&lt;/p&gt;

  &lt;p&gt;The deck also did not come back as the slop the model would have produced by default. The specific refusals came from someone who had watched the model fail enough times to know exactly which patterns to name.&lt;/p&gt;

  &lt;p&gt;A skeptic could write a system prompt that captures part of this. They could write it and live with the cost: it gets loaded on every call where it might be relevant, paid for in tokens, and carried even on calls where it is not. The selective loading isn&apos;t a UX detail. It is what makes a long, domain-specific refusal list practical to maintain over time.&lt;/p&gt;

  &lt;h2 id=&quot;what-unification-does-not-solve&quot;&gt;&lt;a href=&quot;#what-unification-does-not-solve&quot; class=&quot;heading-link&quot;&gt;What Unification Does Not Solve&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Skills can be bad. The format guarantees nothing about the contents. A Skill written by someone without taste in a domain produces tasteless results, and one written before a major change in tools or conventions can keep telling the model to follow rules that no longer apply.&lt;/p&gt;

  &lt;p&gt;Length and structure do not protect against shallow judgment. A long bad Skill can be worse than no Skill, because users may treat it as authority. Unification is a property of the package, not of what the package contains.&lt;/p&gt;

  &lt;h2 id=&quot;the-markdown-is-simple-whats-in-the-package-is-not&quot;&gt;&lt;a href=&quot;#the-markdown-is-simple-whats-in-the-package-is-not&quot; class=&quot;heading-link&quot;&gt;The Markdown Is Simple. What&apos;s in the Package Is Not.&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Skills are prompts. That is the starting point.&lt;/p&gt;

  &lt;p&gt;What is new is not the markdown. The markdown is now part of a named, selectively loaded, reusable package that carries its full payload as a unit. What ships in a Skill is a compact way to do two jobs at once: move expert knowledge across domains, and refuse the model&apos;s defaults at a level of detail most general-purpose prompts can&apos;t afford to carry.&lt;/p&gt;

  &lt;p&gt;The practical upshot is a different question to ask before reaching for a Skill. The question is no longer &quot;is this prompt good.&quot; The question is &quot;does this task call for a package the user could not have assembled themselves.&quot; When the answer is yes, the markdown stops being markdown and starts being infrastructure.&lt;/p&gt;

  &lt;p&gt;The markdown is simple. What&apos;s in the package is not.&lt;/p&gt;

  &lt;aside class=&quot;skills-summary-card&quot; aria-label=&quot;Essay summary&quot;&gt;
    &lt;div class=&quot;skills-summary-card-label&quot;&gt;In one card&lt;/div&gt;

    &lt;div class=&quot;skills-summary-thesis&quot;&gt;A Skill is the prompt-shaped package where four properties live together. The combination is the new thing, and the combination is what makes two awkward problems solvable.&lt;/div&gt;

    &lt;div class=&quot;skills-summary-section&quot;&gt;
      &lt;div class=&quot;skills-summary-heading&quot;&gt;The four properties&lt;/div&gt;
      &lt;div class=&quot;skills-summary-properties&quot;&gt;
        &lt;span&gt;Task-scoped&lt;/span&gt;
        &lt;span&gt;Selectively loaded&lt;/span&gt;
        &lt;span&gt;Reusable across people&lt;/span&gt;
        &lt;span&gt;Bundled payload&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;skills-summary-section&quot;&gt;
      &lt;div class=&quot;skills-summary-heading&quot;&gt;What that makes possible&lt;/div&gt;
      &lt;div class=&quot;skills-summary-pair&quot;&gt;
        &lt;div class=&quot;skills-summary-pair-item&quot;&gt;
          &lt;span class=&quot;skills-summary-pair-key&quot;&gt;Knowledge transfer&lt;/span&gt;
          An expert&apos;s working process becomes loadable by anyone whose task calls for it.
        &lt;/div&gt;
        &lt;div class=&quot;skills-summary-pair-item&quot;&gt;
          &lt;span class=&quot;skills-summary-pair-key&quot;&gt;Refusing defaults&lt;/span&gt;
          A long, domain-specific list of patterns to reject is loaded only when needed.
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;skills-summary-question&quot;&gt;
      &lt;strong&gt;The new question to ask&lt;/strong&gt;
      Not &quot;is this prompt good.&quot; Instead: does this task call for a package the user could not have assembled themselves?
    &lt;/div&gt;
  &lt;/aside&gt;

  &lt;section class=&quot;skills-footnotes&quot;&gt;
    &lt;ol&gt;
      &lt;li id=&quot;fn1&quot;&gt;Anthropic&apos;s documentation on Agent Skills covers the package format and the progressive-disclosure loading model in more detail. See &lt;a href=&quot;https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview&quot;&gt;platform.claude.com/docs/en/agents-and-tools/agent-skills/overview&lt;/a&gt;.&lt;/li&gt;
      &lt;li id=&quot;fn2&quot;&gt;The full instruction file for the &lt;code&gt;pptx&lt;/code&gt; Skill, including the specific patterns shown above, is published in Anthropic&apos;s open repository at &lt;a href=&quot;https://github.com/anthropics/skills/tree/main/skills/pptx&quot;&gt;github.com/anthropics/skills/tree/main/skills/pptx&lt;/a&gt;.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/section&gt;</content>
    <author><name>Tosin Amuda</name></author>
  </entry>
  <entry>
    <title>You might still need a useEffect</title>
    <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/you-might-still-need-a-useeffect.html" />
    <id>https://www.tosinamuda.com/blog/you-might-still-need-a-useeffect.html</id>
    <updated>2026-04-25T00:00:00.000Z</updated>
    <published>2026-04-25T00:00:00.000Z</published>
    <summary>A gentle introduction to useEffect, synchronization, cleanup, dependencies, referential stability, and related React hooks.</summary>
    <content type="html">&lt;p&gt;A gentle introduction to useEffect, synchronization, cleanup, dependencies, referential stability, and related React hooks.&lt;/p&gt;&lt;p&gt;&lt;em&gt;A gentle introduction to synchronization in React&lt;/em&gt;&lt;/p&gt;

  &lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; is one of the first React hooks that starts to feel confusing. The name sounds simple, but the behavior gets strange when an effect runs too many times, doesn&apos;t run when you expect, or keeps doing work after a component has left the screen.&lt;/p&gt;

  &lt;p&gt;The clearest way to think about it is this:&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; is how your component talks to things that live outside React.&lt;/p&gt;
  &lt;/blockquote&gt;

  &lt;p&gt;That &quot;outside&quot; includes the DOM, network requests, timers, subscriptions, browser APIs like &lt;code&gt;window.innerWidth&lt;/code&gt;, and third-party libraries that want to attach to a real DOM node. Anything that isn&apos;t already managed by props and state. The effect&apos;s job is to set up a connection to that outside thing on the way in, and tear it down on the way out.&lt;/p&gt;

  &lt;p&gt;If you want to go deeper on when to use effects and when to avoid them, the React docs have a guide called &lt;a href=&quot;https://react.dev/learn/you-might-not-need-an-effect&quot;&gt;&lt;em&gt;You Might Not Need an Effect&lt;/em&gt;&lt;/a&gt;, and Alvin Sng has written about &lt;a href=&quot;https://x.com/alvinsng/status/2033969062834045089&quot;&gt;banning direct &lt;code&gt;useEffect&lt;/code&gt;&lt;/a&gt; in production codebases. Both are worth reading once you&apos;ve got the basics down. This article is the basics.&lt;/p&gt;

  &lt;h2 id=&quot;how-useeffect-works&quot;&gt;&lt;a href=&quot;#how-useeffect-works&quot; class=&quot;heading-link&quot;&gt;How useEffect works&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; takes two arguments: a callback function and a dependency array.&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  // ...your code
}, [dep1, dep2]);&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;Three things determine when and how the callback runs.&lt;/p&gt;

  &lt;h3 id=&quot;the-callback-runs-after-the-component-renders&quot;&gt;&lt;a href=&quot;#the-callback-runs-after-the-component-renders&quot; class=&quot;heading-link&quot;&gt;The callback runs after the component renders&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;When React renders your component and updates the DOM, it then runs the callback. Anything inside the callback happens after the user can already see the result of the render. That&apos;s why effects are a safe place for side effects: they don&apos;t block the screen from updating.&lt;/p&gt;

  &lt;h3 id=&quot;the-dependency-array-decides-when-to-re-run-the-callback&quot;&gt;&lt;a href=&quot;#the-dependency-array-decides-when-to-re-run-the-callback&quot; class=&quot;heading-link&quot;&gt;The dependency array decides when to re-run the callback&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;When you provide a dependency array, React compares the values inside it against the previous render&apos;s values. If any of them changed, React runs the callback again. If none of them changed, React skips it.&lt;/p&gt;

  &lt;p&gt;There are three shapes the array can take, and each one means something different:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;// 1. Specific dependencies: re-run when any of these change
useEffect(() =&amp;gt; {
  const connection = openChatRoom(roomId);
}, [roomId]);

// 2. Empty array: run once after the first render, never again
useEffect(() =&amp;gt; {
  console.log(&quot;mounted&quot;);
}, []);

// 3. No array at all: run after every render
useEffect(() =&amp;gt; {
  console.log(&quot;rendered&quot;);
});&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;Most of the time you want the first shape. The empty array is useful when the work doesn&apos;t depend on any changing value, like a one-time setup. The no-array form is rarely what you want, and the dependency linter will usually warn you against it.&lt;/p&gt;

  &lt;h3 id=&quot;the-callback-returns-a-cleanup-function&quot;&gt;&lt;a href=&quot;#the-callback-returns-a-cleanup-function&quot; class=&quot;heading-link&quot;&gt;The callback returns a cleanup function&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;The work an effect starts often needs to be stopped. A &lt;code&gt;setInterval&lt;/code&gt; should be cleared. An event listener should be removed. A subscription should be cancelled. To handle that, the callback can return a function, and React will run that function before the next time the effect runs or when the component unmounts.&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  const connection = openChatRoom(roomId); // setup

  return () =&amp;gt; {
    connection.close(); // teardown
  };
}, [roomId]);&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;When &lt;code&gt;roomId&lt;/code&gt; changes, React closes the old connection before opening the new one. When the component leaves the screen, React closes the connection one last time. This is what most beginner tutorials describe as &quot;mounting and unmounting,&quot; but the more useful framing is &quot;open and close a connection.&quot;&lt;/p&gt;

  &lt;p&gt;That&apos;s the entire model. Setup runs after render. Teardown runs before the next setup or before unmount. The dependency array decides when to do another setup-teardown cycle.&lt;/p&gt;

  &lt;h2 id=&quot;when-not-to-write-an-effect&quot;&gt;&lt;a href=&quot;#when-not-to-write-an-effect&quot; class=&quot;heading-link&quot;&gt;When not to write an effect&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Now that you know what an effect does, it&apos;s easier to spot the cases where one shouldn&apos;t be there at all. Two patterns come up constantly.&lt;/p&gt;

  &lt;h3 id=&quot;deriving-a-value-from-props-or-state&quot;&gt;&lt;a href=&quot;#deriving-a-value-from-props-or-state&quot; class=&quot;heading-link&quot;&gt;Deriving a value from props or state&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;If a value can be calculated from existing props or state, calculate it during render. Don&apos;t reach for an effect:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;// Don&apos;t do this
function Greeting({ firstName, lastName }) {
  const [fullName, setFullName] = useState(&quot;&quot;);

  useEffect(() =&amp;gt; {
    setFullName(`${firstName} ${lastName}`);
  }, [firstName, lastName]);

  return &amp;lt;h1&amp;gt;Hello, {fullName}&amp;lt;/h1&amp;gt;;
}

// Do this
function Greeting({ firstName, lastName }) {
  const fullName = `${firstName} ${lastName}`;
  return &amp;lt;h1&amp;gt;Hello, {fullName}&amp;lt;/h1&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;The effect version forces React to render once with an empty &lt;code&gt;fullName&lt;/code&gt;, run the effect, then render again with the real value. Two renders to do the work of one. There&apos;s also nothing outside React being synchronized here, so the effect doesn&apos;t earn its place.&lt;/p&gt;

  &lt;h3 id=&quot;reacting-to-a-user-event&quot;&gt;&lt;a href=&quot;#reacting-to-a-user-event&quot; class=&quot;heading-link&quot;&gt;Reacting to a user event&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;If something should happen because a user clicked a button, that logic belongs in the click handler. It doesn&apos;t belong in an effect that fires after the resulting state change:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;// Don&apos;t do this
useEffect(() =&amp;gt; {
  if (product.isInCart) {
    showNotification(`Added ${product.name} to cart`);
  }
}, [product]);

// Do this
function handleAddToCart() {
  addToCart(product);
  showNotification(`Added ${product.name} to cart`);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;The effect version fires the notification any time &lt;code&gt;product&lt;/code&gt; changes, including on initial render if the product was already in the cart from a previous session. The handler version only fires when the user actually clicks. That&apos;s almost always what you want.&lt;/p&gt;

  &lt;p&gt;The general test is: &quot;is this code talking to something outside React?&quot; If no, it probably shouldn&apos;t be an effect.&lt;/p&gt;

  &lt;h2 id=&quot;three-things-to-pay-attention-to-when-writing-effects&quot;&gt;&lt;a href=&quot;#three-things-to-pay-attention-to-when-writing-effects&quot; class=&quot;heading-link&quot;&gt;Three things to pay attention to when writing effects&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Once you&apos;re writing real effects, three things determine whether they behave correctly. The first is positive: getting cleanup right. The other two are traps that catch most beginners.&lt;/p&gt;

  &lt;h3 id=&quot;1-clean-up-what-you-start&quot;&gt;&lt;a href=&quot;#1-clean-up-what-you-start&quot; class=&quot;heading-link&quot;&gt;1. Clean up what you start&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;Most subtle effect bugs come from missing cleanup. Whatever your setup starts, your teardown should stop. The shape is the same across every external system, just applied to different APIs.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Window event listeners.&lt;/strong&gt; The teardown removes the same function the setup added:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  function handleResize() {
    setWidth(window.innerWidth);
  }
  window.addEventListener(&quot;resize&quot;, handleResize);
  return () =&amp;gt; window.removeEventListener(&quot;resize&quot;, handleResize);
}, []);&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;&lt;code&gt;removeEventListener&lt;/code&gt; requires the same function reference that &lt;code&gt;addEventListener&lt;/code&gt; got, which is why &lt;code&gt;handleResize&lt;/code&gt; is named and reused.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Intervals.&lt;/strong&gt; The teardown clears the interval:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  const id = setInterval(() =&amp;gt; {
    setSeconds((s) =&amp;gt; s + 1);
  }, 1000);
  return () =&amp;gt; clearInterval(id);
}, []);&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;Using the functional form &lt;code&gt;setSeconds((s) =&amp;gt; s + 1)&lt;/code&gt; makes sure the callback always sees the current value, not a stale one captured when the interval was created.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Subscriptions.&lt;/strong&gt; Many APIs return an unsubscribe function, which you can return directly from the effect:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  return chatRoom.subscribe((message) =&amp;gt; {
    setMessages((messages) =&amp;gt; [...messages, message]);
  });
}, [chatRoom]);&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;&lt;strong&gt;Network requests.&lt;/strong&gt; The teardown either marks the response as ignored or aborts the request:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  let ignore = false;
  fetch(`/api/users/${userId}`)
    .then((res) =&amp;gt; res.json())
    .then((data) =&amp;gt; {
      if (!ignore) setUser(data);
    });
  return () =&amp;gt; {
    ignore = true;
  };
}, [userId]);&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;The &lt;code&gt;ignore&lt;/code&gt; flag prevents a stale response from overwriting newer data when &lt;code&gt;userId&lt;/code&gt; changes mid-request. One practical caveat: in production apps, libraries like TanStack Query and SWR, or framework data layers in Next.js and Remix, handle race conditions, caching, and loading states for you. Writing your own fetch effects is fine for learning and small projects, but it stops being the right call at scale.&lt;/p&gt;

  &lt;h3 id=&quot;2-effects-run-twice-in-development&quot;&gt;&lt;a href=&quot;#2-effects-run-twice-in-development&quot; class=&quot;heading-link&quot;&gt;2. Effects run twice in development&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;If you&apos;ve used React 18 or later, you&apos;ve probably seen an effect fire twice in development and wondered if something was broken. Nothing is broken. React&apos;s Strict Mode runs setup, then teardown, then setup again, on purpose.&lt;/p&gt;

  &lt;p&gt;The reason is that Strict Mode is testing whether your teardown actually works. If running setup-teardown-setup leaves your component in a broken state, the synchronization isn&apos;t symmetric, and it&apos;ll eventually break in production too when a dependency change legitimately causes React to teardown and reopen the connection.&lt;/p&gt;

  &lt;p&gt;A buggy effect makes this visible:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;// Logs two visits in development
useEffect(() =&amp;gt; {
  fetch(&quot;/api/visit&quot;, { method: &quot;POST&quot; });
}, []);&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;The fix is to add a teardown that cancels the in-flight request, or to move the analytics call somewhere that running it twice doesn&apos;t matter. Don&apos;t disable Strict Mode. It&apos;s catching a real bug for you while it&apos;s still cheap to fix.&lt;/p&gt;

  &lt;h3 id=&quot;3-referential-stability&quot;&gt;&lt;a href=&quot;#3-referential-stability&quot; class=&quot;heading-link&quot;&gt;3. Referential stability&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;Once you start writing dependency arrays carefully, you&apos;ll run into a frustrating-feeling case. The effect keeps firing on every render even though nothing seems to have changed. The cause is almost always referential stability.&lt;/p&gt;

  &lt;p&gt;React compares dependencies with &lt;code&gt;Object.is&lt;/code&gt;. For primitives like strings and numbers, that compares values. For objects, arrays, and functions, it compares references. Since the component function reruns on every render, anything you build inside the function body gets a fresh reference each time, even if the contents are identical:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;function SearchResults({ query }) {
  const options = { limit: 20, query };

  useEffect(() =&amp;gt; {
    search(options);
  }, [options]);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;&lt;code&gt;options&lt;/code&gt; is a new object on every render, so the effect runs on every render too. There are four reasonable ways out, and the right one depends on what the value is for.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Option 1: depend on the primitive.&lt;/strong&gt; If the object is only used inside the effect, build it inside the effect and depend on the primitive that actually changes:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  search({ limit: 20, query });
}, [query]);&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;This is the answer most of the time. Reach for it first.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Option 2: memoize the object.&lt;/strong&gt; If something else also needs the object, such as a child component or another hook, wrap it in &lt;code&gt;useMemo&lt;/code&gt; so its identity stays stable until its real inputs change:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;const options = useMemo(() =&amp;gt; ({ limit: 20, query }), [query]);&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;&lt;strong&gt;Option 3: memoize a function passed across components.&lt;/strong&gt; &lt;code&gt;useCallback&lt;/code&gt; matters when a function&apos;s identity is observed by something else, typically a memoized child:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;const runSearch = useCallback(() =&amp;gt; {
  search({ limit: 20, query });
}, [query]);

return &amp;lt;SearchButton onSearch={runSearch} /&amp;gt;;&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;If the function only lives inside one effect in one component, you don&apos;t need &lt;code&gt;useCallback&lt;/code&gt; at all; depend on &lt;code&gt;query&lt;/code&gt; directly.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Option 4: a ref for a value that should not retrigger the effect.&lt;/strong&gt; Sometimes the effect genuinely should not restart when a value changes, but the effect still needs to read the latest version. A ref gives you a stable container whose &lt;code&gt;.current&lt;/code&gt; you can update without triggering re-renders:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;const latestQueryRef = useRef(query);

useEffect(() =&amp;gt; {
  latestQueryRef.current = query;
}, [query]);

useEffect(() =&amp;gt; {
  const id = setInterval(() =&amp;gt; {
    search({ limit: 20, query: latestQueryRef.current });
  }, 5000);
  return () =&amp;gt; clearInterval(id);
}, []);&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;This works, but it&apos;s the option to reach for last. Refs hide which values actually drive the effect&apos;s behavior, and they make the dependency lint rule unable to help you. As of React 19.2, there&apos;s a cleaner tool for this exact case, which is in the next section.&lt;/p&gt;

  &lt;h2 id=&quot;related-hooks-that-extend-the-model&quot;&gt;&lt;a href=&quot;#related-hooks-that-extend-the-model&quot; class=&quot;heading-link&quot;&gt;Related hooks that extend the model&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Plain &lt;code&gt;useEffect&lt;/code&gt; covers most synchronization needs, but four situations have their own purpose-built tools. Each one solves a specific gap, and each one fits the same connection metaphor we&apos;ve been building on.&lt;/p&gt;

  &lt;h3 id=&quot;useeffectevent-read-a-value-without-restarting-the-effect&quot;&gt;&lt;a href=&quot;#useeffectevent-read-a-value-without-restarting-the-effect&quot; class=&quot;heading-link&quot;&gt;&lt;code&gt;useEffectEvent&lt;/code&gt;: read a value without restarting the effect&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;A common pain point with the dependency array is that it forces a bad trade. Either you list everything the effect reads, which is correct but may restart the connection more than you want, or you omit some values, which is wrong and makes the linter complain. The classic example is a chat room that wants to show a notification with the current theme:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;function ChatRoom({ roomId, theme }) {
  useEffect(() =&amp;gt; {
    const connection = openChatRoom(roomId);
    connection.on(&quot;connected&quot;, () =&amp;gt; {
      showNotification(&quot;Connected!&quot;, theme);
    });
    return () =&amp;gt; connection.close();
  }, [roomId, theme]); // Reconnects when theme changes
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;The connection only cares about &lt;code&gt;roomId&lt;/code&gt;. The notification call cares about &lt;code&gt;theme&lt;/code&gt;. Listing both as dependencies means changing the theme tears down the chat connection and opens a new one, which is wasteful and visibly wrong.&lt;/p&gt;

  &lt;p&gt;&lt;code&gt;useEffectEvent&lt;/code&gt;, stable since React 19.2 in October 2025, lets you split the &quot;event-like&quot; piece out of the effect. The effect still reads the latest &lt;code&gt;theme&lt;/code&gt; when the notification fires, but &lt;code&gt;theme&lt;/code&gt; no longer defines the connection&apos;s identity:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;import { useEffect, useEffectEvent } from &quot;react&quot;;

function ChatRoom({ roomId, theme }) {
  const onConnected = useEffectEvent(() =&amp;gt; {
    showNotification(&quot;Connected!&quot;, theme);
  });

  useEffect(() =&amp;gt; {
    const connection = openChatRoom(roomId);
    connection.on(&quot;connected&quot;, onConnected);
    return () =&amp;gt; connection.close();
  }, [roomId]); // Only reconnects when roomId changes
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;This replaces the &quot;ref to read the latest value&quot; trick from Option 4 in the previous section. The hook signals intent, this is an event-like callback fired from inside an effect, and the linter understands not to flag it as a missing dependency.&lt;/p&gt;

  &lt;h3 id=&quot;ref-callbacks-with-cleanup-when-the-connection-is-to-a-dom-node&quot;&gt;&lt;a href=&quot;#ref-callbacks-with-cleanup-when-the-connection-is-to-a-dom-node&quot; class=&quot;heading-link&quot;&gt;Ref callbacks with cleanup: when the connection is to a DOM node&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;Sometimes the thing being synchronized isn&apos;t your component, it&apos;s a specific DOM node. Imagine attaching a &lt;code&gt;ResizeObserver&lt;/code&gt; to a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; so you can react to its dimensions changing. The conventional approach used a &lt;code&gt;useRef&lt;/code&gt; plus a &lt;code&gt;useEffect&lt;/code&gt;:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;function MeasuredBox() {
  const ref = useRef(null);

  useEffect(() =&amp;gt; {
    if (!ref.current) return;
    const observer = new ResizeObserver(() =&amp;gt; {
      console.log(ref.current.getBoundingClientRect());
    });
    observer.observe(ref.current);
    return () =&amp;gt; observer.disconnect();
  }, []);

  return &amp;lt;div ref={ref}&amp;gt;...&amp;lt;/div&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;This works, but the &lt;code&gt;ResizeObserver&lt;/code&gt; is conceptually tied to the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, not to the component&apos;s lifetime. React 19 in December 2024 made ref callbacks, functions you pass directly to &lt;code&gt;ref&lt;/code&gt;, able to return cleanup functions, which lets you express that relationship directly:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;function MeasuredBox() {
  return (
    &amp;lt;div
      ref={(node) =&amp;gt; {
        const observer = new ResizeObserver(() =&amp;gt; {
          console.log(node.getBoundingClientRect());
        });
        observer.observe(node);
        return () =&amp;gt; observer.disconnect();
      }}
    &amp;gt;
      ...
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;The setup runs when React attaches the ref, and the cleanup runs when the node is detached or replaced. There&apos;s no &lt;code&gt;useRef&lt;/code&gt;, no &lt;code&gt;useEffect&lt;/code&gt;, and no null check. The synchronization is colocated with the node it depends on.&lt;/p&gt;

  &lt;p&gt;The rule of thumb: if the thing being synchronized is &quot;this DOM node,&quot; prefer a ref callback with cleanup. If it&apos;s &quot;this component&apos;s lifetime in general,&quot; use &lt;code&gt;useEffect&lt;/code&gt;.&lt;/p&gt;

  &lt;h3 id=&quot;usesyncexternalstore-subscribing-to-data-that-drives-rendering&quot;&gt;&lt;a href=&quot;#usesyncexternalstore-subscribing-to-data-that-drives-rendering&quot; class=&quot;heading-link&quot;&gt;&lt;code&gt;useSyncExternalStore&lt;/code&gt;: subscribing to data that drives rendering&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;You can subscribe to an external data source with &lt;code&gt;useEffect&lt;/code&gt;, and the cleanup pattern from earlier works fine:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(true);

  useEffect(() =&amp;gt; {
    function update() {
      setIsOnline(navigator.onLine);
    }
    update();
    window.addEventListener(&quot;online&quot;, update);
    window.addEventListener(&quot;offline&quot;, update);
    return () =&amp;gt; {
      window.removeEventListener(&quot;online&quot;, update);
      window.removeEventListener(&quot;offline&quot;, update);
    };
  }, []);

  return isOnline;
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;This is fine for most cases. But when the external data drives what you actually render, such as a Redux store, a Zustand store, &lt;code&gt;navigator.onLine&lt;/code&gt;, or anything where the value affects the UI, React provides &lt;code&gt;useSyncExternalStore&lt;/code&gt;, which handles concurrent rendering edge cases that &lt;code&gt;useEffect&lt;/code&gt; cannot:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;function subscribe(callback) {
  window.addEventListener(&quot;online&quot;, callback);
  window.addEventListener(&quot;offline&quot;, callback);
  return () =&amp;gt; {
    window.removeEventListener(&quot;online&quot;, callback);
    window.removeEventListener(&quot;offline&quot;, callback);
  };
}

function useOnlineStatus() {
  return useSyncExternalStore(
    subscribe,
    () =&amp;gt; navigator.onLine,    // current value on the client
    () =&amp;gt; true                  // current value on the server
  );
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;The hook takes a subscribe function, same shape as your effect&apos;s setup, a function that returns the current value, and an optional function that returns the value during server rendering. You&apos;ll most often see this through libraries, since Zustand and React Redux both use it under the hood, but it&apos;s worth knowing about when you&apos;re writing your own subscription logic.&lt;/p&gt;

  &lt;h3 id=&quot;uselayouteffect-when-synchronization-has-to-happen-before-paint&quot;&gt;&lt;a href=&quot;#uselayouteffect-when-synchronization-has-to-happen-before-paint&quot; class=&quot;heading-link&quot;&gt;&lt;code&gt;useLayoutEffect&lt;/code&gt;: when synchronization has to happen before paint&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; runs after the browser paints, which keeps the screen feeling responsive. Once in a while, you need synchronization that has to happen &lt;em&gt;before&lt;/em&gt; paint so the user doesn&apos;t see a flicker. Positioning a tooltip based on its measured width is the canonical case: if you measure and adjust in &lt;code&gt;useEffect&lt;/code&gt;, the user briefly sees the tooltip in the wrong place before it snaps into position.&lt;/p&gt;

  &lt;p&gt;&lt;code&gt;useLayoutEffect&lt;/code&gt; has the same API as &lt;code&gt;useEffect&lt;/code&gt; but runs synchronously before paint:&lt;/p&gt;

  &lt;code-block language=&quot;jsx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;useLayoutEffect(() =&amp;gt; {
  const { width } = tooltipRef.current.getBoundingClientRect();
  setLeft(triggerLeft - width / 2);
}, [triggerLeft]);&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;Use it only when you actually need it. It blocks the screen from updating until your effect finishes, so the responsiveness benefit of plain &lt;code&gt;useEffect&lt;/code&gt; is gone. If you ever notice a one-frame flash between an effect&apos;s setup and what the user sees, that&apos;s the signal that the effect should probably be a &lt;code&gt;useLayoutEffect&lt;/code&gt;.&lt;/p&gt;

  &lt;h2 id=&quot;a-checklist-before-writing-an-effect&quot;&gt;&lt;a href=&quot;#a-checklist-before-writing-an-effect&quot; class=&quot;heading-link&quot;&gt;A checklist before writing an effect&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Before reaching for &lt;code&gt;useEffect&lt;/code&gt;, ask:&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;Am I synchronizing with something outside React, or am I deriving a value from props and state? If it&apos;s the latter, calculate during render instead.&lt;/li&gt;
    &lt;li&gt;What is the external system, and what defines the identity of the connection to it?&lt;/li&gt;
    &lt;li&gt;What values does that identity depend on? Are they all in the dependency array?&lt;/li&gt;
    &lt;li&gt;Does my teardown actually undo what my setup did?&lt;/li&gt;
    &lt;li&gt;Will this still behave correctly under Strict Mode&apos;s setup-teardown-setup pattern in development?&lt;/li&gt;
    &lt;li&gt;Is the connection tied to a specific DOM node? A ref callback with cleanup might be a better fit.&lt;/li&gt;
    &lt;li&gt;Is the effect reading a value that shouldn&apos;t restart it? &lt;code&gt;useEffectEvent&lt;/code&gt; is built for that.&lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;The rules underneath these questions are simple. If your effect starts something, stop it. If it reads a value that can change, list that value as a dependency unless you have a deliberate reason not to. If you&apos;re only moving React values around inside React, you don&apos;t need an effect at all.&lt;/p&gt;

  &lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; isn&apos;t an arbitrary hook with a weird name and surprising behavior. It&apos;s React&apos;s interface to the world outside it. Once you start treating it that way, the rest of the rules write themselves.&lt;/p&gt;

  &lt;h2 id=&quot;further-reading&quot;&gt;&lt;a href=&quot;#further-reading&quot; class=&quot;heading-link&quot;&gt;Further reading&lt;/a&gt;&lt;/h2&gt;

  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://react.dev/learn/synchronizing-with-effects&quot;&gt;&lt;em&gt;Synchronizing with Effects&lt;/em&gt;&lt;/a&gt;, official React documentation&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://react.dev/learn/you-might-not-need-an-effect&quot;&gt;&lt;em&gt;You Might Not Need an Effect&lt;/em&gt;&lt;/a&gt;, the canonical &quot;don&apos;t reach for &lt;code&gt;useEffect&lt;/code&gt; first&quot; guide&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://react.dev/reference/react/useEffectEvent&quot;&gt;&lt;em&gt;useEffectEvent&lt;/em&gt; reference&lt;/a&gt;, for the new hook stabilized in React 19.2&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://react.dev/reference/react/useSyncExternalStore&quot;&gt;&lt;em&gt;useSyncExternalStore&lt;/em&gt; reference&lt;/a&gt;, for store subscriptions&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://x.com/alvinsng/status/2033969062834045089&quot;&gt;Alvin Sng on banning direct &lt;code&gt;useEffect&lt;/code&gt;&lt;/a&gt;, an opinionated take from a production codebase&lt;/li&gt;
  &lt;/ul&gt;</content>
    <author><name>Tosin Amuda</name></author>
  </entry>
  <entry>
    <title>LLM Agents: A Gentle Introduction</title>
    <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/llm-agents-gentle-introduction.html" />
    <id>https://www.tosinamuda.com/blog/llm-agents-gentle-introduction.html</id>
    <updated>2026-04-25T00:00:00.000Z</updated>
    <published>2026-04-25T00:00:00.000Z</published>
    <summary>A developer-friendly introduction to LLM agents: what they are, how they run, what tools and memory do, and where to start.</summary>
    <content type="html">&lt;p&gt;A developer-friendly introduction to LLM agents: what they are, how they run, what tools and memory do, and where to start.&lt;/p&gt;&lt;p&gt;When developers first hear &quot;AI agent&quot; or &quot;agentic AI,&quot; a fair question follows: how is this different from sending a prompt to ChatGPT and getting a response back?&lt;/p&gt;

  &lt;p&gt;A raw language model call is a single round trip. You send input, the model returns output, and the exchange ends. By itself, the model cannot decide to search your docs, call your database, run a test, inspect a file, or check whether its answer worked.&lt;/p&gt;

  &lt;p&gt;An agent extends that single call into a loop. The model can decide what to do next, call a tool, read the result, update its context, and keep going until the task is finished, blocked, or stopped by a limit.&lt;/p&gt;

  &lt;p&gt;The simplest way to say it is:&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;An LLM agent is a language model inside a loop, connected to tools, memory, and an environment.&lt;/p&gt;
  &lt;/blockquote&gt;

  &lt;figure&gt;
    &lt;img src=&quot;/images/blog/llm-agents/single-call-vs-agent.png&quot; alt=&quot;Diagram comparing a single LLM call with an agent loop that remembers context, calls tools, observes results, and decides what to do next.&quot;&gt;
    &lt;figcaption&gt;A single LLM call is input to output. An agent wraps the model in a loop that can act, observe, and continue.&lt;/figcaption&gt;
  &lt;/figure&gt;

  &lt;p&gt;At every step, the model still only sees input. That input may contain system instructions, user messages, tool definitions, memory snippets, prior tool results, and retrieved documents. In that practical sense, everything the model sees is a prompt. The engineering work is deciding what should be assembled into that prompt at each step.&lt;/p&gt;

  &lt;h2 id=&quot;what-is-an-ai-agent&quot;&gt;&lt;a href=&quot;#what-is-an-ai-agent&quot; class=&quot;heading-link&quot;&gt;What is an AI agent?&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Agents are older than LLMs. In classical AI, an agent is something that perceives an environment and acts on it to achieve a goal. That definition covers simple systems such as thermostats and complex systems such as chess engines, robots, and reinforcement learning policies.&lt;/p&gt;

  &lt;p&gt;What they share is a shape:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;There is a goal.&lt;/li&gt;
    &lt;li&gt;There is an environment.&lt;/li&gt;
    &lt;li&gt;The agent observes something about that environment.&lt;/li&gt;
    &lt;li&gt;The agent chooses an action.&lt;/li&gt;
    &lt;li&gt;The environment changes or returns feedback.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;An LLM-based agent fits the same shape. The user&apos;s task is the goal. The model is the decision-maker. Tools are actions. Tool results are observations. The environment is whatever the agent can act on: a browser, a codebase, a database, a calendar, an API, or a sandbox.&lt;/p&gt;

  &lt;p&gt;So &quot;agent&quot; does not name one specific technology. It names a pattern: observe, decide, act, observe again.&lt;/p&gt;

  &lt;figure&gt;
    &lt;img src=&quot;/images/blog/llm-agents/agent-loop.png&quot; alt=&quot;Diagram showing thermostats, chess engines, robots, and LLM agents as the same observe-decide-act pattern with different decision makers.&quot;&gt;
    &lt;figcaption&gt;The agent pattern predates LLMs. The shape stays the same; the decision-maker changes.&lt;/figcaption&gt;
  &lt;/figure&gt;

  &lt;h2 id=&quot;llms-as-the-brain-of-the-agent&quot;&gt;&lt;a href=&quot;#llms-as-the-brain-of-the-agent&quot; class=&quot;heading-link&quot;&gt;LLMs as the brain of the agent&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;For a long time, the hard part was the policy: the logic that maps an observation to the next action. Hand-written rules were brittle. Search systems could explode in complexity. Learned policies often needed task-specific data and training.&lt;/p&gt;

  &lt;p&gt;LLMs changed the bottleneck. A modern instruction-following model can read a natural-language goal, inspect a list of available tools, choose a tool, fill in structured arguments, and interpret the result. That does not make the model the whole agent, but it makes the model a useful decision engine inside the agent.&lt;/p&gt;

  &lt;p&gt;Three capabilities made this practical:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Instruction following:&lt;/strong&gt; you can describe behavior in prose.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Structured output:&lt;/strong&gt; the model can return JSON or function calls the harness can route.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Long context:&lt;/strong&gt; the model can receive enough task history, tool output, and retrieved context to continue across multiple steps.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;Reasoning improved sharply too, and that is where most agent discussions begin.&lt;/p&gt;

  &lt;h2 id=&quot;the-capabilities-of-an-agent&quot;&gt;&lt;a href=&quot;#the-capabilities-of-an-agent&quot; class=&quot;heading-link&quot;&gt;The capabilities of an agent&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Three capabilities sit at the core of most useful agents: reasoning, tools, and memory.&lt;/p&gt;

  &lt;figure&gt;
    &lt;img src=&quot;/images/blog/llm-agents/agent-capabilities.png&quot; alt=&quot;Diagram showing reasoning as choosing the next step, tools as reaching outside the model, and memory as carrying state forward.&quot;&gt;
    &lt;figcaption&gt;Useful agents need reasoning to choose, tools to act, and memory to carry context forward.&lt;/figcaption&gt;
  &lt;/figure&gt;

  &lt;h3 id=&quot;reasoning&quot;&gt;&lt;a href=&quot;#reasoning&quot; class=&quot;heading-link&quot;&gt;Reasoning&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;Chain-of-thought prompting was an eye-opening moment. Before it, many developers did not have a practical reason to believe that asking a model to show intermediate steps could improve difficult answers. The model was not given a new tool or a new training run. The prompt simply gave it room to work through the problem.&lt;/p&gt;

  &lt;code-block language=&quot;text&quot;&gt;
    &lt;pre&gt;&lt;code&gt;User: A bakery has 23 cupcakes. They sell 8 in the morning
and bake 12 more in the afternoon. How many at the end of the day?

Prompt addition: Think step by step.

Model:
Start with 23.
After selling 8: 23 - 8 = 15.
After baking 12: 15 + 12 = 27.
Answer: 27.&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;The safer way to phrase the lesson is: no task-specific training was needed. The reasoning behavior was latent enough that a better prompt could surface it.&lt;/p&gt;

  &lt;p&gt;ReAct extended that idea into an agent loop. Instead of only writing intermediate reasoning, the model alternates between reasoning and actions:&lt;/p&gt;

  &lt;code-block language=&quot;text&quot;&gt;
    &lt;pre&gt;&lt;code&gt;Task: What is the population of the capital of Slovakia?

Thought: I need the capital first.
Action: search(&quot;capital of Slovakia&quot;)
Observation: The capital of Slovakia is Bratislava.

Thought: Now I need Bratislava&apos;s population.
Action: search(&quot;Bratislava population&quot;)
Observation: Approximately 475,000 residents.

Final: Approximately 475,000.&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;ReAct mattered because it grounded reasoning in feedback from the world. The model could think, act, observe, and revise.&lt;/p&gt;

  &lt;p&gt;The newer shift is the reasoning model. For a gentle introduction, you can think of these as &quot;thinking models&quot;: models trained to spend more computation on hard problems before producing a final answer. The standard terms are reasoning models and test-time compute. OpenAI&apos;s o1 and DeepSeek-R1 made this pattern widely visible.&lt;/p&gt;

  &lt;p&gt;The important point for agent builders is that these ideas stack. A reasoning model can run inside a ReAct-style loop. The model handles hard local reasoning; the loop handles tools, observations, and grounding.&lt;/p&gt;

  &lt;h3 id=&quot;tools&quot;&gt;&lt;a href=&quot;#tools&quot; class=&quot;heading-link&quot;&gt;Tools&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;Tools are how an agent reaches outside the model. A tool might search documents, query a database, send an email, inspect a GitHub issue, run code, or control a browser.&lt;/p&gt;

  &lt;p&gt;The model learns which tools exist because tool names, descriptions, and argument schemas are included in the model input.&lt;/p&gt;

  &lt;code-block language=&quot;text&quot;&gt;
    &lt;pre&gt;&lt;code&gt;You have access to these tools:

search_docs(query: string, top_k: number)
  Search the knowledge base for documents matching a query.

send_email(to: string, subject: string, body: string)
  Send an email to a recipient.&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;When the model chooses a tool, it produces structured output. The harness reads that output, runs the actual function in the environment, and feeds the result back as the next observation.&lt;/p&gt;

  &lt;code-block language=&quot;json&quot;&gt;
    &lt;pre&gt;&lt;code&gt;{
  &quot;tool&quot;: &quot;search_docs&quot;,
  &quot;arguments&quot;: {
    &quot;query&quot;: &quot;Q3 report&quot;,
    &quot;top_k&quot;: 5
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;Early agent systems used many custom wrappers. Every framework had its own tool format, and every provider had a slightly different function-calling shape. The Model Context Protocol, released by Anthropic in November 2024, standardizes the client-server boundary for tools and resources. Once an MCP server exists, an agent client can discover and call its tools without a one-off integration for that specific provider.&lt;/p&gt;

  &lt;p&gt;There is still engineering work. Someone has to expose the useful API as an MCP server, handle authentication, define permissions, and decide what tool outputs should look like. MCP reduces integration friction; it does not remove design work.&lt;/p&gt;

  &lt;p&gt;As tool catalogs grow, another problem appears: you cannot always put every tool definition into the model context. Tool search solves this by loading only the relevant tools on demand. Claude Code&apos;s tool-search documentation is a good practical example of this pattern.&lt;/p&gt;

  &lt;p&gt;There is also CodeAct, where the model writes executable code instead of emitting one JSON tool call at a time. That can be powerful because code can use variables, loops, and multiple API calls in one action. It also raises the bar for sandboxing and safety.&lt;/p&gt;

  &lt;h3 id=&quot;memory&quot;&gt;&lt;a href=&quot;#memory&quot; class=&quot;heading-link&quot;&gt;Memory&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;The model does not remember previous calls by itself. Each call starts from the input it receives. If the agent &quot;remembers&quot; something, the harness or a tool has put that memory back into the model context.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Short-term memory&lt;/strong&gt; is the running state of the current task: messages, prior tool calls, prior observations, scratchpad notes, and partial outputs.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Long-term memory&lt;/strong&gt; persists across tasks: user preferences, project facts, prior decisions, or stored documents. It usually lives outside the model in a database, vector store, file, or application backend.&lt;/p&gt;

  &lt;p&gt;The hard part is not only storage. The hard part is deciding what to save, when to retrieve it, and how much to put back into context. Too little memory makes the agent forgetful. Too much memory floods the prompt with noise.&lt;/p&gt;

  &lt;h2 id=&quot;the-anatomy-of-a-running-agent&quot;&gt;&lt;a href=&quot;#the-anatomy-of-a-running-agent&quot; class=&quot;heading-link&quot;&gt;The anatomy of a running agent&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;The capabilities explain what an agent can do. The anatomy explains how it runs.&lt;/p&gt;

  &lt;figure&gt;
    &lt;img src=&quot;/images/blog/llm-agents/running-agent-anatomy.png&quot; alt=&quot;Diagram showing how the scaffold feeds the agent harness, the harness runs the loop, and tools act on an environment such as a filesystem, browser, database, shell, or APIs.&quot;&gt;
    &lt;figcaption&gt;The model is only one part. The harness, scaffold, and environment make the agent usable.&lt;/figcaption&gt;
  &lt;/figure&gt;

  &lt;h3 id=&quot;the-loop&quot;&gt;&lt;a href=&quot;#the-loop&quot; class=&quot;heading-link&quot;&gt;The loop&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;The core loop is simple:&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;Build the model input.&lt;/li&gt;
    &lt;li&gt;Call the model.&lt;/li&gt;
    &lt;li&gt;Parse the model response.&lt;/li&gt;
    &lt;li&gt;If the model is done, return the answer.&lt;/li&gt;
    &lt;li&gt;If the model requested a tool, run the tool.&lt;/li&gt;
    &lt;li&gt;Add the result to context.&lt;/li&gt;
    &lt;li&gt;Repeat until done, blocked, or out of budget.&lt;/li&gt;
  &lt;/ol&gt;

  &lt;h3 id=&quot;the-harness&quot;&gt;&lt;a href=&quot;#the-harness&quot; class=&quot;heading-link&quot;&gt;The harness&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;The harness is the runtime code that drives that loop.&lt;/p&gt;

  &lt;code-block language=&quot;javascript&quot;&gt;
    &lt;pre&gt;&lt;code&gt;function runAgent(task, scaffold, environment) {
  let context = buildInitialContext(scaffold, task);

  for (let step = 0; step &amp;lt; maxSteps; step++) {
    const response = model.call(context);

    if (response.isComplete()) {
      return response.answer;
    }

    const toolCall = response.toolCall;
    const result = environment.execute(toolCall);

    context = appendToContext(context, response, result);
    context = compactIfNeeded(context);
  }

  return timedOut();
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;Most production concerns live in the harness: tracing, retries, rate limits, cost tracking, malformed output recovery, context compaction, approval gates, and stopping conditions. A demo can survive with a weak harness. A production agent usually cannot.&lt;/p&gt;

  &lt;h3 id=&quot;the-environment&quot;&gt;&lt;a href=&quot;#the-environment&quot; class=&quot;heading-link&quot;&gt;The environment&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;The environment is the world the agent acts on. For a coding agent, that might be a repository, shell, filesystem, test runner, and browser. For a support agent, it might be a CRM, ticketing system, knowledge base, and email API.&lt;/p&gt;

  &lt;p&gt;Two questions matter:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Is the action deterministic?&lt;/strong&gt; Running a local parser is easier to reason about than searching the web.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Is the action reversible?&lt;/strong&gt; Editing a sandboxed file can be undone. Sending money or deleting production data cannot.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;The less deterministic and less reversible the environment is, the more guardrails you need: narrow permissions, dry-run modes, human approval, audit logs, and rollback plans.&lt;/p&gt;

  &lt;h3 id=&quot;the-instruction-scaffold&quot;&gt;&lt;a href=&quot;#the-instruction-scaffold&quot; class=&quot;heading-link&quot;&gt;The instruction scaffold&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;The terms scaffold and harness are not fully standardized. People often use agent scaffolding and agent harness interchangeably to mean &quot;the software around the model.&quot; That is fine in casual conversation, but the distinction is useful when you are building.&lt;/p&gt;

  &lt;p&gt;In this article, the scaffold is the structure available before the agent runs: role, behavioral rules, tool definitions, permissions, memory conventions, and output formats.&lt;/p&gt;

  &lt;code-block language=&quot;text&quot;&gt;
    &lt;pre&gt;&lt;code&gt;[role]
You are a research assistant for software developers.

[rules]
- Cite sources.
- Search before answering if the answer may have changed.
- Ask before taking irreversible actions.

[tools]
- search_docs(query, top_k)
- fetch_url(url)

[output format]
Respond in markdown with source links.&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;The harness assembles the scaffold with runtime context: the current task, today&apos;s date, retrieved memory, previous tool results, and anything else the model needs for the next step.&lt;/p&gt;

  &lt;h3 id=&quot;everything-the-model-sees-is-a-prompt&quot;&gt;&lt;a href=&quot;#everything-the-model-sees-is-a-prompt&quot; class=&quot;heading-link&quot;&gt;Everything the model sees is a prompt&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;This is the unifying idea. The model does not see your database connection, your app server, your vector store, or your tool registry directly. It sees the input the harness gives it.&lt;/p&gt;

  &lt;p&gt;That input is systematically assembled context. It may contain static instructions from the scaffold, dynamic facts from the environment, retrieved memory, tool schemas, and observations from previous steps. To the model, all of that is the prompt.&lt;/p&gt;

  &lt;p&gt;If the agent chooses the wrong next action, the bug is often in this assembled prompt: missing tool description, unclear instruction, stale memory, noisy retrieval, ambiguous output format, or a tool result that lost the important detail.&lt;/p&gt;

  &lt;p&gt;This is why context engineering is becoming a core agent skill. You are not just &quot;writing prompts.&quot; You are designing the information surface the model uses to act.&lt;/p&gt;

  &lt;h2 id=&quot;architectural-patterns&quot;&gt;&lt;a href=&quot;#architectural-patterns&quot; class=&quot;heading-link&quot;&gt;Architectural patterns&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Once you understand a single agent, the next question is how to compose systems.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;A workflow&lt;/strong&gt; is a fixed sequence of steps. Your code decides what happens next. The model may summarize, classify, extract, or generate at each step, but the path is known ahead of time.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;A single agent&lt;/strong&gt; is one model-driven loop with access to tools. The model decides the next action based on the current context. This is the best starting point when the task path is uncertain.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;A multi-agent system&lt;/strong&gt; uses multiple agents, often with specialized roles. This can help when work naturally splits across domains, but it also adds communication overhead, coordination failures, and harder debugging.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;An orchestrator-worker pattern&lt;/strong&gt; is the most common useful multi-agent shape. One orchestrator breaks the task into subtasks and delegates to workers. Mechanically, calling a worker agent is just a tool call where the implementation happens to be another agent.&lt;/p&gt;

  &lt;p&gt;The honest guidance is boring and useful: start with a workflow when the steps are predictable. Use a single agent when the path is genuinely uncertain. Reach for multi-agent systems only when you have evidence that one agent with better tools is not enough.&lt;/p&gt;

  &lt;h2 id=&quot;customizing-agents&quot;&gt;&lt;a href=&quot;#customizing-agents&quot; class=&quot;heading-link&quot;&gt;Customizing agents&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;The cheapest way to change an agent is to change the prompt: improve the role, tighten the output format, clarify tool descriptions, add examples, or change what memory gets injected.&lt;/p&gt;

  &lt;p&gt;When manual prompting plateaus, three stronger options show up.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Prompt optimization&lt;/strong&gt; treats the prompt as something that can be searched and tuned against a metric. DSPy is the clearest example: you define a language-model program, provide a metric and examples, and let an optimizer improve instructions or demonstrations.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Supervised fine-tuning&lt;/strong&gt; trains a model on examples of the behavior you want. It is useful when you need a stable format, domain-specific language, or a smaller model to imitate a larger one. It also gives you a model artifact to maintain.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Reinforcement learning with verifiable rewards&lt;/strong&gt; is useful when correctness can be checked automatically: math answers, code that passes tests, structured outputs that parse, or tasks with clear success signals. For most application developers, this is something you consume by choosing a reasoning model, not something you run yourself.&lt;/p&gt;

  &lt;p&gt;The order matters. Start with better context. Add prompt optimization when you have a metric. Consider SFT when prompting cannot reliably produce the behavior. Treat RL with verifiable rewards as advanced training infrastructure.&lt;/p&gt;

  &lt;h2 id=&quot;frameworks-at-a-glance&quot;&gt;&lt;a href=&quot;#frameworks-at-a-glance&quot; class=&quot;heading-link&quot;&gt;Frameworks at a glance&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;A framework is a set of opinions about harness, scaffold, tools, state, and deployment.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;LangChain and LangGraph&lt;/strong&gt; are widely used in the Python and JavaScript ecosystem. LangChain gives agent and tool abstractions; LangGraph gives an explicit graph runtime with state, persistence, interrupts, and human-in-the-loop patterns.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Google ADK&lt;/strong&gt; is a code-first framework for developing and deploying agents. It is optimized for Gemini and the Google ecosystem, but the official docs describe it as model-agnostic and deployment-agnostic.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;BeeAI Framework&lt;/strong&gt; is an open-source framework for building production-grade multi-agent systems with provider-agnostic model support and memory strategies.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Agent Stack&lt;/strong&gt;, formerly BeeAI Platform, is deployment and runtime infrastructure. It helps run agents as services, with a web UI, CLI, LLM routing, storage, document extraction, secrets, OAuth, MCP integrations, and A2A compatibility.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;DSPy&lt;/strong&gt; is different from graph frameworks. It treats prompts and LM calls as parts of a typed program that can be optimized against examples and metrics.&lt;/p&gt;

  &lt;p&gt;Do not pick a framework because it is popular. Pick it because its mental model matches the problem you are solving.&lt;/p&gt;

  &lt;h2 id=&quot;where-to-start&quot;&gt;&lt;a href=&quot;#where-to-start&quot; class=&quot;heading-link&quot;&gt;Where to start&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;The smallest useful project is a ReAct-style agent with one real tool.&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;Pick a model with function calling or structured output.&lt;/li&gt;
    &lt;li&gt;Define one tool that does something real.&lt;/li&gt;
    &lt;li&gt;Write the loop yourself.&lt;/li&gt;
    &lt;li&gt;Log every model input, tool call, observation, and final answer.&lt;/li&gt;
    &lt;li&gt;Add a stopping condition and a step budget.&lt;/li&gt;
    &lt;li&gt;Add one small eval set: five to ten tasks you expect it to handle.&lt;/li&gt;
    &lt;li&gt;Only then move the same idea into a framework.&lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;You will hit the real problems quickly. The model will ask for a tool that does not exist. A tool will fail. Context will get noisy. The agent will repeat itself. Each failure teaches something specific about harness design, scaffold writing, tool design, memory, or context engineering.&lt;/p&gt;

  &lt;p&gt;That is the durable lesson: an agent is not just an LLM. It is a model inside a runtime loop, shaped by a scaffold, connected to tools, operating in an environment, and fed by carefully assembled context.&lt;/p&gt;

  &lt;h2 id=&quot;further-reading&quot;&gt;&lt;a href=&quot;#further-reading&quot; class=&quot;heading-link&quot;&gt;Further reading&lt;/a&gt;&lt;/h2&gt;

  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://huggingface.co/papers/2201.11903&quot;&gt;Chain-of-Thought Prompting Elicits Reasoning in Large Language Models&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://react-lm.github.io/&quot;&gt;ReAct: Synergizing Reasoning and Acting in Language Models&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://openai.com/index/learning-to-reason-with-llms/&quot;&gt;OpenAI: Learning to reason with LLMs&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.anthropic.com/news/model-context-protocol&quot;&gt;Anthropic: Introducing the Model Context Protocol&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.anthropic.com/research/building-effective-agents/&quot;&gt;Anthropic: Building effective agents&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://code.claude.com/docs/en/agent-sdk/tool-search&quot;&gt;Claude Code docs: Tool search&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://docs.cloud.google.com/agent-builder/agent-development-kit/overview&quot;&gt;Google Cloud: Agent Development Kit overview&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://agentstack.beeai.dev/stable/introduction/welcome&quot;&gt;Agent Stack documentation&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://dspy.ai/&quot;&gt;DSPy documentation&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;</content>
    <author><name>Tosin Amuda</name></author>
  </entry>
  <entry>
    <title>Towards a More Trustworthy Electoral Architecture for National Elections in Nigeria: The Presidential Election Results Collation Case Study</title>
    <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/inec-presidential-election-collation-architecture.html" />
    <id>https://www.tosinamuda.com/blog/inec-presidential-election-collation-architecture.html</id>
    <updated>2026-04-25T00:00:00.000Z</updated>
    <published>2026-04-25T00:00:00.000Z</published>
    <summary>Nigeria&apos;s presidential results still depend on repeated manual collation. This article maps the failure points and proposes a new architecture: BVAS as the capture device, mandatory e-transmission, and a public electronic register for collation.</summary>
    <content type="html">&lt;p&gt;Nigeria&apos;s presidential results still depend on repeated manual collation. This article maps the failure points and proposes a new architecture: BVAS as the capture device, mandatory e-transmission, and a public electronic register for collation.&lt;/p&gt;&lt;inec-collation&gt;&lt;/inec-collation&gt;</content>
    <author><name>Tosin Amuda</name></author>
  </entry>
  <entry>
    <title>Interesting Concept I Picked Up — Eliminate Stupid Mental Effort (ESME)</title>
    <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/interesting-concept-eliminate-stupid-mental-effort-esme.html" />
    <id>https://www.tosinamuda.com/blog/interesting-concept-eliminate-stupid-mental-effort-esme.html</id>
    <updated>2020-12-20T00:00:00.000Z</updated>
    <published>2020-12-20T00:00:00.000Z</published>
    <summary>I discovered Andela&apos;s Eliminate Stupid Mental Effort concept in 2019, a refreshing perspective for Nigerian developers. ESME addresses the unnecessary mental exertion we endure daily, much like enduring Lagos traffic.</summary>
    <content type="html">&lt;p&gt;I discovered Andela&apos;s Eliminate Stupid Mental Effort concept in 2019, a refreshing perspective for Nigerian developers. ESME addresses the unnecessary mental exertion we endure daily, much like enduring Lagos traffic.&lt;/p&gt;&lt;p&gt;Sometimes in 2019, I stumbled on &lt;a href=&quot;https://github.com/andela/bestpractices/wiki&quot;&gt;Andela Best Practices&lt;/a&gt; on GitHub and, for me, it was the closest you could get to an Andela education if you did not pass through Andela.&lt;/p&gt;

  &lt;p&gt;One of the very interesting concepts in their best practices is &lt;a href=&quot;https://github.com/andela/bestpractices/wiki/Eliminate-Stupid-Mental-Effort-(ESME)&quot;&gt;Eliminate Stupid Mental Effort (ESME)&lt;/a&gt;. I found the concept profound because it recognizes the environment we live in as Nigerian developers and the things we may have internalized while growing up in Nigeria that could affect the way we work.&lt;/p&gt;

  &lt;p&gt;To understand this concept, you first need to understand &lt;strong&gt;stupid mental effort&lt;/strong&gt;.&lt;/p&gt;

  &lt;p&gt;Let&apos;s look at a typical Lagosian life. Some people say in Lagos it is 5-9 and not 9-5.&lt;/p&gt;

  &lt;p&gt;You leave your house very early by 5AM to beat traffic and get to work on time. You struggle to enter public transport. Then you spend about 3 hours in traffic, and going back home can be even worse.&lt;/p&gt;

  &lt;p&gt;As inconvenient as this way of life is, Lagosians have become used to it because this is what they experience constantly and it has become the norm.&lt;/p&gt;

  &lt;p&gt;I remember a conversation with my friend who was in Rwanda for grad school. She complained that she could not get used to life in Rwanda because things felt slower compared to Lagos.&lt;/p&gt;

  &lt;p&gt;The problem with getting used to inconvenience is that when things become convenient we think something must be wrong, so we tend to do things the harder way.&lt;/p&gt;

  &lt;h2 id=&quot;what-are-the-possible-stupid-mental-efforts-you-can-encounter-as-a-developer&quot;&gt;&lt;a href=&quot;#what-are-the-possible-stupid-mental-efforts-you-can-encounter-as-a-developer&quot; class=&quot;heading-link&quot;&gt;What are the possible stupid mental efforts you can encounter as a developer?&lt;/a&gt;&lt;/h2&gt;

  &lt;ol&gt;
    &lt;li&gt;&lt;strong&gt;Using HTTPS instead of SSH to clone your repository.&lt;/strong&gt; When you clone with HTTPS, every remote Git operation asks again for username and password. That repeated friction can be avoided by cloning with SSH.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Manual testing and deployment instead of using a CI/CD pipeline.&lt;/strong&gt; Manually running tests and deploying code is time-consuming and error-prone when it can be automated.&lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;Andela puts it strongly: if you bring a mentality of being okay with inconvenience, or stupid mental effort, to your job as a software developer, you will never achieve greatness.&lt;/p&gt;

  &lt;h2 id=&quot;how-do-you-avoid-wasting-your-mental-energy-on-stupid-mental-effort&quot;&gt;&lt;a href=&quot;#how-do-you-avoid-wasting-your-mental-energy-on-stupid-mental-effort&quot; class=&quot;heading-link&quot;&gt;How do you avoid wasting your mental energy on stupid mental effort?&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;You must enter the &lt;strong&gt;lazy programmer mode&lt;/strong&gt; where you automate repetitive activities that waste your mental energy or find alternative solutions that make you more productive.&lt;/p&gt;

  &lt;p&gt;Which other stupid mental efforts can you think of, and how do you think we can address them as developers?&lt;/p&gt;</content>
    <author><name>Tosin Amuda</name></author>
  </entry>
  <entry>
    <title>Understanding Serverless using a Restaurant Server Analogy</title>
    <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/understanding-serverless-using-restaurant-server-analogy.html" />
    <id>https://www.tosinamuda.com/blog/understanding-serverless-using-restaurant-server-analogy.html</id>
    <updated>2020-03-11T00:00:00.000Z</updated>
    <published>2020-03-11T00:00:00.000Z</published>
    <summary>A simple explanation of the serverless cloud model using the analogy of two different types of restaurants: traditional busy restaurants versus futuristic clone-based service.</summary>
    <content type="html">&lt;p&gt;A simple explanation of the serverless cloud model using the analogy of two different types of restaurants: traditional busy restaurants versus futuristic clone-based service.&lt;/p&gt;&lt;p&gt;I will try to explain the &lt;strong&gt;serverless cloud model&lt;/strong&gt; using the analogy of two kinds of restaurants.&lt;/p&gt;

  &lt;h2 id=&quot;busy-restaurant-with-a-typical-server&quot;&gt;&lt;a href=&quot;#busy-restaurant-with-a-typical-server&quot; class=&quot;heading-link&quot;&gt;Busy restaurant with a typical server&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Imagine you walk into a busy restaurant and notice that there are more orders than servers. Requests are handled first come, first served, and when demand spikes, wait times increase.&lt;/p&gt;

  &lt;p&gt;That is similar to a traditional server-based model in the cloud. One server attends to several workloads, and even when load balancing spreads the traffic, the system still depends on pre-provisioned servers.&lt;/p&gt;

  &lt;h2 id=&quot;restaurant-of-the-future-serverless&quot;&gt;&lt;a href=&quot;#restaurant-of-the-future-serverless&quot; class=&quot;heading-link&quot;&gt;Restaurant of the future: serverless&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Now imagine a restaurant that employs a human clone outsourcing company. Every time a new order arrives, a fresh server-clone is created, assigned to that order, and destroyed as soon as the work is done.&lt;/p&gt;

  &lt;p&gt;That is the shape of serverless. A function or container image exists, and the cloud platform spins up a new execution environment for each request or event trigger.&lt;/p&gt;

  &lt;p&gt;Cloud platforms that offer serverless services let you write code in your preferred language without worrying about where to host it or how to scale it. The platform handles that operational layer for you.&lt;/p&gt;

  &lt;h2 id=&quot;what-are-the-benefits-of-serverless&quot;&gt;&lt;a href=&quot;#what-are-the-benefits-of-serverless&quot; class=&quot;heading-link&quot;&gt;What are the benefits of serverless?&lt;/a&gt;&lt;/h2&gt;

  &lt;ol&gt;
    &lt;li&gt;It is one of the cheapest models in the cloud because you only pay when your code executes.&lt;/li&gt;
    &lt;li&gt;You do not have to worry about scaling, because each invocation gets the compute it needs.&lt;/li&gt;
    &lt;li&gt;You do not have to manage server tuning, configuration, or maintenance.&lt;/li&gt;
  &lt;/ol&gt;

  &lt;h2 id=&quot;what-kinds-of-use-cases-benefit-from-serverless&quot;&gt;&lt;a href=&quot;#what-kinds-of-use-cases-benefit-from-serverless&quot; class=&quot;heading-link&quot;&gt;What kinds of use cases benefit from serverless?&lt;/a&gt;&lt;/h2&gt;

  &lt;ol&gt;
    &lt;li&gt;Event-based notification work, such as sending emails or SMS messages after user registration, or generating PDFs from reports.&lt;/li&gt;
    &lt;li&gt;Time-based triggers, such as scheduled tasks that send birthday messages or generate monthly reports.&lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;Popular serverless platforms include:&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;AWS Lambda&lt;/li&gt;
    &lt;li&gt;Google Cloud Functions&lt;/li&gt;
    &lt;li&gt;Azure Functions&lt;/li&gt;
    &lt;li&gt;IBM Cloud Functions&lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;The main value of serverless is not novelty. It is the removal of infrastructure work that does not need to sit in the developer&apos;s head.&lt;/p&gt;</content>
    <author><name>Tosin Amuda</name></author>
  </entry>
  <entry>
    <title>How to Containerize a React Application</title>
    <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/how-to-containerize-a-react-application.html" />
    <id>https://www.tosinamuda.com/blog/how-to-containerize-a-react-application.html</id>
    <updated>2020-03-11T00:00:00.000Z</updated>
    <published>2020-03-11T00:00:00.000Z</published>
    <summary>Learn how to containerize your React application using Docker with a step-by-step guide from creating a Dockerfile to running your container.</summary>
    <content type="html">&lt;p&gt;Learn how to containerize your React application using Docker with a step-by-step guide from creating a Dockerfile to running your container.&lt;/p&gt;&lt;p&gt;Containers and Kubernetes have become some of the enduring darlings of developers. A recent React deployment I needed to push into a Kubernetes environment made me revisit how much easier the job becomes once a Dockerfile is part of the workflow.&lt;/p&gt;

  &lt;p&gt;Before getting into the main guide, it helps to remember how much pain containers replace. In one of my internships, I worked as a pre-sales engineer for EduERP, an open-source ERP for universities.&lt;/p&gt;

  &lt;p&gt;EduERP ran on the LAMP stack and had a number of dependencies. Guiding a university through setup on its own server could take a full week because installation, configuration, and troubleshooting all had to be repeated manually. Docker would have changed that entire experience.&lt;/p&gt;

  &lt;h2 id=&quot;the-modern-approach&quot;&gt;&lt;a href=&quot;#the-modern-approach&quot; class=&quot;heading-link&quot;&gt;The modern approach&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Today the workflow can be reduced to five steps:&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;Create a Dockerfile containing all instructions for installing dependencies and running the application.&lt;/li&gt;
    &lt;li&gt;Build the Docker image from that Dockerfile.&lt;/li&gt;
    &lt;li&gt;Push the Docker image to a container repository.&lt;/li&gt;
    &lt;li&gt;Have the client pull the Docker image from the repository.&lt;/li&gt;
    &lt;li&gt;Run the Docker container.&lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;That shift means a setup that once took days can become a repeatable process measured in minutes.&lt;/p&gt;

  &lt;h2 id=&quot;pre-requisites&quot;&gt;&lt;a href=&quot;#pre-requisites&quot; class=&quot;heading-link&quot;&gt;Pre-requisites&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Before starting, make sure you have:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;Node.js installed in your development environment&lt;/li&gt;
    &lt;li&gt;Docker installed&lt;/li&gt;
    &lt;li&gt;A terminal of choice&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;If you do not have an existing React app, create one:&lt;/p&gt;

  &lt;code-block language=&quot;bash&quot;&gt;
    &lt;pre&gt;&lt;code&gt;npx create-react-app my-app
cd my-app&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;Create an Nginx configuration file that the Docker image can use to serve the application:&lt;/p&gt;

  &lt;code-block language=&quot;nginx&quot;&gt;
    &lt;pre&gt;&lt;code&gt;server {
    listen 8080;
    server_name frontend;
    location / {
        root /usr/share/nginx/html;
        try_files $uri /index.html;
    }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;h2 id=&quot;step-1-create-your-dockerfile&quot;&gt;&lt;a href=&quot;#step-1-create-your-dockerfile&quot; class=&quot;heading-link&quot;&gt;Step 1: Create your Dockerfile&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;For React apps, the development workflow is usually:&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;&lt;code&gt;npm install&lt;/code&gt; to install dependencies&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;npm run build&lt;/code&gt; to produce the optimized build output&lt;/li&gt;
    &lt;li&gt;Serve the built site through a web server such as Nginx&lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;That sequence leads directly to a multi-stage Dockerfile:&lt;/p&gt;

  &lt;code-block language=&quot;dockerfile&quot;&gt;
    &lt;pre&gt;&lt;code&gt;FROM bitnami/node:12-prod as builder
WORKDIR /app
COPY ./package.json /app/package.json
COPY ./yarn.lock /app/yarn.lock
ENV NODE_ENV=production
RUN yarn install --production
COPY . .
RUN yarn build

FROM nginxinc/nginx-unprivileged
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 8080&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;h2 id=&quot;step-2-build-the-image&quot;&gt;&lt;a href=&quot;#step-2-build-the-image&quot; class=&quot;heading-link&quot;&gt;Step 2: Build the image&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;Build the image with a tag of your choice:&lt;/p&gt;

  &lt;code-block language=&quot;bash&quot;&gt;
    &lt;pre&gt;&lt;code&gt;docker build -t my-react-app-name .&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;h2 id=&quot;step-3-run-the-container&quot;&gt;&lt;a href=&quot;#step-3-run-the-container&quot; class=&quot;heading-link&quot;&gt;Step 3: Run the container&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;To run the container, keep three things in mind:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;the container&apos;s internal port&lt;/li&gt;
    &lt;li&gt;the port on your own machine&lt;/li&gt;
    &lt;li&gt;the image name you used while building&lt;/li&gt;
  &lt;/ul&gt;

  &lt;code-block language=&quot;bash&quot;&gt;
    &lt;pre&gt;&lt;code&gt;docker run -p 8080:8080 my-react-app-name&lt;/code&gt;&lt;/pre&gt;
  &lt;/code-block&gt;

  &lt;p&gt;If everything works, &lt;code&gt;http://localhost:8080&lt;/code&gt; should serve the newly containerized React application.&lt;/p&gt;

  &lt;h2 id=&quot;next-steps&quot;&gt;&lt;a href=&quot;#next-steps&quot; class=&quot;heading-link&quot;&gt;Next steps&lt;/a&gt;&lt;/h2&gt;

  &lt;ul&gt;
    &lt;li&gt;Push the image to a registry such as Docker Hub&lt;/li&gt;
    &lt;li&gt;Create a Kubernetes pod definition to run the image&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;With Docker containers, deployment becomes consistent and predictable across environments. That is the real payoff.&lt;/p&gt;</content>
    <author><name>Tosin Amuda</name></author>
  </entry>
  <entry>
    <title>12-Factor Engineering Best Practices You Can Learn From</title>
    <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/12-factor-engineering-best-practices.html" />
    <id>https://www.tosinamuda.com/blog/12-factor-engineering-best-practices.html</id>
    <updated>2020-03-11T00:00:00.000Z</updated>
    <published>2020-03-11T00:00:00.000Z</published>
    <summary>Learn the 12 principles introduced by Heroku engineers for developing high-quality web applications with scale, robustness, and portability in mind.</summary>
    <content type="html">&lt;p&gt;Learn the 12 principles introduced by Heroku engineers for developing high-quality web applications with scale, robustness, and portability in mind.&lt;/p&gt;&lt;p&gt;During my Computer Science days at the University of Lagos, I used to wonder why software engineering was called engineering. Before then, I had always thought engineering had to be hardware.&lt;/p&gt;

  &lt;p&gt;Luckily, Ian Sommerville was thinking about confused people like me when he wrote &lt;strong&gt;Software Engineering&lt;/strong&gt;. He described software engineering as an engineering discipline concerned with all aspects of software production.&lt;/p&gt;

  &lt;p&gt;That framing helped. Engineering is still engineering because we make things work by applying theories, methods, and tools where appropriate. We also inherit best practices from other engineers so we can avoid already solved problems.&lt;/p&gt;

  &lt;p&gt;Similarly, the 12-factor methodology introduced by engineers at Heroku offers practical principles for building high-quality web applications with scale, robustness, and portability in mind.&lt;/p&gt;

  &lt;h2 id=&quot;the-12-factor-application-methodology&quot;&gt;&lt;a href=&quot;#the-12-factor-application-methodology&quot; class=&quot;heading-link&quot;&gt;The 12-factor application methodology&lt;/a&gt;&lt;/h2&gt;

  &lt;p&gt;The &lt;a href=&quot;https://12factor.net/&quot;&gt;12th Factor&lt;/a&gt; application methodology contains 12 principles for building a strong web application or SaaS product. It came from Heroku engineers after developing, deploying, and scaling thousands of applications.&lt;/p&gt;

  &lt;h3 id=&quot;factor-1-codebase&quot;&gt;&lt;a href=&quot;#factor-1-codebase&quot; class=&quot;heading-link&quot;&gt;Factor 1: Codebase&lt;/a&gt;&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;Track your source code in version control.&lt;/li&gt;
    &lt;li&gt;Keep one codebase per app and use branching strategies for different deployment paths.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;h3 id=&quot;factor-2-dependencies&quot;&gt;&lt;a href=&quot;#factor-2-dependencies&quot; class=&quot;heading-link&quot;&gt;Factor 2: Dependencies&lt;/a&gt;&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;Declare dependencies explicitly with package managers such as npm, Yarn, pip, or Composer.&lt;/li&gt;
    &lt;li&gt;Avoid copying dependencies into source code directly.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;h3 id=&quot;factor-3-config&quot;&gt;&lt;a href=&quot;#factor-3-config&quot; class=&quot;heading-link&quot;&gt;Factor 3: Config&lt;/a&gt;&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;Store configuration in the environment.&lt;/li&gt;
    &lt;li&gt;Separate secrets and environment-specific values from application code.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;h3 id=&quot;factor-4-backing-services&quot;&gt;&lt;a href=&quot;#factor-4-backing-services&quot; class=&quot;heading-link&quot;&gt;Factor 4: Backing Services&lt;/a&gt;&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;Treat databases, queues, and similar services as attached resources.&lt;/li&gt;
    &lt;li&gt;Be able to switch between local and managed services without rewriting the application.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;h3 id=&quot;factor-5-build-release-run&quot;&gt;&lt;a href=&quot;#factor-5-build-release-run&quot; class=&quot;heading-link&quot;&gt;Factor 5: Build, Release, Run&lt;/a&gt;&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;Separate build, release, and run stages strictly.&lt;/li&gt;
    &lt;li&gt;Use CI/CD pipelines with test and deploy stages.&lt;/li&gt;
    &lt;li&gt;Give each release a unique identifier and preserve rollback options.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;h3 id=&quot;factor-6-stateless-processes&quot;&gt;&lt;a href=&quot;#factor-6-stateless-processes&quot; class=&quot;heading-link&quot;&gt;Factor 6: Stateless Processes&lt;/a&gt;&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;Run the app as one or more stateless processes.&lt;/li&gt;
    &lt;li&gt;Persist state in backing services rather than application memory.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;h3 id=&quot;factor-7-port-binding&quot;&gt;&lt;a href=&quot;#factor-7-port-binding&quot; class=&quot;heading-link&quot;&gt;Factor 7: Port Binding&lt;/a&gt;&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;Export services via port binding.&lt;/li&gt;
    &lt;li&gt;Make it possible for one application to become another application&apos;s backing service.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;h3 id=&quot;factor-8-concurrency&quot;&gt;&lt;a href=&quot;#factor-8-concurrency&quot; class=&quot;heading-link&quot;&gt;Factor 8: Concurrency&lt;/a&gt;&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;Scale through the process model.&lt;/li&gt;
    &lt;li&gt;Separate HTTP work, workers, and other workloads into explicit process types.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;h3 id=&quot;factor-9-disposability&quot;&gt;&lt;a href=&quot;#factor-9-disposability&quot; class=&quot;heading-link&quot;&gt;Factor 9: Disposability&lt;/a&gt;&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;Optimize for fast startup and graceful shutdown.&lt;/li&gt;
    &lt;li&gt;Disposable processes make releases and scaling safer.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;h3 id=&quot;factor-10-dev-prod-parity&quot;&gt;&lt;a href=&quot;#factor-10-dev-prod-parity&quot; class=&quot;heading-link&quot;&gt;Factor 10: Dev-Prod Parity&lt;/a&gt;&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;Keep development, staging, and production environments as similar as possible.&lt;/li&gt;
    &lt;li&gt;Small gaps reduce surprises and improve continuous delivery.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;h3 id=&quot;factor-11-logs&quot;&gt;&lt;a href=&quot;#factor-11-logs&quot; class=&quot;heading-link&quot;&gt;Factor 11: Logs&lt;/a&gt;&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;Treat logs as event streams.&lt;/li&gt;
    &lt;li&gt;Emit logs to standard output and let external systems handle routing and storage.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;h3 id=&quot;factor-12-admin-processes&quot;&gt;&lt;a href=&quot;#factor-12-admin-processes&quot; class=&quot;heading-link&quot;&gt;Factor 12: Admin Processes&lt;/a&gt;&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;Run management tasks as one-off processes in the same environment as the main app.&lt;/li&gt;
    &lt;li&gt;Ship admin code with the application to avoid synchronization issues.&lt;/li&gt;
  &lt;/ul&gt;</content>
    <author><name>Tosin Amuda</name></author>
  </entry>
  <entry>
    <title>A letter to an outgoing Corper — episode one</title>
    <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/a-letter-to-an-outgoing-corper-episode-one.html" />
    <id>https://www.tosinamuda.com/blog/a-letter-to-an-outgoing-corper-episode-one.html</id>
    <updated>2016-04-11T00:00:00.000Z</updated>
    <published>2016-04-11T00:00:00.000Z</published>
    <summary>A heartfelt letter to graduating NYSC corps members about maintaining identity, building personal brand, and preparing for life after service to the nation.</summary>
    <content type="html">&lt;p&gt;A heartfelt letter to graduating NYSC corps members about maintaining identity, building personal brand, and preparing for life after service to the nation.&lt;/p&gt;&lt;p&gt;Dear Corper,&lt;/p&gt;
&lt;p&gt;Corper Shan! I will like to say how else can we thank you for dedicating one year of your life to serve your country. You have shown there is hope in our educational and Healy system only if we have passionate and energetic hands like you. What a great show of patriotism! What a great show of dedicated service! So what&amp;#39;s up after service? Like are you ready for the things to come. I am writing this letter to remind you of the changes ahead and how you can prepare for it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4&gt;If you don&amp;#39;t stand for something you will fall for anything!&lt;/h4&gt;
&lt;/blockquote&gt;
&lt;p&gt;First, watch out for losing your identity to the challenges ahead. Watch out for losing your voice to that of the crowd. The school and NYSC has a way of protecting your identity from the reality and harsh conditions of life. The identity I am talking about is who you have always wanted to be! Do you know it is time that the protective shell of school and government ended. Some years back, you were asked what you wanted to be in the future and you mentioned great stuff you wanted to become. The expectation on what you mentioned years back on your great future starts now. The future you talked about years ago is finally here. Nothing holds your future back again not 4 years of school, not one year of service. If you have forgotten those great dream, aspiration and hopes about your future, now is the time to remember. You wanted to be a great biochemist, a world class philosopher, a superb counsellor. However, I hear you are already changing your gears. You wanted to be a world class biochemist and I hear you applying already to be a police officer. Are you sure you are going for your passion ? You want to take any job that comes you ways. You are ready to settle for anybody, any job, any fiancé, any life. &lt;strong&gt;&lt;em&gt;Remember anything is nothing, that way any job means no job.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now I challenge you to recall what you told me sometimes ago. About how you wanted to be somebody, a great person whose voice will be heard and valued. Now it is time to start taking steps toward those future ambition. Let&amp;#39;s say you want a biochemist job, you should&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;list out the top twenty companies/organizations that offer biochemist opportunity.&lt;/li&gt;
&lt;li&gt;Write a powerful CV to show your are a biochemist in training who can learn and will be successful.&lt;/li&gt;
&lt;li&gt;Then APPLY! Do cold calling or unsolicited application it is allowed!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Go for your passion now ! You wanted to be an entrepreneur now it is the time to test the market. Having formed your identity it is time to give yourself a brand.&lt;/p&gt;
&lt;h1&gt;Branding is staying true to deliver what you promised as your identity.&lt;/h1&gt;
&lt;p&gt;Second, I hear you are ignorant of what your personal brand is. You know someone once defined branding as staying true to the what you promised as your identity. A personal brand is how you project yourself. It starts from you on paper, that is your CV. Then the physical you, your dressing, your spoken and written English, social etiquette. It also speaks about your integrity.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s start an intro conversation on the CV. I have seen so many dry CV. Old, common and dry! I hope your CV isn&amp;#39;t like that. And please don&amp;#39;t use the same CV for all job roles. Each job role is unique, so your relevant experience and hobbies should change.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I even hear some of your colleagues don&amp;#39;t have a CV yet and they are praying to get a job.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I overheard you wasted almost a page on biodata and nothing much on your relevant work experience. And some of you say you don&amp;#39;t have work experience, you want to be an accountant and you served as the financial secretary of your CDS group for almost 11 months. Did you need the Holy Ghost to tell you that it is a relevant experience in the absence of actual formal work place experience. We will talk more about CV subsequently.&lt;/p&gt;
&lt;p&gt;What of dressing? By now you should know the dressing of the workplace. You should know the language of the workplace. You can&amp;#39;t wear a Khaki to an interview. You can&amp;#39;t wear a white tennis for an interview. Now Let&amp;#39;s talk about integrity.&lt;/p&gt;
&lt;h1&gt;Don&amp;#39;t be part of the problems, rather be a solution to these problems!!&lt;/h1&gt;
&lt;p&gt;One of the two major problems of our country is corruption and unemployment. Don&amp;#39;t be part of the problems, rather be a solution to these problems!! My pastor used to say your competence will open doors for you but your character will keep you in the room. Let&amp;#39;s assume your competence has gotten you a job, problem one of unemployment is solved. Then you will have to face problem two of corruption. You will be tempted with challenges of corruption. I have heard story of young corpers who were avid advocate of anti-corruption who went on to become corrupt as they become entrenched in the system.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Make your stands known from your early days so people are aware you are a no go area!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You might even be a victim of corruption. In a case where you are to get a job and it goes to the family members of a politician. You will be met with a lot of rejections which will should talk about too.&lt;/p&gt;
&lt;h1&gt;Nobody owes you anything in this life.&lt;/h1&gt;
&lt;p&gt;Third, you should be aware nobody owes you a job. Nobody owes you anything in this life. Not even your uncle who is promising a job when you come back home. And because of this you might be met with rejections as you apply for various vacancy. It doesn&amp;#39;t mean you are not good enough or you should give up. It is just because they can&amp;#39;t take all the very fantastic people or maybe you haven&amp;#39;t convinced them you are fantastic enough. In fact, I read one stat recently. It refers to the fact that an average graduate should submit their CVs in 70 organization before they are guaranteed a place in 5 companies. So be prepared for rejection in 65 others. Someone will not even get back to you.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Rejections doesn&amp;#39;t mean you are not good enough! It means you can do better!!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Remember my friend I have said three things about identity, personal branding and rejection. Don&amp;#39;t forget your identity. You can stay true to your identity through personal branding and be prepared for rejection of your brand.&lt;/p&gt;
&lt;p&gt;Don&amp;#39;t forget our service to our dear nation shouldn&amp;#39;t stop in few days time. Service is a continuous process.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Do what you can where you are with what you have!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Happy Passing Out!&lt;/h1&gt;
&lt;p&gt;Sincerely yours,&lt;/p&gt;
&lt;p&gt;Mr. Future&lt;/p&gt;</content>
    <author><name>Tosin Amuda</name></author>
  </entry>
  <entry>
    <title>Building Kids Into Whizkids</title>
    <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/building-kids-into-whizkids.html" />
    <id>https://www.tosinamuda.com/blog/building-kids-into-whizkids.html</id>
    <updated>2015-10-26T00:00:00.000Z</updated>
    <published>2015-10-26T00:00:00.000Z</published>
    <summary>During my National Youth Service, I started an ICT club called &apos;Whizkids&apos; to empower the next generation of technology leaders. Teaching HTML to excited kids who built their first webpage, I now challenge everyone to organize #hourofcode events and become nation builders.</summary>
    <content type="html">&lt;p&gt;During my National Youth Service, I started an ICT club called &apos;Whizkids&apos; to empower the next generation of technology leaders. Teaching HTML to excited kids who built their first webpage, I now challenge everyone to organize #hourofcode events and become nation builders.&lt;/p&gt;&lt;p&gt;If you are a techie like me you must have heard about one of these: computer science for high school, hour of code. If you are not a techie you must have heard catch them young or the leaders of tomorrow. I must have complained a lot about &lt;a href=&quot;http://nysc.gov.ng&quot;&gt;NYSC&lt;/a&gt;, I had to stop, come to think of it, the NYSC scheme puts me in a position to impact on my host community however big or small. It puts me in a position to build the next set of leaders. With obvious bias, I want the kids in my host community to be next technology leaders of their generations and digital armed forces of Nigeria. This prompted me to start an ICT club in my &lt;a href=&quot;https://m.facebook.com/pages/Jetters-Montessori-schools-Jalingo/521138361283409&quot;&gt;school&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I can not but mention that the &lt;a href=&quot;http://www.hourofcode.com&quot;&gt;hour of code&lt;/a&gt; promotional videos especially the one from Mark Zuckerberg keeps motivating me to do more with raising the next generation of ICT leaders.&lt;/p&gt;
&lt;p&gt;Let me digress a little bit I was not lucky to start programming at 13 like Bill gate but I once did Logo programming maybe at 15 can&amp;#39;t remember exactly and I felt good about it. However, today is not for inviting you to a pity party of how I started coding late. I am inviting you rather to a challenge. I challenge you to become a nation builder however small or big. Build someone today with your intellect and resources and stop complaining of infrastructural/system collapse in the nation.&lt;/p&gt;
&lt;p&gt;Back to the business, the vision for the club was simple: to build next generation of technology leaders. We call ourselves &amp;quot;Whizkids&amp;quot;. And our mission was to empower ourselves with contemporary tools to deliver the future. How do we get this done? We will focus on web, mobile and robotics technology.&lt;/p&gt;
&lt;p&gt;There are a lot of options here, it was hard getting to choose which technology to actually start with. Scratch, snap, JavaScript, Python, html all staring at me. I decided to start off with html. Whatever you believe in someone agrees with you on the Internet. Someone recently said internet is going to be a place where people echo your ideas. Technologies like Facebook like, Twitter favorite and retweet are obvious examples. I stumbled on html for babies it was helpful in coming up with a curriculum.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/img_2081-1024x802.jpg&quot; alt=&quot;Students learning HTML&quot;&gt;
&lt;em&gt;Students excited about learning web development&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Are the kids excited? Yeah they are super excited they are going to be building a website. How will you feel if at 13, if someone told you, you will be taught how to build a rocket or robot in 2 months. I will be super excited. My closest-to-techy-experience was turning my dad transistor radio to my physics experiment apparatus. It was good experience for me but it was attracted punishment from my dad.&lt;/p&gt;
&lt;p&gt;The kids are doing well with learning that HTML code is like two slices of bread with butter. The first slice of bread is like the opening tag, the butter is the content in the middle and the closing tag is like the second slice of bread. My kids have successfully built a webpage containing their school anthem and they are excited.&lt;/p&gt;
&lt;p&gt;Everyone who reads this I challenge you to hold an &lt;a href=&quot;https://twitter.com/hashtag/hourofcode?lang=en&quot;&gt;#hourofcode&lt;/a&gt; event for kids in your schools, churches or mosques. You can also tweet at me at &lt;a href=&quot;https://twitter.com/tosinamuda&quot;&gt;@tosinamuda&lt;/a&gt;&lt;/p&gt;</content>
    <author><name>Tosin Amuda</name></author>
  </entry>
  <entry>
    <title>Resurrected from the dead</title>
    <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/resurrected-from-the-dead.html" />
    <id>https://www.tosinamuda.com/blog/resurrected-from-the-dead.html</id>
    <updated>2015-10-20T00:00:00.000Z</updated>
    <published>2015-10-20T00:00:00.000Z</published>
    <summary>During my National Youth Service as an ICT instructor, I learned how PowerPoint can kill classroom engagement. Through research and student feedback, I discovered solutions to avoid &apos;Death by PowerPoint&apos; and resurrect interactive learning through better presentation techniques.</summary>
    <content type="html">&lt;p&gt;During my National Youth Service as an ICT instructor, I learned how PowerPoint can kill classroom engagement. Through research and student feedback, I discovered solutions to avoid &apos;Death by PowerPoint&apos; and resurrect interactive learning through better presentation techniques.&lt;/p&gt;&lt;p&gt;I am a geek, I am excited about technology and I love to use it. Teaching ICT even drives me to use technology more. I always tell myself I can&amp;#39;t teach technology without using technology. Apart from being passionate about technology, I am more interested in using technology to impact on the lifes of people I meet everyday.&lt;/p&gt;
&lt;p&gt;As a matter of fact, after your undergraduate program in Nigeria, there is the compulsory national youth service. Under this scheme, I was posted as an ICT instructor to &lt;a href=&quot;https://www.facebook.com/pages/jetters-montessori-college/312799712184617?rf=334391576705465&quot;&gt;Jetters Montessori College, Jalingo&lt;/a&gt;, one of the &lt;a href=&quot;http://serveafrica.info/top-60-nigeria-secondary-schools-2014&quot;&gt;best schools&lt;/a&gt; in Nigeria and one of the leading schools in ICT in the country. Wow, I was impressed with the level of technology infrastructure available in the school. However, the infrastructure were going into ruins because there were no capable hands to use the school e-learning facilities to teach the student.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/img_2058-1-1024x768.jpg&quot; alt=&quot;School Technology Infrastructure&quot;&gt;
&lt;em&gt;The technology infrastructure at Jetters Montessori College&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Consequently, the current situation of the school, and my passion for change and technology sets in the temptation to avoid the traditional classroom teaching for an edtech classroom.&lt;/p&gt;
&lt;p&gt;I started out by impressing my bosses when I created my scheme of work using Microsoft Word. It was not a big deal to me but my director made it an example for others. As a faithful servant, I continued by creating my lesson plan and note with Microsoft word. I couldn&amp;#39;t wait to start my first class with PowerPoint slides.&lt;/p&gt;
&lt;p&gt;As a naive teacher, I had quickly forgotten that while in the University I would switch to playing either 2048 or candy crush in a boring PowerPoint class. I had powerful pictures, my PowerPoint was not wordy but something was wrong in the class. I noticed a number of students were distracted, even tried sleeping.&lt;/p&gt;
&lt;p&gt;I guess I failed at using technology in my first class. I was tempted to quickly give up as I was advised by a fellow ICT teacher. I told myself No, technology is meant to help and it can work.&lt;/p&gt;
&lt;p&gt;Thank God for Google, I did what I usually call counter search on &amp;quot;10 mistakes you could be doing with PowerPoint in class&amp;quot;. Then, I stumbled on the phrase &amp;quot;Death by PowerPoint&amp;quot;. Powerpoint is meant to power a class but it can kill a class. After the I did my online research, I went offline and did the most important research with my clients, my students of course.&lt;/p&gt;
&lt;p&gt;I noticed the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;PowerPoint was killing the interactiveness of the class.&lt;/li&gt;
&lt;li&gt;The students were straining their eyes because of poor lightning in the classroom environment and the choice of background colour.&lt;/li&gt;
&lt;li&gt;Some students have eye defects.&lt;/li&gt;
&lt;li&gt;When you think your powerpoint is not wordy but is is actually wordy.&lt;/li&gt;
&lt;li&gt;Too much information on one slide: more than one equation or table.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I worked with my student in proferring these solutions to avoid death by PowerPoint and also resurrect.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enhance active learning by using a picture to start off a discussion in class.&lt;/li&gt;
&lt;li&gt;Follow the 6 by 6 principle strictly: not more than 6 words in a bulletpoint and not more than 6 bulletpoint in a slide.&lt;/li&gt;
&lt;li&gt;Use one word slide to start off a discussion&lt;/li&gt;
&lt;li&gt;Use animation to delay how much information the students get at once.&lt;/li&gt;
&lt;li&gt;Introduce varieties: try videos to start off a discussion or group discussion.&lt;/li&gt;
&lt;li&gt;I am looking at the Takashi method as well. Using only one word per slide.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now my class has fully resurrected from death by PowerPoint. I also now appreciate why people spend 4 years in school studying education by the day. I can&amp;#39;t imagine how much of educational methods I will learn while trying to teach my students. I hope to conduct a research where I will compare my student performance in my course - where I use technology - to other courses - where traditional method is being used. I can&amp;#39;t shy away from the fact that I love teaching. What about you?&lt;/p&gt;
&lt;p&gt;And please feel free to share your own teaching method. You can also tweet at me &lt;a href=&quot;http://www.twitter.com/tosinamuda&quot;&gt;@tosinamuda&lt;/a&gt;.&lt;/p&gt;</content>
    <author><name>Tosin Amuda</name></author>
  </entry>
  <entry>
    <title>The Lie About The Future</title>
    <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/the-lie-about-the-future.html" />
    <id>https://www.tosinamuda.com/blog/the-lie-about-the-future.html</id>
    <updated>2013-12-05T00:00:00.000Z</updated>
    <published>2013-12-05T00:00:00.000Z</published>
    <summary>The article challenges the notion of a promising future that previous generations have promised but not delivered upon. It highlights the disillusionment of today&apos;s youth who were told they&apos;d succeed if they worked hard but face challenges like unemployment, nepotism, and economic struggles.</summary>
    <content type="html">&lt;p&gt;The article challenges the notion of a promising future that previous generations have promised but not delivered upon. It highlights the disillusionment of today&apos;s youth who were told they&apos;d succeed if they worked hard but face challenges like unemployment, nepotism, and economic struggles.&lt;/p&gt;&lt;p&gt;Every generation - while young - admires the beauty of the future, its promises, potentials and possibilities. It is like a Nollywood story of a poor village girl who has been betrothed to a city lover who she has never met, but her parents assure her of the cuteness of the city boy and his heavy pocket, what else can the poor girl ask for. Just like the village girl, the current generation falls in love with this future they are supposedly yet to see but believes the future will come one day. They blush at being called the future leader, the greater tomorrow just like the teen tell themselves you are the cockroach in my wardrobe, of course we know any cockroach is useless, it will eventually spoil some precious cloth.&lt;/p&gt;
&lt;p&gt;The old folks, they tell us the sweet phrases: where&amp;#39;re the future leaders, the leaders of tomorrow. Have you ever wondered when this tomorrow will come? In high school, our teachers told us about this beautiful future. Distracted by the awesomeness of this lie, as opposed to the inquisitive nature of kids, we never ask how and when they got into theirs. This isn&amp;#39;t how it was supposed to go! They told us we would be okay if only we worked hard. They told us we&amp;#39;d be successful if we studied for the exams, had the right hair-cut and had the right parents! They LIED to us!&lt;/p&gt;
&lt;p&gt;Pause!!! This generation at 18 wakes up in the FUTURE and discovers their cities are run with thousands of youthful agberos, energetic beggars, cute prostitutes, scholarly aristos, youth discouraged by unemployment, nepotism, struggle for admission, O level exam failures, expensive data (outside blackberry though), incessant power supply. Some of them are wasting away smoking, partying, experimenting hard chemicals believing it will numb their anxiety and give them a break from the supposed beautiful FUTURE.&lt;/p&gt;
&lt;p&gt;This was supposed to be the future. The future our principal told us about, the one the sunday school teacher told us every Sunday, in fact the political czars have a way of sweet-talking us into this future. Funny enough, the fools among them still blush at the slightest use of our future leader.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://shirtblog.de/wp-content/uploads/2010/08/zoom.gif&quot; alt=&quot;This was supposed to be the future&quot;&gt;
&lt;em&gt;This was supposed to be the future&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This generation will be fine if they accept the future is not the city boy who is going to come visiting one day, it is the moment we live in and that the beautiful story they were told won&amp;#39;t be soon, and it won&amp;#39;t be in the way they were made to believe. This generation can&amp;#39;t expect to win by playing along, but what else can they do? After all, the older generations &amp;#39;re the ones with the power. The older folks &amp;#39;ve got the money and the guns and the government and maybe God, the older folk sign our paycheques, mark our exams (the old professors) and grade our various crawling efforts to please. What have they got to challenge that?&lt;/p&gt;
&lt;p&gt;I&amp;#39;ll tell you what we this generation has got. This is the part I start using we.&lt;/p&gt;
&lt;p&gt;We have Energy, Information(Truth), Beauty and Love. We have a flourishing counterculture that&amp;#39;s more alive than anything the mainstream has produced in the last twenty years. We have social media, mindset deviancy. We have the talent and the information-delivery media to reprogramme the minds of Young Corporate Leaders and drive them, frothing, into the sea. We have the vote. Most importantly, we have much swag.&lt;/p&gt;
&lt;p&gt;&amp;quot;Unlike them, we are truly hypertextual. We have the information and communications technology to entirely re-imagine the concept of socio-political power, and we are bright enough and brave enough to use it. We are multi-ethnic, multi-gendered, multi-talented and massively up for a fight, we are no longer frightened of your disapproval, and we have bombs.&amp;quot;&lt;/p&gt;
&lt;p&gt;If you accept the future leader title, you might not lead until you end up in the grave, because someone will always be alive to lie to you about your position in the future and will distract you from your position today.&lt;/p&gt;
&lt;p&gt;Inspired by &lt;a href=&quot;http://pennyred.blogspot.com/2008/02/they-lied-to-us.html&quot;&gt;Penny Red&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Follow &lt;a href=&quot;http://twitter.com/tosinamuda&quot;&gt;@tosinamuda&lt;/a&gt;.&lt;/p&gt;</content>
    <author><name>Tosin Amuda</name></author>
  </entry>
  <entry>
    <title>Today&apos;s Sci-fi and Tomorrow&apos;s Reality: 4 Future Technologies You Will Not Believe</title>
    <link rel="alternate" type="text/html" href="https://www.tosinamuda.com/blog/todays-sci-fi-and-tomorrows-reality-4-future-technologies.html" />
    <id>https://www.tosinamuda.com/blog/todays-sci-fi-and-tomorrows-reality-4-future-technologies.html</id>
    <updated>2012-04-07T00:00:00.000Z</updated>
    <published>2012-04-07T00:00:00.000Z</published>
    <summary>Explore four groundbreaking technologies that are transforming from science fiction into reality: Internet of Things, Project Glass, driverless cars, and 3D printing.</summary>
    <content type="html">&lt;p&gt;Explore four groundbreaking technologies that are transforming from science fiction into reality: Internet of Things, Project Glass, driverless cars, and 3D printing.&lt;/p&gt;&lt;p&gt;The movie &amp;quot;The Social Network&amp;quot; before 21st century might have been a science-fiction (sci-fi); however, it turned out to be a real story. This is because prior to the 21st century, there was almost nothing like social networking, no video conferencing, maybe it was in a 1970 sci-fi but in the few space of time, man continues to discover technology that astonishes him. Technology that changes the way we communicate and process information.&lt;/p&gt;
&lt;p&gt;I bet there are still technologies that have not entered into the heart of men coming through this century. Nothing seems to be impossible again. The Christian and the other religions of the books might call it the end-time, a philosopher might still be questioning why but as a technology enthusiast I believe this is the beginning of the end we are all anticipating for. If you are still with me permit me to take you into the future for a few minute, a future very near, permit me to introduce to you four awesome technologies you might not believe.&lt;/p&gt;
&lt;h2 id=&quot;1-internet-of-things-iot&quot;&gt;&lt;a href=&quot;#1-internet-of-things-iot&quot; class=&quot;heading-link&quot;&gt;1. Internet of Things (IoT)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Have you ever imagined:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Googling your room to find your lost Blackberry&lt;/li&gt;
&lt;li&gt;Your flower tweeting you to be watered&lt;/li&gt;
&lt;li&gt;Your pot facebooking you that your food is done&lt;/li&gt;
&lt;li&gt;Your laundry machine updating its status about being done with washing your clothes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It might have been sci-fi just a decade ago, but with the internet forcing its way into every aspect of our lives, cyberspace is leaking out into the real world. This is the future with the possibility of interconnecting people and objects – lightbulbs, fridges, cars, buildings – to create an &lt;strong&gt;internet of things&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&amp;quot;Some of the things that are possible are truly unbelievable,&amp;quot; says Constantine Valhouli from the Hammersmith Group, a strategy consulting firm. This technology is called the Internet of things (IoT), many are already saying this is a trend bound to hit us all in the near future. There is a whole lot about (IOT) &lt;a href=&quot;http://www.bbc.co.uk/news/magazine-15018894&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;2-project-glass-the-future-pc&quot;&gt;&lt;a href=&quot;#2-project-glass-the-future-pc&quot; class=&quot;heading-link&quot;&gt;2. Project Glass - The Future PC&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now let&amp;#39;s take a deeper journey into the future to find out what &lt;a href=&quot;http://money.cnn.com/2012/04/04/technology/google-project-glass/?source=cnn_bin&quot;&gt;CNN&lt;/a&gt; already calls the future PC. We&amp;#39;ve moved from a desktop internet to mobile phones and mobile internet – who knows the next step might be the &lt;a href=&quot;https://plus.google.com/111626127367496192147/posts&quot;&gt;recently unveiled long-rumored concept&lt;/a&gt; called &lt;strong&gt;&amp;quot;Project Glass,&amp;quot;&lt;/strong&gt; which takes all the functionality of a smartphone and places it into a wearable device that resembles eyeglasses.&lt;/p&gt;
&lt;p&gt;The see-through lens could display everything from text messages to maps to reminders. They may be capable of showing video chats, providing turn-by-turn directions, taking photos and recording notes all through simple voice commands, according to a concept video produced by the company and &lt;a href=&quot;http://www.youtube.com/watch?v=9c6W4CCU9M4&quot;&gt;released on YouTube&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;3-driverless-cars&quot;&gt;&lt;a href=&quot;#3-driverless-cars&quot; class=&quot;heading-link&quot;&gt;3. Driverless Cars&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There&amp;#39;s still something from Google&amp;#39;s Google X lab, the same future-thinking research facility that is working on the project glass and &lt;a href=&quot;http://www.time.com/time/health/article/0,8599,2099830,00.html&quot;&gt;space elevator&lt;/a&gt;. However this time around is about a &lt;a href=&quot;http://money.cnn.com/2010/11/04/technology/google_big_bets/index.htm?iid=EL&quot;&gt;&lt;strong&gt;driverless car&lt;/strong&gt;&lt;/a&gt;. The car will be integrated with Google Maps.&lt;/p&gt;
&lt;p&gt;&amp;quot;Google believes it is a technology that is here and now and will start appearing in motorcars in the near future,&amp;quot; said Professor Alan Woodward from the department of computing at the University of Surrey. &amp;quot;We already have systems that park your cars for you and automatically brake – the next obvious step is to have cars take over the routine driving.&amp;quot;&lt;/p&gt;
&lt;h2 id=&quot;4-3d-printing-technology&quot;&gt;&lt;a href=&quot;#4-3d-printing-technology&quot; class=&quot;heading-link&quot;&gt;4. 3D Printing Technology&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve talked about glasses and cars; yes it&amp;#39;s all about objects, things. However, another technology worthy of mention is the &lt;strong&gt;3D Printing&lt;/strong&gt; technology.&lt;/p&gt;
&lt;p&gt;I bet you&amp;#39;ve never imagined:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Downloading and printing your favourite delicacy online&lt;/li&gt;
&lt;li&gt;Printing out a tennis ball or even a football&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Consumer-level 3D printing technology has moved ahead in leaps and bounds in recent years with the release of devices such as the &lt;a href=&quot;http://www.gizmag.com/makerbot-thing-o-matic--the-diy-3d-printer/17516/&quot;&gt;Thing-o-Matic&lt;/a&gt;, the &lt;a href=&quot;http://www.gizmag.com/makerbot-replicator-3d-printer/21078/&quot;&gt;Replicator&lt;/a&gt; and &lt;a href=&quot;http://www.gizmag.com/3d-systems-cubify-printer/21091/&quot;&gt;Cubify&lt;/a&gt; 3D printers.&lt;/p&gt;
&lt;p&gt;In the nearest future users of this technology will be able to download designs and print everything from car parts to … well, a new and improved 3D printer. The folks at &lt;em&gt;The Pirate Bay&lt;/em&gt; are already taking a bold step by adding a new &amp;quot;Physibles&amp;quot; category. The new category will contain digital files for objects that can be physically created using a 3D printer.&lt;/p&gt;
&lt;p&gt;In announcing the move on its blog, &lt;em&gt;The Pirate Bay&lt;/em&gt; describes physibles as &amp;quot;data objects that are able (and feasible) to become physical.&amp;quot; Watch out for a future with huge benefits in terms of savings on shipping and (child) labour, with users even able to literally print food to feed the hungry.&lt;/p&gt;
&lt;h2 id=&quot;the-future-is-now&quot;&gt;&lt;a href=&quot;#the-future-is-now&quot; class=&quot;heading-link&quot;&gt;The Future is Now&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Technology as a promising world-view in a not-too-distant future will make life richer and comfortable. Imagine getting a tweet from my farm in the village through my &lt;strong&gt;project glass&lt;/strong&gt; in my &lt;strong&gt;driverless car&lt;/strong&gt;. It&amp;#39;s a beautiful world I&amp;#39;m sure you will be waiting for.&lt;/p&gt;
&lt;p&gt;The convergence of these technologies represents more than just individual innovations – they represent a fundamental shift in how we interact with our environment and each other. As we stand on the brink of this technological revolution, one thing is certain: the future is arriving faster than we ever imagined.&lt;/p&gt;</content>
    <author><name>Tosin Amuda</name></author>
  </entry>
</feed>
