<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Oh my AI]]></title><description><![CDATA[Developer and architect exploring the space where humans, systems, and AI meet. I write about code, cognition, and the architecture of intelligent workflows.]]></description><link>https://www.thatskiki.ai</link><image><url>https://substackcdn.com/image/fetch/$s_!iSlL!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98b6ca8f-4f8a-4e07-8f53-de7264be4f51_401x401.png</url><title>Oh my AI</title><link>https://www.thatskiki.ai</link></image><generator>Substack</generator><lastBuildDate>Wed, 06 May 2026 11:04:23 GMT</lastBuildDate><atom:link href="https://www.thatskiki.ai/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Kiki C]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[thatskiki@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[thatskiki@substack.com]]></itunes:email><itunes:name><![CDATA[Kiki C]]></itunes:name></itunes:owner><itunes:author><![CDATA[Kiki C]]></itunes:author><googleplay:owner><![CDATA[thatskiki@substack.com]]></googleplay:owner><googleplay:email><![CDATA[thatskiki@substack.com]]></googleplay:email><googleplay:author><![CDATA[Kiki C]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[The API-to-MCP Debate Is Really About Agent Experience]]></title><description><![CDATA[In the AI engineering community, there&#8217;s this interesting hot take going around: auto-generated MCP servers that simply wrap REST APIs create poor agent performance.]]></description><link>https://www.thatskiki.ai/p/the-api-to-mcp-debate-is-really-about-agent-experience</link><guid isPermaLink="false">https://www.thatskiki.ai/p/the-api-to-mcp-debate-is-really-about-agent-experience</guid><dc:creator><![CDATA[Kiki C]]></dc:creator><pubDate>Mon, 08 Dec 2025 00:29:28 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d0dcf19e-09d0-4e32-ac4e-fce0200b1015_299x234.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the AI engineering community, there&#8217;s this interesting hot take going around: auto-generated MCP servers that simply wrap REST APIs create poor agent performance. The main concern is that these APIs were originally designed for humans or SDKs, not for agents. When you expose them &#8220;as-is,&#8221; you get tool overload, wasted reasoning cycles, and confused models.</p><p>There&#8217;s definitely truth to this. I&#8217;ve worked with APIs that completely overwhelm agents, especially with older LLMs. Even with current models, a large surface area of tools can push them to wander rather than act decisively. That said, I&#8217;m not fully convinced that API-to-MCP is inherently flawed. My position is more nuanced. I&#8217;ve quipped &#8220;maybe your API is just bad,&#8221; but my fuller thought is that it has less to do with whether an API is good or bad and more to do with what kind of experience we want an agent to have.</p><p>The reality is that nearly everything about AI engineering is fairly new, including our approaches to designing agent experience. I don&#8217;t know if there&#8217;s an official term for &#8220;Agent Experience&#8221; yet, and I&#8217;m not trying to coin one here. I imagine someone somewhere is already thinking about Agent Experience (AX?) as a new design discipline that sits beside the traditional UX we&#8217;ve built for humans. And refocusing our attention on AX helps us move beyond blanket prescriptions toward a better understanding of when API-to-MCP works and when it doesn&#8217;t.</p><h2>Why Some API Surfaces Fail When Mapped Directly into MCP</h2><p>The clearest failure mode happens when someone points an MCP generator at a very large, SDK-oriented API. These APIs often contain hundreds of operations, deeply nested resources, pagination helpers, batch endpoints, and internal administrative actions. They were designed for typed programming languages where developers rely on autocompletion, documentation, and compiler checks. They were not designed to be reasoned over by a language model.</p><p>If you expose this entire surface directly to an agent, the model has too many choices. Tool selection becomes noisy, the agent explores irrelevant operations, and the number of back-and-forth calls grows. In these situations, where no one intentionally designed for the agent&#8217;s experience, the critique is valid. It doesn&#8217;t surprise me that a design inherited from assumptions that only make sense for developers may not work well for agents.</p><h2>But Not All APIs Look Like SDKs</h2><p>Many real-world APIs are much smaller and built to mirror the task flows that humans perform through a UI. These UI-shaped APIs tend to be pragmatic and intuitive. They have just enough operations to support the interface without producing an overwhelming number of choices. When an agent&#8217;s role resembles a task a human might perform in the product, these UI-shaped APIs often align well with what the agent needs.</p><p>This is where API-to-MCP becomes an elegant, low-friction pattern. The API already expresses the steps in a workflow: one operation to create something, another to update it, another to attach related items, and another to finalize the task. There&#8217;s no obscure domain model to infer, no arbitrary distinctions to decode. The agent can reason about the operations the same way a human would if they were using the UI.</p><h2>A Concrete Example: My Reporter Application</h2><p>I saw this firsthand while building my <a href="https://kikia.io/2025/10/05/reimagining-my-application-as-an-agentic-workflow/">Reporter application</a>. The API behind Reporter was originally structured for a simple UI: create a report, add findings, attach actions, leave comments, and update status. It wasn&#8217;t large, and it wasn&#8217;t designed as a formal SDK surface. It simply mirrored how a human completed reporting tasks.</p><p>When I exposed that API through MCP, the agent handled the full workflow with ease. It created reports, added findings, attached actions to each one, and inserted comments in relevant places. It understood how to reference IDs returned from previous calls and could chain those operations effectively. I didn&#8217;t have to invent agent-specific abstractions or redesign anything. The shape of the API already matched the shape of the work.</p><h2>When API-to-MCP Is Appropriate</h2><p>API-to-MCP is a valid and often effective pattern when the API surface is small and corresponds to meaningful tasks, when the agent&#8217;s responsibilities resemble human workflows, when resource boundaries are clear and easy to reason about, and when operations compose naturally. It also works well when the agent doesn&#8217;t need hidden backend capabilities and when we can support the agent with context that explains relationships or expected sequences.</p><p>This is when you can introduce agentic value immediately with what you already have. If the API is already a clean representation of domain capabilities, use it. Investing in API design pays dividends twice. A well-structured API serves your human users through the UI, and it serves your agents through MCP. The same clarity that makes an API pleasant for frontend developers to work with makes it navigable for an agent. If your API is a mess, both audiences suffer. If it&#8217;s clean, both benefit.</p><h2>The Real Question: What Experience Should the Agent Have?</h2><p>The success or failure of API-to-MCP is not determined by whether the API was created for humans or for SDKs. The key question is whether the API surface supports the experience we want the agent to have.</p><p>Humans have UX. Agents need AX. UX is supported and expressed through the UI&#8212;the visual layer that guides users through interactions, constrains their choices, and provides feedback. AX needs its own supporting structures, but we don&#8217;t yet have a fully developed equivalent of the UI for agents. What we have is MCP, which exposes capabilities and schemas, but doesn&#8217;t actively guide the agent through workflows the way a UI guides a human.</p><p>In the absence of that guiding layer, a smaller, more directed API surface compensates by reducing cognitive load. It limits the agent&#8217;s choices and makes the workflow clearer through the shape of the tools themselves. This is exactly what I observed with my Reporter application. The API was clear enough that the agent could navigate the workflow without needing additional guidance structures. The tool surface itself provided enough direction.</p><p>Designing AX means asking thoughtful questions. Does this agent work more like a human completing a task? Or is it acting as a system-level orchestrator? Does it need broad domain coverage or a narrow, purpose-built surface? Does it need to understand relationships across resources, or will those be supplied as context? These decisions shape whether an existing API is enough, or whether we need a curated agent-native layer.</p><p>A real Agent Experience guiding layer might look more like:</p><ul><li><p>Workflow orchestration hints</p></li><li><p>Contextual tool filtering</p></li><li><p>Sequential guidance</p></li><li><p>State awareness that limits what&#8217;s shown when</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dq77!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ae82870-aac9-49e0-bfa8-dc9dd8ef08ce_299x234.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dq77!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ae82870-aac9-49e0-bfa8-dc9dd8ef08ce_299x234.png 424w, https://substackcdn.com/image/fetch/$s_!dq77!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ae82870-aac9-49e0-bfa8-dc9dd8ef08ce_299x234.png 848w, https://substackcdn.com/image/fetch/$s_!dq77!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ae82870-aac9-49e0-bfa8-dc9dd8ef08ce_299x234.png 1272w, https://substackcdn.com/image/fetch/$s_!dq77!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ae82870-aac9-49e0-bfa8-dc9dd8ef08ce_299x234.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dq77!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ae82870-aac9-49e0-bfa8-dc9dd8ef08ce_299x234.png" width="1024" height="801" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5ae82870-aac9-49e0-bfa8-dc9dd8ef08ce_299x234.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:801,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!dq77!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ae82870-aac9-49e0-bfa8-dc9dd8ef08ce_299x234.png 424w, https://substackcdn.com/image/fetch/$s_!dq77!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ae82870-aac9-49e0-bfa8-dc9dd8ef08ce_299x234.png 848w, https://substackcdn.com/image/fetch/$s_!dq77!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ae82870-aac9-49e0-bfa8-dc9dd8ef08ce_299x234.png 1272w, https://substackcdn.com/image/fetch/$s_!dq77!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ae82870-aac9-49e0-bfa8-dc9dd8ef08ce_299x234.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The UI is to humans what the emerging agent interface will become for agents. AX depends on this interface, but it is still in formation.</figcaption></figure></div><p>Context engineering is a major part of AX as well. It includes how we prime the agent, guide its sequences, and help it interpret responses. Good context complements the tool surface, working together to shape the agent&#8217;s understanding and behavior. This deserves its own deeper discussion, but for now, it&#8217;s important to recognize context as a key component of agent experience design.</p><h2>Looking Forward</h2><p>API-to-MCP should not be dismissed by default. Yes, some APIs are too broad or too developer-oriented to expose directly. But others map precisely to the tasks we want agents to handle. A poor experience in MCP is not evidence that the pattern is inherently flawed. It might indicate API design issues that humans feel too, or it might mean that the agent deserves a different interface altogether.</p><p>As AX becomes a more mature discipline, the question will shift from &#8220;Should I wrap my API?&#8221; to something more architectural: &#8220;Does my API already represent the work I want this agent to do?&#8221; When the answer is yes, API-to-MCP can be a clean and effective solution for that particular agent&#8217;s needs. When the answer is no, we can design agent-native layers that help the agent understand the domain more clearly.</p><p>But the tool surface is just one piece of agent experience. Context engineering, workflow guidance, state management, and other dimensions of AX are still emerging areas of thought. We&#8217;re early in understanding how to design well for agents, and there&#8217;s room for experimentation and new ideas.</p><p>Either way, our goal is to create environments where agents can act with increased reliably, interpretably, and purpose. Thinking deliberately about agent experience gives us a framework to make those decisions with confidence.</p>]]></content:encoded></item><item><title><![CDATA[Code Update: Similarity Search with Co-Located Vectors and Access Control]]></title><description><![CDATA[A companion to &#8220;The Separation Tax: When You Split Data Between Your Relational And Vector DB&#8220;]]></description><link>https://www.thatskiki.ai/p/code-update-similarity-search-with-co-located-vectors-and-access-control</link><guid isPermaLink="false">https://www.thatskiki.ai/p/code-update-similarity-search-with-co-located-vectors-and-access-control</guid><dc:creator><![CDATA[Kiki C]]></dc:creator><pubDate>Sat, 29 Nov 2025 21:46:39 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!iSlL!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98b6ca8f-4f8a-4e07-8f53-de7264be4f51_401x401.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>A companion to &#8220;<a href="https://kikia.io/2025/10/24/the-separation-tax-when-vectors-live-outside-your-database/">The Separation Tax: When You Split Data Between Your Relational And Vector DB</a>&#8220;</em></p><p>In a recent post, I argued that separating vectors from relational data creates a separation tax. This shows up as costs you pay in correctness, complexity, performance, and observability. My main thesis is that when embeddings and metadata live together in one database, retrieval becomes a bounded act of reasoning under policy constraints, not just simple recall.</p><p>Today, I&#8217;m releasing an update to the <a href="https://github.com/kikiya/agentic-tuning-reporter">CRDB Tuning Report Generator</a> that demonstrates this pattern in action with <strong>semantic similarity search and access control guardrails</strong> all running in a single CockroachDB query.</p><h2>What&#8217;s New</h2><p>This update adds two major features that work together to prove the co-location thesis:</p><h3>1. Semantic Similarity Search</h3><p>Reports and findings now get OpenAI embeddings automatically when created. The system can then find semantically similar content without relying on keyword matching.</p><p><strong>Frontend:</strong></p><ul><li><p>&#8220;Find Similar&#8221; button on every report detail page</p></li><li><p>Dialog showing top 5 similar reports with similarity scores</p></li><li><p>Real-time semantic search across existing reports</p></li></ul><p><strong>Backend:</strong></p><ul><li><p>Auto-embedding via OpenAI <code>text-embedding-3-small</code> (1536 dimensions)</p></li><li><p>Vector similarity using CockroachDB&#8217;s native <code>VECTOR(1536)</code> type</p></li><li><p>Single-query retrieval with the <code>&lt;-&gt;</code> distance operator</p></li></ul><p><strong>Database:</strong></p><pre><code>-- Co-located embeddings with metadata
CREATE TABLE reports (
  id UUID PRIMARY KEY,
  title STRING,
  report_text STRING,
  embedding VECTOR(1536),  -- Semantic representation
  customer_id UUID,        -- Access control
  region STRING,           -- Compliance boundary
  pii_flag BOOL,          -- Content guardrail
  status STRING,          -- Workflow state
  ...
);
</code></pre><h3>2. Access Control Demo</h3><p>Three demo users showcase how guardrails work alongside similarity search:</p><ul><li><p><strong>Alice Johnson</strong> (<code>analyst_alice</code>) &#8211; Can only see Acme Corp reports</p></li><li><p><strong>Bob Smith</strong> (<code>analyst_bob</code>) &#8211; Can only see Globex Industries reports</p></li><li><p><strong>Charlie Davis</strong> (<code>admin_charlie</code>) &#8211; Admin with full access to all customers</p></li></ul><p>Switch between users in the UI and watch the similarity results change based on their access level. Same semantic query, different results&#8212;because access control happens <em>before</em> retrieval, not after.</p><h2>Why This Matters: The Single Query</h2><p>With separated systems, you&#8217;d do this:</p><pre><code># Retrieve all, then filter 
all_similar = vector_db.search(embedding, limit=100)
# Now fetch metadata for each to check access...
allowed = []
for report in all_similar:
    metadata = relational_db.get(report.id)
    if user_has_access(user_id, metadata.customer_id):
        allowed.append(report)
    if len(allowed) &gt;= 5:
        break
return allowed
</code></pre><p>With co-located vectors, it&#8217;s one query:</p><pre><code>-- Filter and retrieve in one serializable snapshot
WITH authorized AS (
  SELECT customer_id 
  FROM user_access 
  WHERE user_id = $user_id
)
SELECT 
  r.id, 
  r.title, 
  r.customer_id,
  r.embedding &lt;-&gt; $query_embedding AS distance
FROM reports r
WHERE r.customer_id IN (SELECT * FROM authorized)
  AND r.embedding IS NOT NULL
  AND r.status IN ('published', 'in_review')
  AND r.pii_flag = FALSE
ORDER BY distance
LIMIT 5;
</code></pre><p><strong>What you gain:</strong></p><ul><li><p><strong>Correctness</strong> &#8211; Access control enforced before retrieval; no &#8220;oops&#8221; moments</p></li><li><p><strong>Simplicity</strong> &#8211; One database, one query, one transaction, one truth</p></li><li><p><strong>Performance</strong> &#8211; Prefilter by indexed customer_id, then compute distance on small candidate set</p></li><li><p><strong>Observability</strong> &#8211; <code>EXPLAIN ANALYZE</code> shows the full plan: filters, joins, and vector distance together</p></li></ul><h2>Code Change Highlights</h2><p>The similarity search integrates cleanly with the existing agentic architecture:</p><p><strong>Main API</strong> (FastAPI) now includes:</p><ul><li><p><code>GET /api/v1/reports/{id}/similar</code> &#8211; Semantic search with access control</p></li><li><p><code>embedding_service.py</code> &#8211; Generates embeddings via OpenAI</p></li><li><p>Auto-embedding on report/finding creation</p></li></ul><p><strong>Frontend</strong> (React + TypeScript):</p><ul><li><p>User selector in top navigation (demo users: Alice, Bob, Charlie)</p></li><li><p>&#8220;Find Similar&#8221; button triggers similarity search dialog</p></li><li><p>Results filtered by selected user&#8217;s access level</p></li><li><p>Automatic redirect when switching users on detail pages</p></li></ul><p><strong>Database</strong> (CockroachDB):</p><ul><li><p><code>VECTOR(1536)</code> columns for embeddings</p></li><li><p>Access control via <code>user_access</code> and <code>customers</code> tables</p></li><li><p>Single-query retrieval with <code>&lt;-&gt;</code> operator</p></li><li><p>ACID transactions guarantee consistency</p></li></ul><h2>Get the Code</h2><p>Repository: <a href="https://github.com/kikiya/agentic-tuning-reporter">github.com/kikiya/agentic-tuning-reporter</a></p><pre><code>git clone https://github.com/kikiya/agentic-tuning-reporter.git
cd agentic-tuning-reporter
</code></pre><h2>Quick Start</h2><p>See the complete <a href="https://github.com/kikiya/agentic-tuning-reporter/blob/main/SIMILARITY_SEARCH.md"><code>SIMILARITY_SEARCH.md</code></a> guide. Quick version:</p><pre><code># 1. Install dependencies
cd backend &amp;&amp; pip install -r requirements.txt

# 2. Add OpenAI key to backend/.env (You'll need this to generate embeddings)
OPENAI_API_KEY=sk-proj-your-key-here

# 3. Run database migration
cockroach sql --file=schema-add-embeddings.sql

# 4. (Optional) Load demo users for access control
cockroach sql --file=test-data-access-control.sql

# 5. Restart services
cd backend &amp;&amp; python main.py

# 6. Test it!
# Open http://localhost:5173 &#8594; Any report &#8594; Click "Find Similar"
# Switch between users (Alice/Bob/Charlie) to see access control
</code></pre><h2>Core Demonstrations</h2><ol><li><p><strong>Co-Location Pattern</strong> &#8211; Embeddings + metadata + guardrails in one database</p></li><li><p><strong>Single-Query Retrieval</strong> &#8211; Similarity search with access control in one plan</p></li><li><p><strong>ACID Guarantees</strong> &#8211; Embedding updates atomic with metadata changes</p></li><li><p><strong>Access Control</strong> &#8211; Customer isolation, PII filtering, region boundaries</p></li><li><p><strong>Observability</strong> &#8211; <code>EXPLAIN ANALYZE</code> shows the full retrieval plan</p></li><li><p><strong>Demo Architecture</strong> &#8211; User switching to showcase access control in action</p></li></ol><h2>Key Takeaways</h2><p>From the original &#8220;Separation Tax&#8221; post:</p><blockquote><p>&#8220;When semantics meet relations under ACID, retrieval becomes a bounded act of reasoning as opposed to simple recall. Co-locating vectors with metadata lets you express hypotheses as predicates and distances in the same query plan&#8212;what should be visible, which era matters, which regions and roles apply, how to weigh similarity against severity&#8212;and settle it with a single, auditable transaction.&#8221;</p></blockquote><p>This code release demonstrates that thesis in practice. The result isn&#8217;t just &#8220;the model said these are similar,&#8221; but rather &#8220;the database proved these are the most similar items you&#8217;re allowed to see, under one serializable snapshot.&#8221;</p><p>While this is a proof-of-concept with areas for enhancement, the core pattern is pretty solid.</p><h2>Performance Notes</h2><p><strong>Cost:</strong> OpenAI embeddings cost ~$0.02 per 1M tokens. For typical reports (500-2000 words), this is negligible&#8212;a few cents for thousands of reports.</p><p><strong>Query Performance:</strong></p><ul><li><p>With proper indexes (<code>customer_id</code>, <code>status</code>, <code>pii_flag</code>)</p></li><li><p>Prefiltering reduces candidates before distance calculation</p></li><li><p>Exact distance search is fast on filtered sets (&lt;1000 rows)</p></li><li><p>Add ANN indexes when dataset grows large (CockroachDB 24.x+ supports <code>ivfflat</code>)</p></li></ul><h2>Contributing &amp; Feedback</h2><p>This is a learning resource built to help others navigate co-located vector architectures. If you:</p><ul><li><p>Find bugs or improvements</p></li><li><p>Have questions about the implementation</p></li><li><p>Want to share how you adapted it</p></li><li><p>Built something similar</p></li></ul><p>Open an issue or PR! I&#8217;m building this in public to demonstrate practical patterns for &#8220;AI as a collaborator&#8221; systems with deterministic foundations.</p><h2>What&#8217;s Next</h2><p>I&#8217;ll continue exploring the intersection of:</p><ul><li><p>Agentic architectures with stateful reasoning</p></li><li><p>Co-located vectors for bounded retrieval</p></li><li><p>Guardrails that enforce correctness at the database layer</p></li><li><p>Human-in-the-loop workflows with AI assistance</p></li></ul><div><hr></div><h2>Links</h2><ul><li><p><a href="https://kikia.io/2025/10/24/the-separation-tax-when-vectors-live-outside-your-database/">Original &#8220;Separation Tax&#8221; Blog Post</a></p></li><li><p><a href="https://github.com/kikiya/agentic-tuning-reporter">GitHub Repository</a></p></li><li><p><a href="https://github.com/kikiya/agentic-tuning-reporter/blob/main/SIMILARITY_SEARCH.md">Similarity Search Guide</a></p></li><li><p><a href="https://github.com/kikiya/agentic-tuning-reporter/blob/main/QUICKSTART.md">Base App Quick Start</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[The Separation Tax: When You Split Data Between Your Relational And Vector DB]]></title><description><![CDATA[As my agentic applications grew more complex, I started uncovering problems that weren&#8217;t visible when everything was stateless.]]></description><link>https://www.thatskiki.ai/p/the-separation-tax-when-vectors-live-outside-your-database</link><guid isPermaLink="false">https://www.thatskiki.ai/p/the-separation-tax-when-vectors-live-outside-your-database</guid><dc:creator><![CDATA[Kiki C]]></dc:creator><pubDate>Fri, 24 Oct 2025 17:55:13 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/1feda71b-ed6e-4c94-b855-ff09875bde09_299x198.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As my agentic applications grew more complex, I started uncovering problems that weren&#8217;t visible when everything was stateless. At first, while I was proving out small tools (single-shot prompts, temporary context, no persistence), things were simple. But once I layered in state&#8212;then agents that <em>manage</em> state and use RAG to retrieve context dynamically&#8212;the <strong>architecture itself</strong> became part of the problem space.</p><p>In a previous post, I argued that <a href="https://kikia.io/2025/10/09/why-agentic-applications-need-deterministic-foundations/">agentic applications need deterministic foundations.</a><br>The short version: if the top of your stack is intentionally non-deterministic (creative, adaptive AI), the foundation has to be rock-solid.</p><p>However, <strong>non-determinism isn&#8217;t the only cost</strong> you pay when you separate vector and relational data in RAG applications. You eventually encounter a separation tax on correctness, simplicity, performance, and observability.</p><h2>The Cost of Separation</h2><p>When I first added RAG, I reached for a vector database for embeddings and kept CockroachDB for relational data. On paper, it looked fine:</p><ul><li><p>structured metadata in CRDB,</p></li><li><p>embeddings in a vector store,</p></li><li><p>application/agents orchestrating both.</p></li></ul><p>In practice, separation shows up as <strong>four recurring costs</strong>:</p><h3>1) Correctness drift (not just dual-writes)</h3><p>Yes, dual-writes can leave embeddings stale, but another issue is <strong>policy and retrieval diverging</strong>:</p><ul><li><p>Permissions/region/PII flags live in relational tables, while retrieval happens elsewhere.</p></li><li><p>You end up <strong>filtering after retrieval</strong>, which means the model may see candidates it shouldn&#8217;t or reason from an incomplete snapshot.</p></li></ul><h3>2) Complexity</h3><p>Two systems = two schemas, two backups, two monitoring planes, two incident playbooks.</p><ul><li><p>You need glue for sync, retries, and idempotency.</p></li><li><p>Every feature that touches knowledge now crosses a boundary and doubles in complexity.</p></li></ul><h3>3) Performance taxes you can&#8217;t index away</h3><ul><li><p><strong>More hops</strong>: app &#8594; vector DB &#8594; app &#8594; relational DB (then post-filter).</p></li><li><p><strong>Bigger candidate sets</strong>: vague prefiltering in the vector tier, precise constraints later.</p></li><li><p><strong>Worse tail latency</strong>: small percentiles dominate user perception, and each hop compounds it.</p></li></ul><h3>4) Observability gaps</h3><p>You can&#8217;t <code>EXPLAIN</code> an end-to-end plan across two engines.</p><ul><li><p>You see half-plans and infer the rest.</p></li><li><p>Fingerprinting and regression tracking break across the boundary.</p></li></ul><p>Once you move out of POC territory, these can become serious headaches. As with any problem, there are many approaches you could take. In my case, I reached for simplicity.</p><p>With a relational database that supports Vector types, I&#8217;m able to simplify my designs so retrieval, policy, and state coexist to coordinate.</p><h2>From Separation to Co-Location (What We&#8217;ll Build Next)</h2><p>In my real applications, I was not using the Reporter. But I&#8217;ll stick with that as an example, just to keep the context.</p><p>Imagine you&#8217;re a consultant for a company that specializes in tuning databases. We could update the Reporter App such that it has a feature to perform similarity searches. This would enable you to explore actions and outcomes taken on systems similar to one you&#8217;re tuning. But your company may have clients who only want to share data with consultants named on the project. So we&#8217;ll need to account for that as well.</p><p>For this update, we want to design the system such that:</p><ul><li><p><strong>Embeddings and metadata live together</strong> in a relational database,</p></li><li><p><strong>Guardrails (PII, region, role)</strong> are enforced <em>inside</em> the retrieval query,</p></li><li><p><strong>Writes are atomic</strong> (report text + embedding update in a single transaction),</p></li><li><p>And <strong>observability</strong> (e.g., <code>EXPLAIN ANALYZE</code>) applies to the whole plan.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ettw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18005be8-da6b-4dc0-980d-8cd50fc8ced1_299x198.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ettw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18005be8-da6b-4dc0-980d-8cd50fc8ced1_299x198.png 424w, https://substackcdn.com/image/fetch/$s_!ettw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18005be8-da6b-4dc0-980d-8cd50fc8ced1_299x198.png 848w, https://substackcdn.com/image/fetch/$s_!ettw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18005be8-da6b-4dc0-980d-8cd50fc8ced1_299x198.png 1272w, https://substackcdn.com/image/fetch/$s_!ettw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18005be8-da6b-4dc0-980d-8cd50fc8ced1_299x198.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ettw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18005be8-da6b-4dc0-980d-8cd50fc8ced1_299x198.png" width="1024" height="678" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/18005be8-da6b-4dc0-980d-8cd50fc8ced1_299x198.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:678,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!ettw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18005be8-da6b-4dc0-980d-8cd50fc8ced1_299x198.png 424w, https://substackcdn.com/image/fetch/$s_!ettw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18005be8-da6b-4dc0-980d-8cd50fc8ced1_299x198.png 848w, https://substackcdn.com/image/fetch/$s_!ettw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18005be8-da6b-4dc0-980d-8cd50fc8ced1_299x198.png 1272w, https://substackcdn.com/image/fetch/$s_!ettw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18005be8-da6b-4dc0-980d-8cd50fc8ced1_299x198.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In the next section, we&#8217;ll walk through a <strong>minimal schema</strong> and the <strong>core query patterns</strong> that make this work:<br><strong>filter &#8594; (join) &#8594; order by vector distance</strong>, all under one serializable snapshot.</p><p>It&#8217;s a simplified use case, but I think you&#8217;ll find the pattern useful in broader scenarios.</p><h2>The Co-Located Reporter (Concept)</h2><p>The Reporter already:</p><ul><li><p>ingests cluster metrics via API,</p></li><li><p>creates structured records (findings, actions, comments) via MCP tools,</p></li><li><p>persists everything in CockroachDB,</p></li><li><p>and keeps a human reviewer in the loop.</p></li></ul><p>Now we add memory:</p><p>1) <strong>Embed</strong> past reports/findings so the agent can find similar situations.<br>2) <strong>Keep</strong> permissions, region/compliance flags, and PII markers alongside those embeddings.<br>3) <strong>Query</strong> for &#8220;similar cases I&#8217;m allowed to see&#8221; in <strong>one</strong> SQL plan.</p><h2>Minimal Schema (relational + vector, with guardrails)</h2><pre><code>CREATE TABLE reports (

  id            UUID PRIMARY KEY DEFAULT gen_random_uuid(),

  customer_id   UUID NOT NULL,

  title         STRING,

  created_by    STRING,

  created_at    TIMESTAMP NOT NULL DEFAULT now(),

  pii_flag      BOOL NOT NULL DEFAULT FALSE,

  region        STRING,                 -- e.g., 'US', 'EU'

  crdb_version  STRING,

  severity      STRING,                 -- e.g., 'low'|'moderate'|'high'

  report_text   STRING,

  embedding     VECTOR(1536)            -- co-located semantic representation

);

-- Per-user access control for consultants/analysts

CREATE TABLE user_access (

  user_id    UUID NOT NULL,

  report_id  UUID NOT NULL,

  PRIMARY KEY (user_id, report_id)

);

-- Optional content flags for finer guardrails

CREATE TABLE content_flags (

  report_id UUID NOT NULL,

  flag      STRING NOT NULL,            -- e.g., 'pii', 'restricted_customer'

  PRIMARY KEY (report_id, flag)

);</code></pre><p><strong>Observability note</strong>: because this all lives in one database, <code>EXPLAIN ANALYZE</code> and query fingerprints apply to the whole retrieval+policy plan.</p><h2>One Query: Similar Reports I&#8217;m Allowed To See</h2><pre><code>WITH authorized AS (

  SELECT report_id AS id

  FROM user_access

  WHERE user_id = $1

)

SELECT r.id,

       r.title,

       r.customer_id,

       r.region,

       r.severity,

       vector_distance(r.embedding, $2) AS score

FROM   reports AS r

JOIN   authorized a USING (id)

WHERE  r.pii_flag = FALSE

  AND  r.region = $3                  -- region boundary (e.g., match analyst region)

  AND  r.severity IN ('moderate','high')

ORDER  BY score

LIMIT  10;</code></pre><p>This is <strong>retrieval + guardrails + business filters</strong> in a single serializable snapshot:</p><ul><li><p>If a report is flagged PII or out-of-region, it never becomes a candidate.</p></li><li><p>If access is revoked, the join eliminates it before scoring.</p></li><li><p>No post-filter &#8220;oops&#8221; moments.</p></li></ul><h2>The Write Path: Atomic, Not Eventual</h2><p>When the agent (or human) updates a report&#8217;s text and re-embeds it, both changes commit or roll back together:</p><pre><code>BEGIN;

UPDATE reports

SET report_text=$1,
    embedding=$2,
    severity=$3
WHERE id=$4

COMMIT;
</code></pre><p>One transaction = <strong>one truth</strong>.</p><h2>Performance: Filter &#8594; (Join) &#8594; Order by Distance</h2><p>Start with exact search + strong filters:</p><ul><li><p>Constrain by region, severity, customer, time windows.</p></li><li><p>Project only needed columns.</p></li><li><p>Order by vector distance last (on a small candidate set).</p></li></ul><p>As data grows, add ANN indexing; until then, filters + exact distance are fast and fully accurate.</p><h2>Why Co-Location Changes the Shape of RAG</h2><ul><li><p><strong>Correctness</strong>: retrieval and policy run under the same plan/snapshot.</p></li><li><p><strong>Simplicity</strong>: one schema, one backup, one monitoring plane.</p></li><li><p><strong>Performance</strong>: prefilter with indexes; compute distance on fewer rows.</p></li><li><p><strong>Observability</strong>: <code>EXPLAIN ANALYZE</code> shows the <em>whole</em> picture, not just half.</p></li></ul><p>In other words, RAG becomes a <strong>relational capability</strong> the Reporter can rely on deterministically.</p><p>When semantics meet relations under ACID, retrieval becomes a bounded act of <strong>reasoning</strong> as opposed to a simple recall. Co-locating vectors with metadata lets you express hypotheses as predicates and distances in the <strong>same query plan</strong>&#8212;what should be visible, which era matters, which regions and roles apply, how to weigh similarity against severity&#8212;and settle it with a single, auditable transaction.</p><p>The result isn&#8217;t just &#8220;a model said so,&#8221; but <strong>&#8220;the system proved it under one snapshot.&#8221;</strong> That&#8217;s the qualitative shift: rather than just fetching context, the agent <strong>reasons over state</strong> and the database provides the guardrails, evidence, and durability that make those judgments more trustworthy.</p>]]></content:encoded></item><item><title><![CDATA[Why We Call It Slop]]></title><description><![CDATA[You&#8217;ve probably seen the term &#8220;AI slop&#8221; floating around lately &#8212; and you may have even used it.]]></description><link>https://www.thatskiki.ai/p/why-we-call-it-slop</link><guid isPermaLink="false">https://www.thatskiki.ai/p/why-we-call-it-slop</guid><dc:creator><![CDATA[Kiki C]]></dc:creator><pubDate>Fri, 17 Oct 2025 23:32:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!iSlL!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98b6ca8f-4f8a-4e07-8f53-de7264be4f51_401x401.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You&#8217;ve probably seen the term <strong>&#8220;AI slop&#8221;</strong> floating around lately &#8212; and you may have even used it. I bet even seeing my previous sentence with the now slop-identifying em-dash made you feel some type of way. In this post, I want to explore a bit on why we marvel at Gen AI in one breath and in the next we reject it as slop.</p><p>This &#8220;AI slop&#8221; is a new slur for our super-charged machine age. It&#8217;s what we call the weird-fingered images, the off-kilter text, the uncanny attempts at art or writing that feel like someone pressed <em>generate</em> and walked away.</p><p>But beneath the meme is something more revealing: <em>a human defense mechanism and a little bit (maybe a lot?) of ego.</em></p><p>I think we call it slop because we feel simultaneously <strong>threatened and superior.</strong></p><h2>The Slur of the Machine Age</h2><p>When we label something as <em>AI slop</em>, we&#8217;re not just critiquing the output. In reality, we&#8217;re trying to <strong>reassert our place</strong> in a changing world. It&#8217;s a psychological recoil against the idea that machines might now share our creative space.</p><p>Every major shift in technology has birthed its insults. Early digital art was &#8220;soulless.&#8221; Word processors were &#8220;lazy writing.&#8221; Even photography, when new, was dismissed as a &#8220;mechanical trick.&#8221; &#8220;AI slop&#8221; joins that lineage. It&#8217;s an emotional shorthand for &#8220;this thing doesn&#8217;t make me feel special anymore.&#8221;</p><h2>We Crave Relevance</h2><p>Human beings need to matter. For many of us, our sense of identity is deeply tied to <em>what we do</em> rather than <em>how we feel</em>. Work is how we prove worth. So when machines start doing the things that once defined us, we begin to feel displaced and <strong>unmoored</strong>.</p><p>But instead of naming that loss directly, we redirect it outward. We mock, we label, we diminish. &#8220;AI slop&#8221; becomes a socially acceptable way to express technological grief.</p><p>It&#8217;s easier to sneer at the product than to sit with the discomfort of perceived redundancy.</p><h2>We&#8217;re Better Than That</h2><p>We also can&#8217;t imagine being redundant because, naturally, we feel more valuable than the tools we wield. In the past, we praised the author, not the pen. You&#8217;ve probably never considered which computer or operating system your favorite novelist uses.</p><p>But with Gen AI, it feels like the awe has shifted to the tool, leaving less for the human. Where it&#8217;s obvious that a word processor doesn&#8217;t <em>create stories</em>, Gen AI seems to blur that line. And because of that illusion, we&#8217;re on high alert. We find ourselves constantly scanning for ways to prove we&#8217;re still better than the machine.</p><h2>When Humans Err, It&#8217;s Humanity. When AI Errs, It&#8217;s Slop.</h2><p>We romanticize our mistakes. A typo is &#8220;authentic.&#8221; A misstep is &#8220;part of the process.&#8221; But when a model does it, we call it &#8220;slop.&#8221;</p><p>We don&#8217;t just measure machine performance by output. We measure it by emotion. Does it make us feel diminished or inspired? </p><p>The irony is that many AI &#8220;failures&#8221; look a lot like human drafts: first tries, rough sketches and unedited thoughts. The difference is that when <em>we</em> make something messy, we call it creativity. When <em>it</em> does, we call it trash.</p><p>Furthermore, we shame the human who dared to use it.</p><h2>Who Calls It &#8220;Slop&#8221; &#8212; and Why</h2><p>Many of the strongest reactions come from highly experienced people who have spent years mastering craft, process, or precision. The ones who know what &#8220;good&#8221; actually means. Theirs is an earned skepticism in many ways.</p><p>I remember being in one of my first corporate jobs after university, working on a mission-critical application. The senior architect on the project had designed a remarkably clean, consistent pattern for building new services. When I was assigned to build one, I followed his structure exactly and got working code.</p><p>During the code review, he glanced at my work and said, &#8220;You can always tell when someone copy/pastes to start.&#8221;</p><p>He didn&#8217;t mean it cruelly, and I don&#8217;t think he realized how it landed. Up until that moment, I was proud. I&#8217;d followed his pattern, learned from it, and built something real. But what I heard in his tone wasn&#8217;t pride in having created a system others could replicate. What I heard was uncertainty. </p><p>And I understand that now.</p><p>When you&#8217;ve spent years building a foundation and suddenly someone (or something) can produce competent results by following your pattern, it stirs complicated emotions. Pride and fear coexist. I don&#8217;t think that the architect resented me. But I do wonder if he felt like he was watching his expertise become invisible through success.</p><p>That&#8217;s what&#8217;s happening to many professionals today.</p><p>Humans have spent generations producing patterns, frameworks, and cultural blueprints. Now AI, trained on those very patterns, can generate something good enough in seconds. It&#8217;s dizzying. You can either cry &#8220;slop!&#8221; or step back and marvel that our collective work has reached a point where a machine can echo it at all.</p><p>And many people do have reason to pause. I think our discomfort with GenAI doing our work, especially creative work, stems from a deep human desire to feel that our contributions still matter in a world that increasingly automates expression.</p><p>We&#8217;ve been here before, watching the tools we built start to outpace us, or at least look like they do. And yet, if we&#8217;re honest, it&#8217;s rarely the tools themselves that scare us.</p><h2>The Real Threat Isn&#8217;t the Machine</h2><p>What really unnerves us are the people who might use those tools against us. The manager who sees automation as a shortcut. The founder who values efficiency over expertise. The peer who leans on the tool instead of the team.</p><p>&#8220;AI slop&#8221; becomes a rallying cry: <em>Don&#8217;t replace us. Don&#8217;t sell out. Don&#8217;t pretend the machine can do what we do.</em></p><p>It&#8217;s a human-to-human warning disguised as a critique of code. Calling out &#8220;slop&#8221; is a way of reminding each other not to become complicit in our own obsolescence.</p><p>But the truth is, AI isn&#8217;t the replacement. No tool has ever replaced human intent; it simply amplifies whatever direction we point it in.</p><p>If I used spell check and Grammarly to collect a bunch of grammatically correct sentences, you wouldn&#8217;t call it an essay. Grammarly can&#8217;t write one for you. And although Gen AI can generate an essay, it&#8217;s rarely inspiring on its own.</p><p>When the direction is thoughtful, the outcome can be extraordinary. When it&#8217;s careless, it looks like slop. That&#8217;s because we humans are still learning how to use AI.</p><p>We might consider judging work by the product itself, not by the tool used to create it.</p><h2>From Shame to Standard</h2><p>Eventually, the cultural shame around using AI will fade. It will be as ordinary as using spellcheck or autocomplete.</p><p>Just as spellcheck doesn&#8217;t make you a writer, AI doesn&#8217;t make you an expert. The tool doesn&#8217;t replace the need for judgment, intent, or taste.</p><p>Instead of being so fixated on identifying AI slop, we should turn our focus to cultivating humans who can shape what it produces with discernment and curiosity instead of defensiveness or fear.</p><p>Learning to use GenAI to create tasteful work will be the mark of creative maturity in the AI era. When it comes to writing code, or doing other non-creative work (I know code is creative in its own way. Don&#8217;t fight me) I think GenAI will have much less resistance to acceptance. Actually when I think about it, developers using coding agents have mostly come to accept AI assistance with some level of joy. Even if resistant at first. </p><h2>So Who&#8217;s Really Being Sloppy?</h2><p>Before we call the next image or paragraph &#8220;AI slop,&#8221; it&#8217;s worth pausing. What are we really reacting to? Are we offended by the machine, or what it reflects back about us?</p><p>Maybe it&#8217;s neither. Maybe it&#8217;s just the natural awkwardness of a species learning to collaborate with its own invention.</p><p>Whatever it is, we should learn to name it honestly. We can learn to identify and articulate whether it&#8217;s disappointment in the product, discomfort with the process, or resistance to change. Some work will need to be rejected. Some will just need another round of human collaboration and iteration.</p><p>We are not (yet :P) being replaced by AI. But I do feel like we are being reshaped through our relationship with it.</p><p><strong>And the sooner we stop shouting &#8220;slop,&#8221; the sooner we can start shaping what&#8217;s next.</strong></p>]]></content:encoded></item><item><title><![CDATA[Code Release: CRDB Tuning Report Generator with AI Agents]]></title><description><![CDATA[A companion to &#8220;Reimagining My Application as an Agentic Workflow (Part 4)&#8220;]]></description><link>https://www.thatskiki.ai/p/code-release-crdb-tuning-report-generator-with-ai-agents</link><guid isPermaLink="false">https://www.thatskiki.ai/p/code-release-crdb-tuning-report-generator-with-ai-agents</guid><dc:creator><![CDATA[Kiki C]]></dc:creator><pubDate>Fri, 17 Oct 2025 18:46:33 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/3a64ce8a-b398-4292-806d-4d11ac9185d0_72x72.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>A companion to &#8220;<a href="https://kikia.io/2025/10/05/reimagining-my-application-as-an-agentic-workflow/">Reimagining My Application as an Agentic Workflow (Part 4)</a>&#8220;</em></p><p>In a previous post, I walked through how I transformed a manual reporting workflow into an agentic one by giving an AI agent the same tools a human analyst would use to create CockroachDB performance reports.</p><p>Today, I&#8217;m releasing the full working code so you can explore, learn from, or adapt it for your own projects.</p><h2>What You&#8217;ll Find</h2><p>This is a complete, working proof-of-concept demonstrating:</p><ul><li><p><strong><a href="http://fast-agent.ai">FastAgent</a></strong> for agentic workflows</p></li><li><p><strong>MCP (Model Context Protocol)</strong> integration with <strong><a href="https://gofastmcp.com/integrations/fastapi#fastapi-fastmcp">FastMCP 2.0</a></strong> (Using FastAPI to generate FastMCP)</p></li><li><p>A simple <strong>React frontend</strong> with AI-powered and manual report creation</p></li><li><p><strong><a href="https://www.cockroachlabs.com/docs/">CockroachDB</a></strong> integration for cluster metrics</p></li></ul><p><strong>Note:</strong> This is a proof-of-concept built to demonstrate a simple agentic architecture pattern. There are areas for improvement (like configurable time ranges for metrics collection), but the core concepts are ready and the code is clear enough to learn from and build upon.</p><h2>Get the Code</h2><p><strong>Repository:</strong> <a href="https://github.com/kikiya/agentic-tuning-reporter">github.com/kikiya/agentic-tuning-reporter</a></p><p><code>git clone https://github.com/kikiya/agentic-tuning-reporter.git</code></p><p><code>cd agentic-tuning-reporter</code></p><h2>Quick Start</h2><p>The repo includes a <a href="https://github.com/kikiya/agentic-tuning-reporter/blob/main/QUICKSTART.md">QUICKSTART.md</a> that gets you running in ~5 minutes:</p><ol><li><p><strong>Setup database</strong> &#8211; One script creates everything</p></li><li><p><strong>Start backend services</strong> &#8211; Main API (8001) + Agent Service (8002)</p></li><li><p><strong>Launch frontend</strong> &#8211; React UI on port 5173</p></li></ol><p>Then click &#8220;New Report&#8221; &#8594; &#8220;Quick Analysis&#8221; and watch the AI agent:</p><ul><li><p>Gather cluster metrics</p></li><li><p>Analyze performance</p></li><li><p>Create structured findings</p></li><li><p>Generate actionable recommendations</p></li><li><p>Save everything to the database</p></li></ul><p>All automatically. All editable afterward.</p><h2>Architecture Highlights</h2><h3>Three Services Working Together</h3><p><strong>Main API</strong> &#8211; FastAPI service with:</p><ul><li><p><code>Reports</code> CRUD operations</p></li><li><p>Cluster metrics endpoints (topology, schema, CPU, slow queries)</p></li><li><p>Direct CockroachDB connection</p></li></ul><p><strong>Agent Service</strong> &#8211; Separate FastAPI service with:</p><ul><li><p>AI-powered report generation</p></li><li><p>FastAgent + LLM integration</p></li><li><p><strong>MCP server that exposes Main API as tools</strong></p></li></ul><p><strong>Frontend</strong> &#8211; React + TypeScript with:</p><ul><li><p>&#8220;Quick Analysis&#8221; (AI-generated reports)</p></li><li><p>&#8220;Custom Report&#8221; (manual creation)</p></li><li><p>Both types are fully editable</p></li></ul><h3>Model Context Protocol for tools</h3><p>The key insight from the blog post was giving the agent <strong>the same API access as a human</strong>. Here&#8217;s how:</p><pre><code># backend/mcp/reporter_mcp.py

from main import app

from fastmcp import FastMCP

# Convert entire FastAPI app to MCP tools

mcp = FastMCP.from_fastapi(app=app)</code></pre><p>Every endpoint becomes a tool the agent can call. No manual wrapping needed.</p><h2>What You Can Learn</h2><p>This repo demonstrates:</p><ol><li><p><strong>Agentic Architecture</strong> &#8211; An introduction into how to structure apps where AI agents act autonomously</p></li><li><p><strong>MCP Integration</strong> &#8211; Practical example of Model Context Protocol</p></li><li><p><strong>Tool Design</strong> &#8211; What makes good tools for AI agents</p></li><li><p><strong>Human-in-the-Loop</strong> &#8211; AI generates, humans refine via the UI</p></li><li><p><strong>Service Separation</strong> &#8211; Why the agent service is separate from the main API</p></li></ol><h2>Use Cases</h2><p>This pattern works for any workflow where you want AI to:</p><ul><li><p>Gather data from multiple sources</p></li><li><p>Analyze and synthesize information</p></li><li><p>Create structured outputs</p></li><li><p>Save results for human review</p></li></ul><p>Examples:</p><ul><li><p>Security audit reports</p></li><li><p>Code review summaries</p></li><li><p>Customer support analysis</p></li><li><p>Financial report generation</p></li><li><p>Research synthesis</p></li></ul><h2>Documentation</h2><p>The repo includes:</p><ul><li><p><strong>README.md</strong> &#8211; Comprehensive setup and architecture guide</p></li><li><p><strong>QUICKSTART.md</strong> &#8211; Get running in 5 minutes</p></li><li><p><strong>backend/AGENT_SERVICE.md</strong> &#8211; Deep dive on agent architecture</p></li><li><p><strong>backend/mcp/README.md</strong> &#8211; MCP server explanation</p></li></ul><h2>What You&#8217;ll Need</h2><ul><li><p>CockroachDB running locally (or remote cluster)</p></li><li><p>Python 3.12 (required for FastAgent)</p></li><li><p>Node.js 16+</p></li><li><p>Anthropic API key (or your choice of model. FastAgent supports most majors)</p></li><li><p>30 minutes to explore</p></li></ul><h2>Key Takeaways</h2><p>As I wrote in the original post:</p><p><em>&#8220;What I love most is that the original pattern of direct value coupling still holds. Every model improvement or new MCP tool instantly enriches the agent&#8217;s output without code rewrites.&#8221;</em></p><p>This architecture is:</p><ul><li><p><strong>Extensible</strong> &#8211; Add new tools by adding API endpoints, or new MCP servers</p></li><li><p><strong>Maintainable</strong> &#8211; Clean separation of concerns</p></li><li><p><strong>Flexible</strong> &#8211; Swap models, change prompts, no rewrites</p></li><li><p><strong>Human-centric</strong> &#8211; AI assists, humans decide</p></li></ul><h2>Known Limitations &amp; Future Improvements</h2><p>This is a proof-of-concept. Some areas for enhancement:</p><ul><li><p><strong>Time Range Selection</strong> &#8211; Currently uses default time windows for metrics. Could add UI controls for &#8220;last hour&#8221;, &#8220;last day&#8221;, &#8220;custom range&#8221;</p></li><li><p><strong>Report Scheduling</strong> &#8211; No automated report generation on a schedule</p></li><li><p><strong>Multi-Cluster Support</strong> &#8211; Currently targets one cluster at a time</p></li><li><p><strong>Advanced Filtering</strong> &#8211; Could add more granular filtering for slow queries and metrics</p></li><li><p><strong>Report Templates</strong> &#8211; Could support different report types (weekly summary, incident analysis, etc.)</p></li></ul><p>The core pattern is solid and these are just natural extensions as you adapt it to your needs.</p><h2>Contributing &amp; Feedback</h2><p>This is a learning resource. If you:</p><ul><li><p>Find bugs or improvements</p></li><li><p>Have questions about the architecture</p></li><li><p>Want to share how you adapted it</p></li></ul><p>Open an issue or PR! I&#8217;m building this in public to help others navigate the shift from &#8220;AI as a feature&#8221; to &#8220;AI as a collaborator.&#8221;</p><h2>What&#8217;s Next</h2><p>I&#8217;ll continue exploring agentic architectures&#8212;how agents, tools, and humans can work together as adaptive systems. Follow along at <a href="https://kikia.io">kikia.io</a> or watch the repo for updates.</p><div><hr></div><p><strong>Links:</strong></p><ul><li><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hq1M!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10c212f6-f6c8-4813-9fc5-57fa4dc8ca82_72x72.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hq1M!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10c212f6-f6c8-4813-9fc5-57fa4dc8ca82_72x72.png 424w, https://substackcdn.com/image/fetch/$s_!hq1M!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10c212f6-f6c8-4813-9fc5-57fa4dc8ca82_72x72.png 848w, https://substackcdn.com/image/fetch/$s_!hq1M!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10c212f6-f6c8-4813-9fc5-57fa4dc8ca82_72x72.png 1272w, https://substackcdn.com/image/fetch/$s_!hq1M!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10c212f6-f6c8-4813-9fc5-57fa4dc8ca82_72x72.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hq1M!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10c212f6-f6c8-4813-9fc5-57fa4dc8ca82_72x72.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/10c212f6-f6c8-4813-9fc5-57fa4dc8ca82_72x72.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&#128221;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="&#128221;" title="&#128221;" srcset="https://substackcdn.com/image/fetch/$s_!hq1M!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10c212f6-f6c8-4813-9fc5-57fa4dc8ca82_72x72.png 424w, https://substackcdn.com/image/fetch/$s_!hq1M!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10c212f6-f6c8-4813-9fc5-57fa4dc8ca82_72x72.png 848w, https://substackcdn.com/image/fetch/$s_!hq1M!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10c212f6-f6c8-4813-9fc5-57fa4dc8ca82_72x72.png 1272w, https://substackcdn.com/image/fetch/$s_!hq1M!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10c212f6-f6c8-4813-9fc5-57fa4dc8ca82_72x72.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><p><a href="https://kikia.io/2025/10/05/reimagining-my-application-as-an-agentic-workflow/">Original Blog Post</a></p></li><li><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Bu3q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ec9d780-ec37-4067-816d-0dfc897691ef_72x72.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Bu3q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ec9d780-ec37-4067-816d-0dfc897691ef_72x72.png 424w, https://substackcdn.com/image/fetch/$s_!Bu3q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ec9d780-ec37-4067-816d-0dfc897691ef_72x72.png 848w, https://substackcdn.com/image/fetch/$s_!Bu3q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ec9d780-ec37-4067-816d-0dfc897691ef_72x72.png 1272w, https://substackcdn.com/image/fetch/$s_!Bu3q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ec9d780-ec37-4067-816d-0dfc897691ef_72x72.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Bu3q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ec9d780-ec37-4067-816d-0dfc897691ef_72x72.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7ec9d780-ec37-4067-816d-0dfc897691ef_72x72.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&#128187;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="&#128187;" title="&#128187;" srcset="https://substackcdn.com/image/fetch/$s_!Bu3q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ec9d780-ec37-4067-816d-0dfc897691ef_72x72.png 424w, https://substackcdn.com/image/fetch/$s_!Bu3q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ec9d780-ec37-4067-816d-0dfc897691ef_72x72.png 848w, https://substackcdn.com/image/fetch/$s_!Bu3q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ec9d780-ec37-4067-816d-0dfc897691ef_72x72.png 1272w, https://substackcdn.com/image/fetch/$s_!Bu3q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ec9d780-ec37-4067-816d-0dfc897691ef_72x72.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><p><a href="https://github.com/kikiya/agentic-tuning-reporter">GitHub Repository</a></p></li><li><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Eewt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64b64e66-0e67-4e1f-929f-a05c621f88e5_72x72.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Eewt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64b64e66-0e67-4e1f-929f-a05c621f88e5_72x72.png 424w, https://substackcdn.com/image/fetch/$s_!Eewt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64b64e66-0e67-4e1f-929f-a05c621f88e5_72x72.png 848w, https://substackcdn.com/image/fetch/$s_!Eewt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64b64e66-0e67-4e1f-929f-a05c621f88e5_72x72.png 1272w, https://substackcdn.com/image/fetch/$s_!Eewt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64b64e66-0e67-4e1f-929f-a05c621f88e5_72x72.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Eewt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64b64e66-0e67-4e1f-929f-a05c621f88e5_72x72.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/64b64e66-0e67-4e1f-929f-a05c621f88e5_72x72.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&#128640;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="&#128640;" title="&#128640;" srcset="https://substackcdn.com/image/fetch/$s_!Eewt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64b64e66-0e67-4e1f-929f-a05c621f88e5_72x72.png 424w, https://substackcdn.com/image/fetch/$s_!Eewt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64b64e66-0e67-4e1f-929f-a05c621f88e5_72x72.png 848w, https://substackcdn.com/image/fetch/$s_!Eewt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64b64e66-0e67-4e1f-929f-a05c621f88e5_72x72.png 1272w, https://substackcdn.com/image/fetch/$s_!Eewt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64b64e66-0e67-4e1f-929f-a05c621f88e5_72x72.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><p><a href="https://github.com/kikiya/agentic-tuning-reporter/blob/main/QUICKSTART.md">QUICKSTART Guide</a></p></li></ul><div><hr></div><p><em>Built with</em></p><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kOLe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad919574-24d5-4bb6-ac00-9a8404c2531b_72x72.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kOLe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad919574-24d5-4bb6-ac00-9a8404c2531b_72x72.png 424w, https://substackcdn.com/image/fetch/$s_!kOLe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad919574-24d5-4bb6-ac00-9a8404c2531b_72x72.png 848w, https://substackcdn.com/image/fetch/$s_!kOLe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad919574-24d5-4bb6-ac00-9a8404c2531b_72x72.png 1272w, https://substackcdn.com/image/fetch/$s_!kOLe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad919574-24d5-4bb6-ac00-9a8404c2531b_72x72.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kOLe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad919574-24d5-4bb6-ac00-9a8404c2531b_72x72.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ad919574-24d5-4bb6-ac00-9a8404c2531b_72x72.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&#10084;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="&#10084;" title="&#10084;" srcset="https://substackcdn.com/image/fetch/$s_!kOLe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad919574-24d5-4bb6-ac00-9a8404c2531b_72x72.png 424w, https://substackcdn.com/image/fetch/$s_!kOLe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad919574-24d5-4bb6-ac00-9a8404c2531b_72x72.png 848w, https://substackcdn.com/image/fetch/$s_!kOLe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad919574-24d5-4bb6-ac00-9a8404c2531b_72x72.png 1272w, https://substackcdn.com/image/fetch/$s_!kOLe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad919574-24d5-4bb6-ac00-9a8404c2531b_72x72.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><p><em> to demonstrate agentic architecture patterns. Not production-ready, but production-inspired.</em></p>]]></content:encoded></item><item><title><![CDATA[Why Agentic Applications Need Deterministic Foundations]]></title><description><![CDATA[Building agentic applications means you&#8217;re deliberately inviting non-determinism into your system.]]></description><link>https://www.thatskiki.ai/p/why-agentic-applications-need-deterministic-foundations</link><guid isPermaLink="false">https://www.thatskiki.ai/p/why-agentic-applications-need-deterministic-foundations</guid><dc:creator><![CDATA[Kiki C]]></dc:creator><pubDate>Thu, 09 Oct 2025 19:56:04 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!iSlL!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98b6ca8f-4f8a-4e07-8f53-de7264be4f51_401x401.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Building agentic applications means you&#8217;re deliberately inviting non-determinism into your system. AI agents&#8217; creativity and adaptability is super powerful, but it&#8217;s also dangerous if your <strong>data layer</strong> isn&#8217;t rock solid. The more flexible the top of your stack becomes, the stronger the foundation underneath has to be. This principle is what led me to anchor my agentic stack in CockroachDB.</p><p>I&#8217;ve been working closely with Gen AI for a few years now. If you&#8217;ve been following along, you&#8217;ll recall I first used Gen AI as a partner in deconstructing data and ideas in my creative process (I wrote more about that <a href="https://kikia.io/2025/07/05/from-prompts-to-programs-to-agents-part-1/">here</a>).</p><p>When OpenAI introduced the API, I began using ChatGPT programmatically. Then came &#8220;Functions/Tools,&#8221; which expanded my programmatic use (I talk about that <a href="https://kikia.io/2025/08/03/my-first-ai-application/">here</a>). Finally, Model Context Protocol arrived, giving LLMs an entirely new level of power. (A bit on my first app re-imaged as agentic <a href="https://kikia.io/2025/10/05/reimagining-my-application-as-an-agentic-workflow/">here</a>).</p><p>As the ecosystem evolved, so did my approach to building applications with LLMs. At first, my projects didn&#8217;t need persistence. But soon enough, data became the central to my functionality, and that shift changed major elements in my stack.</p><h2><strong>From zero to 100 on persistence</strong></h2><p>My first AI app was simple: a report generator that gathered system details, sent them as a formatted prompt, and had the LLM create a detailed report and actionable analysis. That didn&#8217;t require much tech: Node/Express, some HTML and CSS, the OpenAI API, and voila! No persistent data, no complex stack.</p><p>But that phase didn&#8217;t last long.</p><p>As my apps grew more complex, <em>data stopped being incidental and became more central to my functionality</em>. Apps weren&#8217;t just calling LLM APIs, <em><strong>agents</strong></em> were managing state, working with metadata, and contextual data to make better decisions. I started to think more about how to give my agents more of the right context at the right time.</p><p>Eventually retrieval-augmented generation (RAG) entered the picture: I wanted agents to surface relevant context on demand, not just query a database.</p><p>And that brought me to the next stage.</p><h2>Evolving without introducing unnecessary complexity</h2><p>One of my approaches to RAG leveraged embeddings, which to me meant a vector database. So I reached for Pinecone while still leaning on CockroachDB for relational data. initially, it looked like success to me! I was so caught up in the novelty of my apps new super powers that I lost sight of classic principled architecture.</p><p>By using two different data stores, I had revived the notorious dual-write problem. Ugh! One piece of data lived in CRDB, its semantic twin lived in Pinecone, and my agents were managing both. Sometimes they succeeded. Sometimes they left things inconsistent, like updating a record in CRDB but leaving the embedding stale in Pinecone.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!q7eT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe766b7b-cdaf-465d-8c51-ecb5a8362bca_300x165.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!q7eT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe766b7b-cdaf-465d-8c51-ecb5a8362bca_300x165.png 424w, https://substackcdn.com/image/fetch/$s_!q7eT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe766b7b-cdaf-465d-8c51-ecb5a8362bca_300x165.png 848w, https://substackcdn.com/image/fetch/$s_!q7eT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe766b7b-cdaf-465d-8c51-ecb5a8362bca_300x165.png 1272w, https://substackcdn.com/image/fetch/$s_!q7eT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe766b7b-cdaf-465d-8c51-ecb5a8362bca_300x165.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!q7eT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe766b7b-cdaf-465d-8c51-ecb5a8362bca_300x165.png" width="300" height="165" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/be766b7b-cdaf-465d-8c51-ecb5a8362bca_300x165.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:165,&quot;width&quot;:300,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!q7eT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe766b7b-cdaf-465d-8c51-ecb5a8362bca_300x165.png 424w, https://substackcdn.com/image/fetch/$s_!q7eT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe766b7b-cdaf-465d-8c51-ecb5a8362bca_300x165.png 848w, https://substackcdn.com/image/fetch/$s_!q7eT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe766b7b-cdaf-465d-8c51-ecb5a8362bca_300x165.png 1272w, https://substackcdn.com/image/fetch/$s_!q7eT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe766b7b-cdaf-465d-8c51-ecb5a8362bca_300x165.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>It&#8217;s bad enough when you have hard coded instructions performing dual-writes. But this new age &#8220;soft coded&#8221; agent was amplifying risk. How quickly had I gone from a principled architect to a person asking non-deterministic agents to perform a dual-write?!</p><p>Thankfully I found myself and refined my approach.</p><p>The solution wasn&#8217;t to make agents more careful. Agent instructions and guardrails are a valid part of hardening your system. But I had to make a more fundamental change to strengthen the system. I decided to simplify the architecture itself. CockroachDB now supports vector embeddings, which meant I could co-locate both relational metadata and vector data in the same system. Of course, I acknowledge there are other ways to solve for dual-writes! This was the simplest way to completely avoid dual-writing in my solution.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gCmj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89fb7075-829a-4032-96d2-048b039703ef_299x208.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gCmj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89fb7075-829a-4032-96d2-048b039703ef_299x208.png 424w, https://substackcdn.com/image/fetch/$s_!gCmj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89fb7075-829a-4032-96d2-048b039703ef_299x208.png 848w, https://substackcdn.com/image/fetch/$s_!gCmj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89fb7075-829a-4032-96d2-048b039703ef_299x208.png 1272w, https://substackcdn.com/image/fetch/$s_!gCmj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89fb7075-829a-4032-96d2-048b039703ef_299x208.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gCmj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89fb7075-829a-4032-96d2-048b039703ef_299x208.png" width="300" height="208" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/89fb7075-829a-4032-96d2-048b039703ef_299x208.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:208,&quot;width&quot;:300,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!gCmj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89fb7075-829a-4032-96d2-048b039703ef_299x208.png 424w, https://substackcdn.com/image/fetch/$s_!gCmj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89fb7075-829a-4032-96d2-048b039703ef_299x208.png 848w, https://substackcdn.com/image/fetch/$s_!gCmj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89fb7075-829a-4032-96d2-048b039703ef_299x208.png 1272w, https://substackcdn.com/image/fetch/$s_!gCmj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89fb7075-829a-4032-96d2-048b039703ef_299x208.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>For example: I could now design a system to, store both support ticket metadata (customer, severity, etc) and embeddings of past tickets in CRDB. One query could return both related cases and the structured context for escalation. I could do this <strong>without</strong> dual writes <strong>and</strong> with other performance benefits I&#8217;ll dive into a little deeper in different material.</p><p>This simplification worked but there was another foundational reason for using CRDB as my apps DB.</p><h2>Limiting non-determinism at the foundation</h2><p>I glossed over this earlier but the importance of CRDB&#8217;s consistent data principles can&#8217;t be overstated in the context of building agentic apps. Think about how CRDB handles concurrency and anomalies. By default, it uses serializable isolation. When you&#8217;re already introducing a degree of uncertainty by design in your stack, you can&#8217;t afford race conditions or corrupted states in your foundation.</p><p>In a weaker isolation model, two agents might interleave updates and leave a nonsense value like truefalse. With CRDB, one transaction wins cleanly, keeping the system correct. That stability matters when agents participate in state management. In my opinion it matters when introducing state to any system but especially one where you have this extra area of non-determinism.</p><h2><strong>My takeaway</strong></h2><p>AI applications are new, fun, and powerful. But they also run risk to your user&#8217;s Trust by introducing doubt. It doesn&#8217;t even have to be AI&#8217;s fault that a data anomaly occurred, especially if you&#8217;re using a database with lower levels of transaction isolation. But the user&#8217;s perception is everything and blaming AI for any off experience is just easy default behavior. You want to be able to infuse AI into your solutions without weakening or damaging the trust you&#8217;ve built with your customers. And since building agentic applications means embracing some uncertainty at the top of the stack, that only works if you eliminate uncertainty at the bottom.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jabi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dac94f5-5caf-4725-84d5-8577a5d09dd2_299x213.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jabi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dac94f5-5caf-4725-84d5-8577a5d09dd2_299x213.png 424w, https://substackcdn.com/image/fetch/$s_!jabi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dac94f5-5caf-4725-84d5-8577a5d09dd2_299x213.png 848w, https://substackcdn.com/image/fetch/$s_!jabi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dac94f5-5caf-4725-84d5-8577a5d09dd2_299x213.png 1272w, https://substackcdn.com/image/fetch/$s_!jabi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dac94f5-5caf-4725-84d5-8577a5d09dd2_299x213.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jabi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dac94f5-5caf-4725-84d5-8577a5d09dd2_299x213.png" width="300" height="213" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1dac94f5-5caf-4725-84d5-8577a5d09dd2_299x213.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:213,&quot;width&quot;:300,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!jabi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dac94f5-5caf-4725-84d5-8577a5d09dd2_299x213.png 424w, https://substackcdn.com/image/fetch/$s_!jabi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dac94f5-5caf-4725-84d5-8577a5d09dd2_299x213.png 848w, https://substackcdn.com/image/fetch/$s_!jabi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dac94f5-5caf-4725-84d5-8577a5d09dd2_299x213.png 1272w, https://substackcdn.com/image/fetch/$s_!jabi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dac94f5-5caf-4725-84d5-8577a5d09dd2_299x213.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>If <em>consistent</em> data is critical to your application&#8217;s core function and you have agents that manage or rely on that data, a rock-solid data layer is just non-negotiable. For me, that&#8217;s what CockroachDB provides: <strong>strong data consistency</strong>, resilience across failures, and a simplified architecture for both relational and vector data.</p>]]></content:encoded></item><item><title><![CDATA[Reimagining My Application as an Agentic Workflow (Part 4)]]></title><description><![CDATA[From Prompts to Programs to Agents, Part 4]]></description><link>https://www.thatskiki.ai/p/reimagining-my-application-as-an-agentic-workflow</link><guid isPermaLink="false">https://www.thatskiki.ai/p/reimagining-my-application-as-an-agentic-workflow</guid><dc:creator><![CDATA[Kiki C]]></dc:creator><pubDate>Sun, 05 Oct 2025 18:47:10 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/7584aea8-a8ee-473e-be57-5f532258ead8_298x172.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>From Prompts to Programs to Agents, Part 4</h3><p>In the last post, we looked at how AI reshaped teamwork. I discussed how humans stayed in the loop while friction melted away. Now, it&#8217;s time to reimagine the <em>Reporter</em> itself.</p><p>Let&#8217;s start with its purpose. The report was never for reporting&#8217;s sake&#8212;it&#8217;s meant to drive <strong>action</strong>. People need to share it, review it, prune or expand recommendations, maybe even track and execute actions directly from it. That simple workflow carries a lot of potential.</p><p>For now, though, I&#8217;ll keep things simple to show what happens when we give the <em>Reporter</em> more power, more <strong>agency</strong>, without losing control.</p><div><hr></div><h2>From Human Workflow to Agentic Workflow</h2><p>Before we automate, let&#8217;s think about the regular, human-first flow.</p><p>Imagine you have a person responsible for analyzing cluster metrics and building a report. That person has access to the CockroachDB Cluster API and a web application where reports can be created, reviewed, and edited.</p><p>I&#8217;ve built a small demonstration app to show this process:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R_BO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe7914e8-b8a1-4bce-8cd3-c655a4cdd793_298x172.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R_BO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe7914e8-b8a1-4bce-8cd3-c655a4cdd793_298x172.png 424w, https://substackcdn.com/image/fetch/$s_!R_BO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe7914e8-b8a1-4bce-8cd3-c655a4cdd793_298x172.png 848w, https://substackcdn.com/image/fetch/$s_!R_BO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe7914e8-b8a1-4bce-8cd3-c655a4cdd793_298x172.png 1272w, https://substackcdn.com/image/fetch/$s_!R_BO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe7914e8-b8a1-4bce-8cd3-c655a4cdd793_298x172.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R_BO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe7914e8-b8a1-4bce-8cd3-c655a4cdd793_298x172.png" width="1000" height="576" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fe7914e8-b8a1-4bce-8cd3-c655a4cdd793_298x172.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:576,&quot;width&quot;:1000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Screenshot of Reporting App Dashboard&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Screenshot of Reporting App Dashboard" title="Screenshot of Reporting App Dashboard" srcset="https://substackcdn.com/image/fetch/$s_!R_BO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe7914e8-b8a1-4bce-8cd3-c655a4cdd793_298x172.png 424w, https://substackcdn.com/image/fetch/$s_!R_BO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe7914e8-b8a1-4bce-8cd3-c655a4cdd793_298x172.png 848w, https://substackcdn.com/image/fetch/$s_!R_BO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe7914e8-b8a1-4bce-8cd3-c655a4cdd793_298x172.png 1272w, https://substackcdn.com/image/fetch/$s_!R_BO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe7914e8-b8a1-4bce-8cd3-c655a4cdd793_298x172.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Reports App Dashboard, Initial Load</figcaption></figure></div><p>The analyst uses the Cluster API to gather metrics, then creates findings in the web application.</p><div class="captioned-image-container"><figure><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Moe4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5925cef2-1ba9-4a03-86f3-42e6135cad72_299x172.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Moe4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5925cef2-1ba9-4a03-86f3-42e6135cad72_299x172.png 424w, https://substackcdn.com/image/fetch/$s_!Moe4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5925cef2-1ba9-4a03-86f3-42e6135cad72_299x172.png 848w, https://substackcdn.com/image/fetch/$s_!Moe4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5925cef2-1ba9-4a03-86f3-42e6135cad72_299x172.png 1272w, https://substackcdn.com/image/fetch/$s_!Moe4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5925cef2-1ba9-4a03-86f3-42e6135cad72_299x172.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Moe4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5925cef2-1ba9-4a03-86f3-42e6135cad72_299x172.png" width="1024" height="588" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5925cef2-1ba9-4a03-86f3-42e6135cad72_299x172.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:588,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!Moe4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5925cef2-1ba9-4a03-86f3-42e6135cad72_299x172.png 424w, https://substackcdn.com/image/fetch/$s_!Moe4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5925cef2-1ba9-4a03-86f3-42e6135cad72_299x172.png 848w, https://substackcdn.com/image/fetch/$s_!Moe4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5925cef2-1ba9-4a03-86f3-42e6135cad72_299x172.png 1272w, https://substackcdn.com/image/fetch/$s_!Moe4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5925cef2-1ba9-4a03-86f3-42e6135cad72_299x172.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Create new report</figcaption></figure></div></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Q3B_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa9d6583-84b0-4d87-9cae-0be1b1416291_299x172.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Q3B_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa9d6583-84b0-4d87-9cae-0be1b1416291_299x172.png 424w, https://substackcdn.com/image/fetch/$s_!Q3B_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa9d6583-84b0-4d87-9cae-0be1b1416291_299x172.png 848w, https://substackcdn.com/image/fetch/$s_!Q3B_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa9d6583-84b0-4d87-9cae-0be1b1416291_299x172.png 1272w, https://substackcdn.com/image/fetch/$s_!Q3B_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa9d6583-84b0-4d87-9cae-0be1b1416291_299x172.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Q3B_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa9d6583-84b0-4d87-9cae-0be1b1416291_299x172.png" width="1024" height="589" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aa9d6583-84b0-4d87-9cae-0be1b1416291_299x172.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:589,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!Q3B_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa9d6583-84b0-4d87-9cae-0be1b1416291_299x172.png 424w, https://substackcdn.com/image/fetch/$s_!Q3B_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa9d6583-84b0-4d87-9cae-0be1b1416291_299x172.png 848w, https://substackcdn.com/image/fetch/$s_!Q3B_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa9d6583-84b0-4d87-9cae-0be1b1416291_299x172.png 1272w, https://substackcdn.com/image/fetch/$s_!Q3B_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa9d6583-84b0-4d87-9cae-0be1b1416291_299x172.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">New report created</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wB3X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9699f086-50cd-418c-9174-fefe6e1ad860_299x173.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wB3X!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9699f086-50cd-418c-9174-fefe6e1ad860_299x173.png 424w, https://substackcdn.com/image/fetch/$s_!wB3X!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9699f086-50cd-418c-9174-fefe6e1ad860_299x173.png 848w, https://substackcdn.com/image/fetch/$s_!wB3X!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9699f086-50cd-418c-9174-fefe6e1ad860_299x173.png 1272w, https://substackcdn.com/image/fetch/$s_!wB3X!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9699f086-50cd-418c-9174-fefe6e1ad860_299x173.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wB3X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9699f086-50cd-418c-9174-fefe6e1ad860_299x173.png" width="1024" height="591" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9699f086-50cd-418c-9174-fefe6e1ad860_299x173.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:591,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!wB3X!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9699f086-50cd-418c-9174-fefe6e1ad860_299x173.png 424w, https://substackcdn.com/image/fetch/$s_!wB3X!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9699f086-50cd-418c-9174-fefe6e1ad860_299x173.png 848w, https://substackcdn.com/image/fetch/$s_!wB3X!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9699f086-50cd-418c-9174-fefe6e1ad860_299x173.png 1272w, https://substackcdn.com/image/fetch/$s_!wB3X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9699f086-50cd-418c-9174-fefe6e1ad860_299x173.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Add report finding</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6A-v!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbec8635b-607d-46b1-a77d-72fbd0468ddb_298x172.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6A-v!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbec8635b-607d-46b1-a77d-72fbd0468ddb_298x172.png 424w, https://substackcdn.com/image/fetch/$s_!6A-v!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbec8635b-607d-46b1-a77d-72fbd0468ddb_298x172.png 848w, https://substackcdn.com/image/fetch/$s_!6A-v!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbec8635b-607d-46b1-a77d-72fbd0468ddb_298x172.png 1272w, https://substackcdn.com/image/fetch/$s_!6A-v!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbec8635b-607d-46b1-a77d-72fbd0468ddb_298x172.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6A-v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbec8635b-607d-46b1-a77d-72fbd0468ddb_298x172.png" width="1024" height="590" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bec8635b-607d-46b1-a77d-72fbd0468ddb_298x172.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:590,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!6A-v!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbec8635b-607d-46b1-a77d-72fbd0468ddb_298x172.png 424w, https://substackcdn.com/image/fetch/$s_!6A-v!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbec8635b-607d-46b1-a77d-72fbd0468ddb_298x172.png 848w, https://substackcdn.com/image/fetch/$s_!6A-v!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbec8635b-607d-46b1-a77d-72fbd0468ddb_298x172.png 1272w, https://substackcdn.com/image/fetch/$s_!6A-v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbec8635b-607d-46b1-a77d-72fbd0468ddb_298x172.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Add recommended action</figcaption></figure></div><p>The web app is backed by a Python FastAPI service exposing these endpoints:</p><pre><code>GET     /api/v1/reports                    &#8594; List Reports
POST    /api/v1/reports                    &#8594; Create New Report
GET     /api/v1/reports/{report_id}        &#8594; Get Report
PUT     /api/v1/reports/{report_id}        &#8594; Update Existing Report
DELETE  /api/v1/reports/{report_id}        &#8594; Delete Existing Report

GET     /api/v1/reports/{report_id}/findings       &#8594; List Findings
POST    /api/v1/reports/{report_id}/findings       &#8594; Create Finding
PUT     /api/v1/findings/{finding_id}              &#8594; Update Finding
DELETE  /api/v1/findings/{finding_id}              &#8594; Delete Finding

GET     /api/v1/findings/{finding_id}/actions      &#8594; List Actions
POST    /api/v1/findings/{finding_id}/actions      &#8594; Create Action
PUT     /api/v1/actions/{action_id}                &#8594; Update Action

GET     /api/v1/reports/{report_id}/comments       &#8594; List Comments
POST    /api/v1/reports/{report_id}/comments       &#8594; Create Comment
</code></pre><p>This allows me to build a structured report.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DVGv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16fc5062-b7b9-4be4-9a9b-ea5e448b1da2_299x145.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DVGv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16fc5062-b7b9-4be4-9a9b-ea5e448b1da2_299x145.png 424w, https://substackcdn.com/image/fetch/$s_!DVGv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16fc5062-b7b9-4be4-9a9b-ea5e448b1da2_299x145.png 848w, https://substackcdn.com/image/fetch/$s_!DVGv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16fc5062-b7b9-4be4-9a9b-ea5e448b1da2_299x145.png 1272w, https://substackcdn.com/image/fetch/$s_!DVGv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16fc5062-b7b9-4be4-9a9b-ea5e448b1da2_299x145.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DVGv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16fc5062-b7b9-4be4-9a9b-ea5e448b1da2_299x145.png" width="1000" height="485" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/16fc5062-b7b9-4be4-9a9b-ea5e448b1da2_299x145.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:485,&quot;width&quot;:1000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!DVGv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16fc5062-b7b9-4be4-9a9b-ea5e448b1da2_299x145.png 424w, https://substackcdn.com/image/fetch/$s_!DVGv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16fc5062-b7b9-4be4-9a9b-ea5e448b1da2_299x145.png 848w, https://substackcdn.com/image/fetch/$s_!DVGv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16fc5062-b7b9-4be4-9a9b-ea5e448b1da2_299x145.png 1272w, https://substackcdn.com/image/fetch/$s_!DVGv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16fc5062-b7b9-4be4-9a9b-ea5e448b1da2_299x145.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>So what if I want the LLM itself to act as the <em>reporter</em>?<br>I can create an <strong>agent</strong> and give it the same API access as the human&#8212;just through tools.</p><div><hr></div><h2>Building the Agent</h2><p>Let&#8217;s start with a minimal setup using the <code>FastAgent</code> library.</p><pre><code>import asyncio
from mcp_agent.core.fastagent import FastAgent

# Create the application
reporter = FastAgent("Report Generator")

# Define the agent
@reporter.agent(instruction="""You are an expert at database performance analysis and optimization""")
async def main():
    # use the --model command line switch or agent arguments to change model
    async with reporter.run() as agent:
        await agent.interactive()

if __name__ == "__main__":
    asyncio.run(main())
</code></pre><p>At this stage, it&#8217;s in <code>interactive()</code> mode so I can test before weaving it into the full app.</p><p>I also need two files:</p><ul><li><p><code>fastagent.config.yaml</code> &#8211; defines default model, logging, and MCP servers</p></li><li><p><code>fastagent.secrets.yaml</code> &#8211; securely stores model API keys and environment variables</p></li></ul><h3>Example Configuration</h3><pre><code># fastagent.config.yaml
default_model: sonnet35

logger:
  level: "debug"
  type: "console"
  progress_display: true
  show_chat: true
  show_tools: true
  truncate_tools: true
</code></pre><pre><code># fastagent.secrets.yaml
openai:
  api_key: &lt;your-openai-key&gt;
anthropic:
  api_key: &lt;your-anthropic-key&gt;
</code></pre><p>If I start it in interactive mode, I get a chat interface like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!N0p2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc70d3ec-ff89-4b23-bb3d-84bc06370d36_298x117.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!N0p2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc70d3ec-ff89-4b23-bb3d-84bc06370d36_298x117.png 424w, https://substackcdn.com/image/fetch/$s_!N0p2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc70d3ec-ff89-4b23-bb3d-84bc06370d36_298x117.png 848w, https://substackcdn.com/image/fetch/$s_!N0p2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc70d3ec-ff89-4b23-bb3d-84bc06370d36_298x117.png 1272w, https://substackcdn.com/image/fetch/$s_!N0p2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc70d3ec-ff89-4b23-bb3d-84bc06370d36_298x117.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!N0p2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc70d3ec-ff89-4b23-bb3d-84bc06370d36_298x117.png" width="1000" height="392" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fc70d3ec-ff89-4b23-bb3d-84bc06370d36_298x117.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:392,&quot;width&quot;:1000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!N0p2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc70d3ec-ff89-4b23-bb3d-84bc06370d36_298x117.png 424w, https://substackcdn.com/image/fetch/$s_!N0p2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc70d3ec-ff89-4b23-bb3d-84bc06370d36_298x117.png 848w, https://substackcdn.com/image/fetch/$s_!N0p2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc70d3ec-ff89-4b23-bb3d-84bc06370d36_298x117.png 1272w, https://substackcdn.com/image/fetch/$s_!N0p2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc70d3ec-ff89-4b23-bb3d-84bc06370d36_298x117.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Agent prompt input</figcaption></figure></div><p>Feeding it the same prompt as before produces a similar structured report&#8212;almost.<br>Previously, the structure was enforced by a tool call:</p><pre><code>const tools = [
  {
    type: "function",
    function: {
      name: "generateRecommendations",
      description: "Generates structured recommendations for a CockroachDB cluster",
      strict: true,
      parameters: { /* JSON schema */ }
    }
  }
];
</code></pre><p>Stuffing the JSON schema into the agent prompt is brittle because some models still prefix their response (&#8220;Here is your JSON response:&#8221;) and break the UI contract.</p><p>So now we&#8217;ll empower the agent with real tools using <strong>Model Context Protocol (MCP)</strong>.</p><div><hr></div><h2>Empowering the Agent with MCP</h2><p><strong>MCP</strong> (Model Context Protocol) is an open-source standard that connects an LLM to internal or external systems.<br>In this case, I want the agent to access the <em>Reporter Service API</em> to create reports the same way a human would.</p><p>If APIs connect UIs to services, think of MCP as connecting agents to tools.<br>An MCP server sits between the agent and those systems, exposing structured functions it can call.</p><p>Let&#8217;s define one using <code>FastMCP</code>:</p><pre><code>from fastmcp import FastMCP

mcp = FastMCP("Example Server")

@mcp.tool
def temp_to_celsius(f: float) -&gt; float:
    """Convert a temperature from Fahrenheit to Celsius"""
    return round((f - 32) * 5.0 / 9.0, 2)

if __name__ == "__main__":
    mcp.run()
</code></pre><p>Each <code>@mcp.tool</code> makes a function callable by an agent.<br>For our app, instead of writing every endpoint by hand, <code>FastMCP 2.0</code> introduces a shortcut that can wrap a full FastAPI app into an MCP server:</p><pre><code>from main import app
from fastmcp import FastMCP

# Convert to MCP server
mcp = FastMCP.from_fastapi(app=app)

if __name__ == "__main__":
    mcp.run()
</code></pre><p>Now every endpoint in the Reporter API becomes a callable tool.</p><p>Next, register the server in the FastAgent configuration:</p><pre><code># fastagent.config.yaml
mcp:
  servers:
    reporter:
      command: "python"
      args: ["reporter_mcp.py"]
</code></pre><p>And add necessary environment variables:</p><pre><code># fastagent.secrets.yaml
mcp:
  servers:
    reporter:
      env:
        DATABASE_URL: "cockroachdb+psycopg://root@insecure-database:26257/tuning_reports?sslmode=disable"
</code></pre><p>Finally, wire it into the agent definition:</p><pre><code>@reporter.agent(
  instruction="You are an expert at database performance analysis and optimization.",
  servers=["reporter"]
)
</code></pre><p>Now, when I prompt:</p><blockquote><p>&#8220;Use the reporting tools to create a fictional crdb tuning report.&#8221;</p></blockquote><p>the agent does exactly that&#8212;creating structured records via the MCP tools.</p><div class="captioned-image-container"><figure><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!X4G-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdccb56c-7ae1-4ce4-8d11-f2a0b6231172_299x189.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!X4G-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdccb56c-7ae1-4ce4-8d11-f2a0b6231172_299x189.png 424w, https://substackcdn.com/image/fetch/$s_!X4G-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdccb56c-7ae1-4ce4-8d11-f2a0b6231172_299x189.png 848w, https://substackcdn.com/image/fetch/$s_!X4G-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdccb56c-7ae1-4ce4-8d11-f2a0b6231172_299x189.png 1272w, https://substackcdn.com/image/fetch/$s_!X4G-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdccb56c-7ae1-4ce4-8d11-f2a0b6231172_299x189.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!X4G-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdccb56c-7ae1-4ce4-8d11-f2a0b6231172_299x189.png" width="1024" height="647" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bdccb56c-7ae1-4ce4-8d11-f2a0b6231172_299x189.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:647,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!X4G-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdccb56c-7ae1-4ce4-8d11-f2a0b6231172_299x189.png 424w, https://substackcdn.com/image/fetch/$s_!X4G-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdccb56c-7ae1-4ce4-8d11-f2a0b6231172_299x189.png 848w, https://substackcdn.com/image/fetch/$s_!X4G-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdccb56c-7ae1-4ce4-8d11-f2a0b6231172_299x189.png 1272w, https://substackcdn.com/image/fetch/$s_!X4G-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdccb56c-7ae1-4ce4-8d11-f2a0b6231172_299x189.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">AI-generated report</figcaption></figure></div></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fOzf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae27dec-02ba-4ed9-ace1-e49654fd1b39_300x126.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fOzf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae27dec-02ba-4ed9-ace1-e49654fd1b39_300x126.png 424w, https://substackcdn.com/image/fetch/$s_!fOzf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae27dec-02ba-4ed9-ace1-e49654fd1b39_300x126.png 848w, https://substackcdn.com/image/fetch/$s_!fOzf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae27dec-02ba-4ed9-ace1-e49654fd1b39_300x126.png 1272w, https://substackcdn.com/image/fetch/$s_!fOzf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae27dec-02ba-4ed9-ace1-e49654fd1b39_300x126.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fOzf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae27dec-02ba-4ed9-ace1-e49654fd1b39_300x126.png" width="1024" height="430" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3ae27dec-02ba-4ed9-ace1-e49654fd1b39_300x126.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:430,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!fOzf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae27dec-02ba-4ed9-ace1-e49654fd1b39_300x126.png 424w, https://substackcdn.com/image/fetch/$s_!fOzf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae27dec-02ba-4ed9-ace1-e49654fd1b39_300x126.png 848w, https://substackcdn.com/image/fetch/$s_!fOzf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae27dec-02ba-4ed9-ace1-e49654fd1b39_300x126.png 1272w, https://substackcdn.com/image/fetch/$s_!fOzf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae27dec-02ba-4ed9-ace1-e49654fd1b39_300x126.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Reports dashboard</figcaption></figure></div><p>It even added comments automatically! That&#8217;s the power of giving an agent access to well-documented tools.</p><div><hr></div><h2>Wiring It All Together</h2><p>There&#8217;s one last piece: <strong>context</strong>. The agent still needs cluster metrics. We can expose <code>CockroachDB Cluster API</code> endpoints through the same <code>FastAPI app</code> and include credentials in the secrets config.</p><p>Then we create an API endpoint that generates reports using the agent.</p><h3>The Agent Service (snippet)</h3><pre><code> async def generate_report_with_agent(database: str, app: str, custom_prompt: Optional[str] = None) -&gt; str:
    reporter = FastAgent("Report Generator")
    prompt = custom_prompt or f"""
Please analyze the CockroachDB cluster performance for the '{database}' database and '{app}' application...
"""
    @reporter.agent(
        instruction="You are an expert at database performance analysis and optimization.",
        servers=["reporter"]
    )
    async def generate():
        async with reporter.run() as agent:
            return await agent.send(prompt)
    return await generate()
</code></pre><h3>The API Endpoint</h3><pre><code>@app.post("/generate-report", response_model=GenerateReportResponse)
async def generate_report(request: GenerateReportRequest):
    try:
        report = await generate_report_with_agent(
            database=request.database,
            app=request.app,
            custom_prompt=request.prompt
        )
        return GenerateReportResponse(success=True, report=report)
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Failed to generate report: {e}")
</code></pre><p>This lives in a separate <code>agent_main.py</code>, isolated from the core Reporter APIs.</p><p>To test, I start a <code>CRDB</code> cluster and load it with test data for my &#8220;bookly&#8221; database and app:</p><pre><code>curl -X POST "http://localhost:8002/generate-report"   -H "Content-Type: application/json"   -d '{"database": "bookly", "app": "bookly"}'
</code></pre><p>Refreshing the app shows the new report instantly&#8212;no UI changes required!</p><div class="captioned-image-container"><figure><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!__Pf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66495621-2225-4d16-8ca9-b31592e20d78_300x122.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!__Pf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66495621-2225-4d16-8ca9-b31592e20d78_300x122.png 424w, https://substackcdn.com/image/fetch/$s_!__Pf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66495621-2225-4d16-8ca9-b31592e20d78_300x122.png 848w, https://substackcdn.com/image/fetch/$s_!__Pf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66495621-2225-4d16-8ca9-b31592e20d78_300x122.png 1272w, https://substackcdn.com/image/fetch/$s_!__Pf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66495621-2225-4d16-8ca9-b31592e20d78_300x122.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!__Pf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66495621-2225-4d16-8ca9-b31592e20d78_300x122.png" width="1024" height="416" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/66495621-2225-4d16-8ca9-b31592e20d78_300x122.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:416,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!__Pf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66495621-2225-4d16-8ca9-b31592e20d78_300x122.png 424w, https://substackcdn.com/image/fetch/$s_!__Pf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66495621-2225-4d16-8ca9-b31592e20d78_300x122.png 848w, https://substackcdn.com/image/fetch/$s_!__Pf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66495621-2225-4d16-8ca9-b31592e20d78_300x122.png 1272w, https://substackcdn.com/image/fetch/$s_!__Pf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66495621-2225-4d16-8ca9-b31592e20d78_300x122.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">New AI-generated report added!</figcaption></figure></div></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Rv7z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd87728ad-e747-42f8-9d3d-9f210520ee85_299x189.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Rv7z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd87728ad-e747-42f8-9d3d-9f210520ee85_299x189.png 424w, https://substackcdn.com/image/fetch/$s_!Rv7z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd87728ad-e747-42f8-9d3d-9f210520ee85_299x189.png 848w, https://substackcdn.com/image/fetch/$s_!Rv7z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd87728ad-e747-42f8-9d3d-9f210520ee85_299x189.png 1272w, https://substackcdn.com/image/fetch/$s_!Rv7z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd87728ad-e747-42f8-9d3d-9f210520ee85_299x189.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Rv7z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd87728ad-e747-42f8-9d3d-9f210520ee85_299x189.png" width="1024" height="647" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d87728ad-e747-42f8-9d3d-9f210520ee85_299x189.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:647,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!Rv7z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd87728ad-e747-42f8-9d3d-9f210520ee85_299x189.png 424w, https://substackcdn.com/image/fetch/$s_!Rv7z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd87728ad-e747-42f8-9d3d-9f210520ee85_299x189.png 848w, https://substackcdn.com/image/fetch/$s_!Rv7z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd87728ad-e747-42f8-9d3d-9f210520ee85_299x189.png 1272w, https://substackcdn.com/image/fetch/$s_!Rv7z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd87728ad-e747-42f8-9d3d-9f210520ee85_299x189.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">AI-generated report details</figcaption></figure></div><p>A UI button could easily call this same endpoint to create either a standard or a custom-prompted report.</p><div><hr></div><h2>The Pattern Holds: Direct Value Coupling</h2><p>What I love most is that the original pattern of <strong>direct value coupling</strong> still holds. Every model improvement or new MCP tool instantly enriches the agent&#8217;s output without code rewrites.</p><p>In the beginning, I had to stuff all context into a single prompt. Now, the agent fetches its own data, calls structured APIs, and builds a shareable, actionable report. The reporter didn&#8217;t just get smarter, it gained <strong>agency</strong>. And the human in the loop kept theirs: reviewing, editing, and managing the AI-generated report assets with intention.</p><p>What emerged was a structured architecture that supported both the machine acting with autonomy, and the human maintaining authorship. This is our triad working together again: <strong>application code orchestrates structure, the AI agent performs the analysis, and the human refines the outcome.</strong> Each doing their best part, in concert.</p><p>Although this is the last part in the original <em>From Prompts to Programs to Agents</em> journey, I&#8217;ll continue exploring what agentic architecture really means &#8212; how agents, tools, and humans can work together as an adaptive system.</p><p>I&#8217;m all about building AI that works <strong>with</strong> humans, not just <strong>for</strong> humans or <strong>in place of</strong> them. I&#8217;ll share more code and technical reflections in future posts.</p>]]></content:encoded></item><item><title><![CDATA[Humans in the Loop: The Overlooked Chapter (Part 3)]]></title><description><![CDATA[From Prompts to Programs to Agents &#8212; Part Three]]></description><link>https://www.thatskiki.ai/p/humans-in-the-loop-the-overlooked-chapter</link><guid isPermaLink="false">https://www.thatskiki.ai/p/humans-in-the-loop-the-overlooked-chapter</guid><dc:creator><![CDATA[Kiki C]]></dc:creator><pubDate>Sat, 06 Sep 2025 16:54:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!iSlL!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98b6ca8f-4f8a-4e07-8f53-de7264be4f51_401x401.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>From Prompts to Programs to Agents &#8212; Part Three</em></p><p>Before I dive into the agentic phase with MCPs and tools, I need to pause. I was moving too fast. There&#8217;s a big part of my journey that I haven&#8217;t shared yet, and it&#8217;s just as important as the code: the role of humans in the loop.</p><h2>Why this matters</h2><p>Early on, I identified the human in the loop as a key pattern for AI workflows. What I want to explore in this post is how one <strong>human in the loop</strong> experience revealed how AI could help bridge people with different specialties. It smoothed friction across cross-functional teams and reduced capacity pressure on teammates.</p><p>Instead of leaning entirely on a technical expert or slogging through scattered Google searches, a non-expert could now get enough grounding to push forward faster and with less burden on others.</p><h2>Lamont and the Tombstones</h2><p>Back in the early GenAI days, I worked with Lamont, a creative video producer and editor. Like me, he was bullish on AI and a big dreamer. And like any great dreamer, he knew how to spot opportunity.</p><p>His first AI project came before AI video tools even existed. He combined his illustration, animation, and editing skills with AI&#8217;s ability to help him grasp technical concepts. The idea was brilliant: a Halloween-themed video about <strong>tombstones</strong> &#8212; not just the spooky kind, but the technical kind. In databases, tombstones mark deleted rows. He turned that into a horror short.</p><p>Lamont had the creative vision, the storytelling skill, and the production chops. But he wasn&#8217;t a database expert. He used AI not to tell the story for him &#8212; he already had that gift &#8212; but to understand the technical side well enough to weave it into the script. Then he iterated on details with AI before pulling me in as the technical reviewer.</p><h2>Before AI vs. After AI</h2><p>Before AI, Lamont would have pulled me in at the very beginning: research, metaphors, breaking things down simply. With AI, he didn&#8217;t need me there. He could use ChatGPT &#8212; which he nicknamed &#8220;Chatty&#8221; &#8212; to clarify concepts, explore metaphors, and test his understanding. He could draft a script, refine it, and only then pull me in to check technical accuracy.</p><p>The workflow shifted:</p><ul><li><p><strong>Before AI:</strong> Human (creative) &#8594; Human (technical explainer) &#8594; Draft &#8594; Human (technical review)</p></li><li><p><strong>With AI:</strong> Human (creative) + <strong>AI (technical explainer)</strong> &#8594; Draft &#8594; Human (technical review).</p></li></ul><p>Our conversations changed too. Instead of going back and forth on every technical detail just so he could learn, I might only need to explain why AI needed to be steered differently or clarify one subtle point. Meanwhile, he could dream up content ideas a mile a minute and work through them with his indefatigable AI helper.</p><h2>Why this was an aha moment</h2><p>It clicked for me that GenAI didn&#8217;t just change individual workflows. It changed <strong>team workflows.</strong> It lowered friction in cross-functional collaboration. Lamont didn&#8217;t have to worry about pulling me away from other work or me losing time to context switching. He could self-serve on the technical scaffolding and save me for the expert check.</p><p>That&#8217;s revolutionary. We often think of AI as a replacement for rote tasks. But in this case, <em>AI expanded Lamont&#8217;s creative autonomy while deepening the collaboration between us</em>. He could dream bigger because he had a tireless partner to accelerate his research. And I could step in more surgically where my expertise actually mattered.</p><h2>Humans, AI, and roles</h2><p>Looking back, it&#8217;s clear the instinct to know where to place AI and where to place people is just as important as writing the code. It&#8217;s about roles:</p><ul><li><p><strong>Application code</strong> &#8594; structure.</p></li><li><p><strong>AI</strong> &#8594; assistant, explainer, technical researcher.</p></li><li><p><strong>Human experts</strong> &#8594; reviewers, editors, creators.</p></li></ul><p>Lamont embodied that instinct. Even where he was the creative expert, he still invited feedback. He never treated AI or himself as the final authority. That kind of collaboration mindset is what makes cross-functional AI workflows powerful.</p><h2>A future glimpse</h2><p>The funny part is, Lamont was early to so much of this. He was experimenting with content workflows, avatars, and synthetic voices long before ElevenLabs made them mainstream. He knew that if you design workflows early, they&#8217;ll only get better with time as the tools mature.</p><p>Eventually, he learned creative prompting and AI tools so well, he was able to build out entire <strong>High Quality</strong> (slop-free) content pipelines in a fraction of time it would typically take. If you are interested in seeing more of Lamont&#8217;s work, check out <a href="http://www.belton.ai">www.belton.ai</a></p><p>It wasn&#8217;t about replacing people. It was about putting creativity into hyperdrive. And participating in his process helped me see how AI could strategically smooth the friction between teams and disciplines. That was an aha moment I still carry.</p><h2>The pivot to agents</h2><p>This reflection sets up the next phase. Once I saw how AI changed not just <em>my</em> workflow, but <em>our</em> workflow, I started to imagine architectures that formalized this: humans in the loop, AI assistants orchestrating context, and applications providing structure. That&#8217;s what Model Context Protocol and agents made possible.</p><p>So before we go back to code, remember: the technical evolution is only half the story. The human patterns matter just as much. And this is the part of the story that made me ready to embrace the agentic phase.</p>]]></content:encoded></item><item><title><![CDATA[My First AI‑Infused Application: The One‑Line Upgrade (Part 2)]]></title><description><![CDATA[From Prompts to Programs to Agents (Part Two)]]></description><link>https://www.thatskiki.ai/p/my-first-ai-application</link><guid isPermaLink="false">https://www.thatskiki.ai/p/my-first-ai-application</guid><dc:creator><![CDATA[Kiki C]]></dc:creator><pubDate>Sun, 03 Aug 2025 17:31:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!iSlL!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98b6ca8f-4f8a-4e07-8f53-de7264be4f51_401x401.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>From Prompts to Programs to Agents (Part Two)</h3><p>In the <a href="https://kikia.io/2025/07/05/from-prompts-to-programs-to-agents-part-1/">last post</a>, I talked about learning to extract meaningful value from ChatGPT even when it was limited by hallucinations, short memory, context limits, and all. The point wasn&#8217;t perfection, it was usefulness. That mindset carried directly into my first programmatic app. It didn&#8217;t need to be flawless to prove something powerful: that AI could integrate into a workflow and improve the product in ways I&#8217;d never seen before.</p><div><hr></div><h2>From Conversational to Programmatic</h2><p>This post begins the programmatic phase. When the ChatGPT APIs arrived I was excited to try it out and coded my first AI&#8209;infused app. It was a simple proof of concept, but it reframed how I think about AI&#8217;s role in traditional stacks.</p><p>It was during this phase that I moved from chatting in the web UI to coding in my IDE. Using GenAI programmatically opened a new world where I could repeatably produce useful content as part of a workflow. My first programmatic workflow implementation was simple, but what I learned from that proof of concept was more enlightening than I expected.</p><p>I built a tiny app that generated a CockroachDB tuning report. The surprising part was not that it worked. It was that the report kept getting better every time the underlying model leveled up&#8212;with me changing almost nothing. Swap the model name in one line, redeploy, and the &#8220;product&#8221; improved. The &#8220;reporter&#8221; got smarter, so the report got better.</p><p>This pointed me to a new way of viewing the relationship between AI and traditional stacks. You can find the precise seam in your workflow where an LLM fashions some deliverable, then let model progress flow straight into user value.</p><div><hr></div><h2>The App, in 60 Seconds</h2><p><strong>Goal:</strong> given cluster metadata and a slice of workload evidence, produce specific, actionable tuning recommendations with example SQL and expected impact.<br><strong>Shape:</strong> tiny HTTP service with one endpoint. Front&#8209;end optional. Returns JSON or HTML.<br><strong>LLM role:</strong> expert &#8220;reporter.&#8221; It must call a tool that enforces a strict JSON schema for recommendations. No rambling essays.</p><h3>High&#8209;Level Flow</h3><pre><code>[Client] &#8594; GET /report/recommendations
            &#8595;
        Express Router
            &#8595;
   gatherClusterData()      &#8594; cluster JSON
            &#8595;
   generateReport()         &#8594; OpenAI chat.completions with tool schema
            &#8595;
  parsed { recommendations } &#8594; JSON/HTML report
</code></pre><h3>Minimal Stack</h3><ul><li><p>Node 18+, ESM modules</p></li><li><p>Express for routing</p></li><li><p>Axios for optional REST calls (e.g., CRDB API)</p></li><li><p>OpenAI SDK v4 (ESM)</p></li><li><p>dotenv for config</p></li></ul><div><hr></div><h2>Managing Context (Early Days)</h2><p>In this first iteration, all context was stuffed directly into a single prompt. Everything the LLM needed&#8212;cluster topology, schema, workload samples&#8212;had to be included inline. There was no memory, no selective fetching, no orchestration. Just one big prompt, every time.</p><p>It worked, but it was rigid. If I wanted a new signal (like CPU usage), I had to update <code>gatherClusterData</code> and stuff more JSON into the prompt. Context stuffing was necessary&#8212;without it, the model would only give generic advice. With it, I could get precise, cluster&#8209;specific insights.</p><div><hr></div><h2>Code Walk&#8209;Through (Trimmed)</h2><h3><code>app.js</code> &#8212; wire up the router</h3><pre><code>// app.js (ESM)
import express from 'express';
import path from 'path';
import { fileURLToPath } from 'url';
import reportRoutes from './reportRoutes.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.use('/report', reportRoutes);

app.listen(3000, () =&gt; {
  console.log('Server listening on 3000');
});
</code></pre><h3><code>gatherClusterData.js</code> &#8212; inputs the reporter needs</h3><pre><code>import axios from 'axios';
import minimist from 'minimist';

const args = minimist(process.argv.slice(2));
const hostIp = args['host-ip'] || '127.0.0.1';
const COCKROACHDB_API_URL = `http://${hostIp}:8080/api/v2`;
const axiosConfig = { /* auth, headers, timeouts */ };

export async function getClusterTopology() {
  const res = await axios.get(`${COCKROACHDB_API_URL}/nodes/`, axiosConfig);
  return res.data.nodes.map(n =&gt; ({
    node_id: n.node_id,
    locality: n.locality?.tiers?.map(t =&gt; `${t.key}=${t.value}`).join(', ') || 'Unknown'
  }));
}

// also: getDatabaseSchema(db), getCPUUsage(), getSlowStatements()
export async function gatherClusterData(databaseName) {
  try {
    const topology = await getClusterTopology();
    const schema = await getDatabaseSchema(databaseName);
    const cpuUsage = await getCPUUsage();
    const slowStatements = await getSlowStatements();
    return { topology, schema, cpuUsage, slowStatements };
  } catch (e) {
    console.error('Error gathering cluster data:', e);
    return { topology: [], schema: {}, cpuUsage: [], slowStatements: [] };
  }
}
</code></pre><h3><code>openaiClient.js</code> &#8212; make the model call and <strong>force</strong> structured output</h3><pre><code>import OpenAI from 'openai';
import dotenv from 'dotenv';
dotenv.config();

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

const tools = [
  {
    type: 'function',
    function: {
      name: 'generateRecommendations',
      description: 'Structured CockroachDB tuning advice',
      strict: true,
      parameters: {
        type: 'object',
        properties: {
          recommendations: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                section: { type: 'string' },
                details: {
                  type: 'array',
                  items: {
                    type: 'object',
                    properties: {
                      title: { type: 'string' },
                      rationale: { type: 'string' },
                      actions: { type: 'array', items: { type: 'string' } },
                      sql_examples: { type: 'array', items: { type: 'string' } },
                      expected_impact: { type: 'string' }
                    },
                    required: ['title', 'actions']
                  }
                }
              },
              required: ['section', 'details']
            }
          }
        },
        required: ['recommendations']
      }
    }
  }
];

export async function generateReport(clusterInfo) {
  const messages = [
    { role: 'system', content: 'You are an expert in CockroachDB performance.' },
    { role: 'user', content: `Analyze this cluster and produce structured JSON via the tool.\n${JSON.stringify(clusterInfo, null, 2)}` }
  ];

  const completion = await openai.chat.completions.create({
    model: process.env.OPENAI_MODEL || 'o3-mini-2025-01-31',
    messages,
    reasoning_effort: 'high',
    tools,
    tool_choice: { type: 'function', function: { name: 'generateRecommendations' } },
    store: true
  });

  const toolCalls = completion.choices[0].message.tool_calls;
  const args = JSON.parse(toolCalls[0].function.arguments);
  return args; // { recommendations: [...] }
}
</code></pre><h3><code>reportRoutes.js</code> &#8212; one endpoint</h3><pre><code>import express from 'express';
import { gatherClusterData } from './gatherClusterData.js';
import { generateReport } from './openaiClient.js';

const router = express.Router();

router.get('/recommendations', async (req, res) =&gt; {
  try {
    const db = req.query.db || 'defaultdb';
    const clusterInfo = await gatherClusterData(db);
    const result = await generateReport(clusterInfo);
    res.json({ ok: true, ...result });
  } catch (err) {
    console.error(err);
    res.status(500).json({ ok: false, error: err.message });
  }
});

export default router;
</code></pre><div><hr></div><h2>The Knobs I Used</h2><ul><li><p><strong>Determinism when needed:</strong> pinned temperature near 0.</p></li><li><p><strong>Schema drift:</strong> enforced <code>strict: true</code>, fail closed if the tool call broke.</p></li><li><p><strong>Reasoning effort:</strong> experimented with low, medium, and high once reasoning models arrived.</p></li></ul><div><hr></div><h2>The Challenges</h2><ul><li><p>When OpenAI deprecated &#8220;functions&#8221; in favor of &#8220;tools,&#8221; I had to refactor. It was mildly inconvenient, but the idea still worked.</p></li><li><p>When the reasoning models arrived, the call signature. I easily adapted thanks to the OpenAI platform playground.</p></li><li><p>Testing non&#8209;OpenAI models wasn&#8217;t straightforward. I could swap models in one provider (OpenAI), but not providers entirely. Unless I built a new client, I was basically locked in with OpenAI.</p></li></ul><div><hr></div><h2>Why This Felt Different Than &#8220;Faster Chips&#8221;</h2><p>Sometimes your product gets better because hardware or dependencies improve, but that value doesn&#8217;t always flow directly into your product&#8217;s core. Faster chips make things smoother. New frameworks bring new features&#8212;if you write the code to take advantage.</p><p>This experiment was different. It was <strong>direct value coupling</strong> where the deliverable was the model&#8217;s output. When GPT&#8209;4 &#8594; o1 &#8594; o3 improved, the report improved along the same axis: nuance, noise filtering, actionable SQL. All I did was switch the model name. No new plumbing. No feature rewrites. That&#8217;s what made it feel profound.</p><div><hr></div><h2>What felt missing? The human in the Loop</h2><p>In the conversational phase, the human orchestrated everything: gathering context, prompting, writing reports.</p><p>In the programmatic phase, I automated orchestration. The LLM produced structured outputs, but the human was absent from the loop. I only had the machine + LLM.</p><p><strong>The ideal future isn&#8217;t removing humans, but shifting roles:</strong></p><div class="captioned-image-container"><figure><p>RoleFunctionApplication codeorchestrates structureLLMreporterHumanreviewer/editor</p></figure></div><p>The human/traditional app code/LLM triad keeps everyone playing their best part and this journey series is dedicated to telling that story.</p><div><hr></div><h2>Recap of My Journey</h2><ul><li><p><strong>Conversational phase:</strong> ChatGPT as a creative partner and deconstruction tool.</p></li><li><p><strong>Programmatic phase:</strong> this project&#8212;a proof that LLMs could reliably call tools and improve the product directly.</p></li><li><p><strong>Agentic phase:</strong> now, with MCPs, context is managed better. Agents fetch what they need, call tools dynamically, and free me from provider lock&#8209;in (Claude, Gemini, OpenAI, etc.).</p></li></ul><div><hr></div><h2>Takeaway</h2><p>Find the seam where your product&#8217;s &#8220;reporter&#8221; lives, and let the model roadmap do part of the lifting. Although this story centers on a small proof of concept, the principle scales: the LLM doesn&#8217;t need to sit at the center of your app; you just need to find the right place, where improvements flow directly into value.</p><p>This was one phase of my journey. In the next, I&#8217;ll reimagine this app in the <strong>agentic phase</strong>&#8212;with MCP agents granting more autonomy to the LLM while keeping humans in the loop.</p><div><hr></div><p><em>This is part two of a series tracing my AI journey. Part one covered the conversational phase, this post focused on the programmatic phase, and next up I&#8217;ll dive into the agentic phase. However, before I dive into the agentic phase, there&#8217;s another lesson that shaped my thinking just as much as writing my first lines of AI code: the human in the loop.</em></p>]]></content:encoded></item><item><title><![CDATA[From Prompts to Programs to Agents (Part 1)]]></title><description><![CDATA[How Early AI Use Sharpened My Instincts]]></description><link>https://www.thatskiki.ai/p/from-prompts-to-programs-to-agents-part-1</link><guid isPermaLink="false">https://www.thatskiki.ai/p/from-prompts-to-programs-to-agents-part-1</guid><dc:creator><![CDATA[Kiki C]]></dc:creator><pubDate>Sat, 05 Jul 2025 16:59:31 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!iSlL!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98b6ca8f-4f8a-4e07-8f53-de7264be4f51_401x401.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>How Early AI Use Sharpened My Instincts</h3><p>In 2022, ChatGPT didn&#8217;t know the news, forgot conversations, and sometimes hallucinated yet I still made it one of the most useful tools in my workflow. Using it early and often sharpened my instincts for how to collaborate with AI in practice, not in theory.</p><p>I&#8217;ve always loved the bleeding edge of technology. Not for novelty&#8217;s sake, not to sit on a shelf at CES, but because what others might see as futuristic, I want to put to work. My favorite moments in tech are when one architectural approach quietly eclipses another by doing the same job in a more elegant, efficient, beautiful way.</p><p>That&#8217;s why, when ChatGPT burst onto the scene in the fall of 2022, I picked it up and began testing its limits immediately! I even gave it a name: <strong>Gina.</strong></p><h2>When ChatGPT Knew Everything and Nothing</h2><p>In the beginning, Gina didn&#8217;t know much about the world. In fact, she knew nothing past September 2021 &#8212; the training cutoff at the time. If you asked about current events, she would come up empty. But if you wanted to dive into history, philosophy, or technical concepts, she would happily oblige.</p><p>Debating policy without worrying about offense? Gina was there. Clarifying an obscure cuneiform text? She leaned in. Exploring concurrency and memory management across programming languages? She had plenty to say. She could even help debug code problems to an extent. She wasn&#8217;t always accurate, but she was always chatty, fun, and useful.</p><p>Looking back, I realize that period was defined by <strong>deconstruction</strong>. Gina excelled at breaking things down with me: dense academic passages, technical white papers, abstract philosophical ideas, and engineering principles. Her generation fed into my generation, and that loop helped me refine my understanding and rebuild ideas in new ways.</p><p>For example, once I fed her a translation of a Thomas Aquinas passage and asked her to turn it into a children&#8217;s story with forest creatures. Other times, I&#8217;d paste in sections from technical papers and ask her to strip them down to first principles. It was play and work at once. This kind of experimentation sharpens your grasp of both the tool and your own thinking.</p><h2><strong>Learning the Boundaries</strong></h2><p>The more I talked with Gina, the more I discovered her boundaries. As I pushed against boundaries, I learned how to prompt better. Through practiced prompt engineering, I figured out what phrases worked best, when to be open-ended and when to be prescriptive, when to stay conversational and when to ask for structured output.</p><p>One of my earliest takeaways was that whether conversing or creating, context was key.</p><p>I realized that to get better answers, I had to provide better context. At the time, context meant including any assumptions, details, things I tried, or even pasting blocks of text from documents, web pages, or code into the chat. This was how I brought in information from after the training cutoff. It also helped me zoom in on specific problems. Providing raw material allowed Gina to deconstruct it with me, often more effectively.</p><p>Conversations themselves sometimes hit a wall. I noticed Gina would forget things we had already discussed. I&#8217;d ask, &#8220;Don&#8217;t you remember I said&#8230;?&#8221; only to realize that I had bumped into what&#8217;s now called the context window.</p><p>I learned to work around this by summarizing. I started condensing our conversations, replaying the highlights back to Gina, and sometimes even asking her to summarize for me. For the early models, it often helped to summarize and then start a fresh conversation with that recap. This forced me to clarify my own understanding. The limits pushed me to compact ideas and keep the thread tight.</p><p>Another limitation was hallucination. Gina sometimes delivered confident but inaccurate statements. But I never treated her as a final authority. She was a tutor, a coach, a study partner. When I needed definitive answers, I went to primary sources: the original text, the dictionary, the official documentation.</p><p>For me, hallucinations weren&#8217;t dealbreakers because I wasn&#8217;t asking for absolute truth. I was asking for perspective, structure, and possibilities. That distinction mattered.</p><p>If I wanted to know the similarities between concurrency in Java and Rust, Gina might not get every detail right, but she gave me enough scaffolding to refine my own thinking. If I wanted to reimagine Aquinas as a woodland tale, she gave me a story to work with. Thinking, creating, and problem solving all became more fun with my new unpretentious partner.</p><h2><strong>Practicing deconstruction developed instinct</strong></h2><p>As I said earlier, those early days with ChatGPT were all about deconstruction. Breaking down concepts, reframing ideas, and reconstructing them into new forms. I worked through policy debates, software engineering principles, theological concepts, and more. The point wasn&#8217;t the final answer, it was the process.</p><p>What others dismissed as novelty, I was putting to serious work.</p><p>And that work left an imprint. There&#8217;s a difference between knowing about a technology and knowing it from experience. Reading about large language models gave me intellectual understanding, but using them daily rewired my instincts.</p><p>I think working with a technology in its infancy imprints something on how you approach it as it grows. Because I had used ChatGPT early and often, I developed a kind of muscle memory around it. I knew its rhythms, its quirks, the way it handled context, the way it faltered. That hands-on experience gave me a foundation I couldn&#8217;t have gotten from articles or demos alone.</p><p>It meant that as the models evolved, I evolved too. My proficiency grew not because I read more, but because I practiced more.</p><p>That&#8217;s why I think of those early months not just as the period of deconstruction, but as <strong>the time when my instincts for working with AI were formed.</strong></p><h2><strong>From Prompts to Programs</strong></h2><p>That was the foundation: using Gina as a conversational partner to help me dismantle and rebuild ideas. Technology will always have shortcomings. Gen AI is no different. Models have context limits, they hallucinate, they miss the headlines of the day. But the measure of a tool isn&#8217;t whether it&#8217;s flawless. It&#8217;s whether you can put it to work today.</p><p>I didn&#8217;t ask Gina to be perfect. I asked her to be useful. And when she was, I extracted surprising amounts of value for a fraction of what that kind of intellectual companionship would have cost in any other form.</p><p>That was the period of deconstruction. Next came something even more exciting: when ChatGPT stopped being just a conversation partner and became a programmable collaborator.</p><p>APIs, programmatic workflows, agents all quickly followed.</p>]]></content:encoded></item></channel></rss>