<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Alvaro Inckot</title>
    <description>Building the cloud from sand—one layer at a time.
</description>
    <link>https://www.alvaroinckot.com/</link>
    <atom:link href="https://www.alvaroinckot.com/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Mon, 01 Jun 2026 10:28:04 +0000</pubDate>
    <lastBuildDate>Mon, 01 Jun 2026 10:28:04 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Agents Need Their Own Accounts</title>
        <description>&lt;p&gt;&lt;em&gt;Why autonomous actors need their own identity model&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The first time you give an agent real access to a system, you discover that most identity architectures were built around an assumption that no longer holds.&lt;/p&gt;

&lt;p&gt;Every platform already knows how to deal with people and services. It has a login flow for users, complete with redirects, consent screens, MFA challenges, and sessions. It has a machine identity model for workloads, complete with credentials, client authentication, and narrowly scoped access. For years, those two models have been enough because almost every actor fit comfortably into one of them.&lt;/p&gt;

&lt;p&gt;Agents do not.&lt;/p&gt;

&lt;p&gt;An agent often operates using authority that originates from a person, yet it performs work without that person being present. It may execute minutes, hours, or days after the original authorization was granted. It may move across systems that the user never directly touches. It may combine capabilities in ways that nobody explicitly designed ahead of time.&lt;/p&gt;

&lt;p&gt;The moment an agent begins participating in real workflows, the distinction between human and machine identity starts to feel less complete than it once did. The problem is not that agents are somehow half human and half service. The problem is that they separate responsibilities that traditional identity systems quietly combined.&lt;/p&gt;

&lt;p&gt;The person authorizing the work is no longer the entity performing it, yet the relationship between those two identities remains essential. Identity systems can no longer treat authorization and execution as a single event because they may be separated by time, context, and hundreds of individual actions.&lt;/p&gt;

&lt;p&gt;Most of what we now call agent identity is an attempt to reconcile that separation.&lt;/p&gt;

&lt;h2 id=&quot;why-human-accounts-break-down&quot;&gt;Why Human Accounts Break Down&lt;/h2&gt;

&lt;p&gt;Human accounts assume participation.&lt;/p&gt;

&lt;p&gt;The same person who authorizes access is the same person who exercises it, which allows identity systems to center everything around explicit moments of interaction. A user logs in, reviews a consent screen, approves a set of permissions, establishes a session, and proceeds. The authority and the action belong to the same actor, so the chain connecting them rarely needs to be expressed directly.&lt;/p&gt;

&lt;p&gt;That model begins to strain when the actor stops being the person who granted the authority.&lt;/p&gt;

&lt;p&gt;An agent cannot pause every few minutes to ask someone to click through another consent screen. It cannot depend on an active browser session. It cannot assume that the user will be present when a task runs. The entire premise of agentic systems is that work continues after the user has stepped away.&lt;/p&gt;

&lt;p&gt;Many early implementations try to avoid confronting this reality by forcing agents through the existing human model. Browser sessions are preserved and replayed. User tokens are shared across multiple executions. Consent flows designed for interactive use are scripted and automated.&lt;/p&gt;

&lt;p&gt;These approaches usually work long enough to create confidence before they create confusion.&lt;/p&gt;

&lt;p&gt;Once multiple agents begin operating under the same borrowed credentials, answering basic questions becomes surprisingly difficult. Which agent performed this action? Which user authorized it? Was the action executed under delegated authority or under independently granted permissions? The system may still have logs, but the identity model can no longer clearly explain what happened.&lt;/p&gt;

&lt;p&gt;The problem is not that the authentication succeeded. The problem is that accountability has become blurred.&lt;/p&gt;

&lt;h2 id=&quot;why-agents-are-not-service-accounts&quot;&gt;Why Agents Are Not Service Accounts&lt;/h2&gt;

&lt;p&gt;The natural reaction is to treat agents as another form of non-human identity.&lt;/p&gt;

&lt;p&gt;That classification is technically correct, but it conceals a fundamental difference.&lt;/p&gt;

&lt;p&gt;A service account acts entirely under its own authority. An agent does not.&lt;/p&gt;

&lt;p&gt;A service account receives a credential and operates within a predefined boundary. Its permissions are known ahead of time. Its purpose is usually narrow. It performs work as itself and answers only for itself.&lt;/p&gt;

&lt;p&gt;Agents move between contexts.&lt;/p&gt;

&lt;p&gt;Reading a user’s calendar may require delegated permissions derived from that user’s consent. Creating execution records, maintaining state, interacting with infrastructure, or invoking internal services may rely on permissions owned directly by the agent itself. During a single workflow, an agent may alternate repeatedly between borrowed authority and independent authority.&lt;/p&gt;

&lt;p&gt;The same identity continuously changes footing depending on the action being performed.&lt;/p&gt;

&lt;p&gt;That distinction changes the role identity plays within the system.&lt;/p&gt;

&lt;p&gt;A service account is often little more than a credential attached to a workload. An agent becomes an identity that can accumulate grants, own connections, participate in policy decisions, and appear directly in audit records. It is not simply a channel through which permissions pass. It becomes a first-class participant in the exchange.&lt;/p&gt;

&lt;p&gt;You can see the shift in the token model itself.&lt;/p&gt;

&lt;p&gt;Traditional clients rarely appear as meaningful actors within a delegation chain. They request tokens intended for downstream services and largely disappear from the security conversation. A first-class agent changes that relationship. Tokens are issued specifically for the agent. The agent validates that those tokens were intended for it. Delegation chains record the agent as a named participant rather than an invisible intermediary.&lt;/p&gt;

&lt;p&gt;Even the audience claim begins to tell a different story. Instead of acting as a transport mechanism carrying credentials toward another destination, the agent becomes a recognized actor within the trust relationship itself.&lt;/p&gt;

&lt;p&gt;The distinction may appear subtle, but it becomes increasingly important as agents gain reach across systems.&lt;/p&gt;

&lt;h2 id=&quot;the-question-identity-has-always-asked&quot;&gt;The Question Identity Has Always Asked&lt;/h2&gt;

&lt;p&gt;At its core, identity has always existed to answer a simple question:&lt;/p&gt;

&lt;p&gt;Who is allowed to do what?&lt;/p&gt;

&lt;p&gt;For years, we were able to simplify that question because the person authorizing an action was often the same person performing it. When that was true, principal and actor could safely collapse into a single identity.&lt;/p&gt;

&lt;p&gt;Service accounts simplified things in a different direction. They largely removed delegation from the conversation. The service acted as itself, so there was rarely a need to ask on whose behalf it was operating.&lt;/p&gt;

&lt;p&gt;Agents bring both concerns back at the same time.&lt;/p&gt;

&lt;p&gt;The person authorizing the work matters. The entity executing the work matters. The relationship between them matters.&lt;/p&gt;

&lt;p&gt;As a result, identity systems are forced to represent three distinct concepts explicitly:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The principal who authorized the work.&lt;/li&gt;
  &lt;li&gt;The actor performing the work.&lt;/li&gt;
  &lt;li&gt;The delegation chain connecting them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An agent account is ultimately a mechanism for preserving those relationships as work moves through autonomous systems. It is the place where principal, actor, and delegation stop being assumptions and become first-class objects.&lt;/p&gt;

&lt;h2 id=&quot;what-an-agent-account-actually-contains&quot;&gt;What an Agent Account Actually Contains&lt;/h2&gt;

&lt;p&gt;Once the philosophical discussion ends, what remains is architecture.&lt;/p&gt;

&lt;p&gt;A workable agent identity model begins by giving every agent its own identity. Not a shared credential. Not a repurposed user account. An actual identity that can be governed independently.&lt;/p&gt;

&lt;p&gt;That identity becomes the anchor for everything else.&lt;/p&gt;

&lt;p&gt;Permissions, connections, ownership, policy evaluation, and audit records all attach to the agent itself rather than being inferred from surrounding context. The system can now reason about the agent as an actor instead of treating it as a side effect of some other identity.&lt;/p&gt;

&lt;p&gt;The model also needs to distinguish between delegated authority and independent authority. An agent must know when it is acting on behalf of a user and when it is acting as itself. That distinction determines how permissions are evaluated, how actions are recorded, and how responsibility is assigned.&lt;/p&gt;

&lt;p&gt;Around that foundation sit the familiar primitives identity systems have always relied upon:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Scopes that define what an agent may do.&lt;/li&gt;
  &lt;li&gt;Delegations with explicit lifetimes.&lt;/li&gt;
  &lt;li&gt;Consent records that capture authorization events.&lt;/li&gt;
  &lt;li&gt;Credential resolution policies that determine whose authority is being spent.&lt;/li&gt;
  &lt;li&gt;Session grants that govern connection reuse.&lt;/li&gt;
  &lt;li&gt;Access summaries that describe current reachability.&lt;/li&gt;
  &lt;li&gt;Audit records that preserve the full chain of execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these concepts are particularly new.&lt;/p&gt;

&lt;p&gt;What changes is the actor they are being applied to.&lt;/p&gt;

&lt;p&gt;The challenge is no longer managing a human session or securing a service credential. The challenge is preserving the relationship between authorization and execution while work moves through autonomous systems that may cross dozens of boundaries before it finishes.&lt;/p&gt;

&lt;h2 id=&quot;harnesses-and-enforcement&quot;&gt;Harnesses and Enforcement&lt;/h2&gt;

&lt;p&gt;An identity model only matters if it can be enforced consistently.&lt;/p&gt;

&lt;p&gt;If every integration invents its own authentication model, delegation mechanism, and audit strategy, the agent account becomes little more than a diagram. Some systems will honor the model. Others will bypass it. Eventually the architecture and the implementation drift apart.&lt;/p&gt;

&lt;p&gt;All of the controls described above need a common enforcement point.&lt;/p&gt;

&lt;p&gt;Every tool invocation needs to pass through a layer capable of determining whether the operation should execute using delegated authority or independent authority. Every request needs a place where scopes can be evaluated, credentials resolved, delegation chains attached, and audit records generated.&lt;/p&gt;

&lt;p&gt;Without that boundary, agent identity becomes difficult to govern because every integration becomes a special case.&lt;/p&gt;

&lt;p&gt;With that boundary, identity becomes a property of the platform rather than a property of individual tools.&lt;/p&gt;

&lt;h2 id=&quot;why-mcp-matters&quot;&gt;Why MCP Matters&lt;/h2&gt;

&lt;p&gt;This is where MCP becomes interesting.&lt;/p&gt;

&lt;p&gt;MCP gives agents a standardized way to reach tools and services, but the protocol itself is only part of the story. More importantly, it creates a common surface where identity decisions can be applied consistently.&lt;/p&gt;

&lt;p&gt;The protocol boundary becomes the place where delegated and independent execution are distinguished, where credentials are resolved, where scopes are evaluated, where delegation chains are attached to requests, and where audit records are generated.&lt;/p&gt;

&lt;p&gt;The gateway in front of an MCP environment is where the agent account stops being an architectural concept and becomes an operational reality.&lt;/p&gt;

&lt;p&gt;That consistency benefits everyone involved.&lt;/p&gt;

&lt;p&gt;Users authorize access once and allow the agent to continue operating without repeated interruptions. Developers inherit identity, delegation, and auditing capabilities through a common protocol instead of rebuilding them for every integration. Security teams gain confidence that every request reaches a policy enforcement point before it reaches a tool.&lt;/p&gt;

&lt;p&gt;Most importantly, the system retains the ability to answer the questions that matter.&lt;/p&gt;

&lt;p&gt;Who performed this action?&lt;/p&gt;

&lt;p&gt;Who authorized it?&lt;/p&gt;

&lt;p&gt;How are those two connected?&lt;/p&gt;

&lt;h2 id=&quot;another-kind-of-identity&quot;&gt;Another kind of Identity&lt;/h2&gt;

&lt;p&gt;Agent accounts are not simply human accounts with automation attached, nor are they service accounts with broader permissions.&lt;/p&gt;

&lt;p&gt;They represent a different identity pattern, one built around the separation of authorization and execution.&lt;/p&gt;

&lt;p&gt;Humans allowed identity systems to collapse principal and actor into the same entity. Service accounts often removed delegation from the conversation altogether. Agents require both concepts to exist simultaneously and remain visible throughout the lifecycle of a task.&lt;/p&gt;

&lt;p&gt;The future of agent identity comes from extending familiar security principles into a world where authority, action, and responsibility can no longer be assumed to reside in the same place.&lt;/p&gt;

&lt;p&gt;As agents become more capable and more autonomous, preserving those relationships stops being an implementation detail and becomes the foundation on which trustworthy systems are built.&lt;/p&gt;

&lt;p&gt;And all of this is only a small part of a much larger conversation. This post focused on identity because agents force us to rethink how we represent principals, actors, and delegation. The next challenge is authorization, and that problem is considerably messier. Context, risk, Human-in-the-Loop approvals, and dynamically evolving tasks all make it harder to answer not just who is acting, but whether an action should be allowed at all. Agent accounts provide a foundation for reasoning about identity. Whether our authorization models are ready for autonomous actors is a question for another post.&lt;/p&gt;
</description>
        <pubDate>Mon, 01 Jun 2026 02:00:00 +0000</pubDate>
        <link>https://www.alvaroinckot.com/posts/agents-need-their-own-accounts</link>
        <guid isPermaLink="true">https://www.alvaroinckot.com/posts/agents-need-their-own-accounts</guid>
        
        <category>en-US</category>
        
        
        <category>identity,</category>
        
        <category>agents,</category>
        
        <category>authorization,</category>
        
        <category>authentication,</category>
        
        <category>security,</category>
        
        <category>mcp</category>
        
      </item>
    
      <item>
        <title>Six Small Fixes That Make MCP Authorization Less Weird</title>
        <description>&lt;p&gt;The &lt;a href=&quot;https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/&quot;&gt;MCP release candidate for 2026-07-28&lt;/a&gt; dropped last week. The biggest change is the protocol going from stateful to stateless. The rest of the coverage will go to MCP Apps and Tasks. The &lt;a href=&quot;https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/#authorization-hardening&quot;&gt;authorization hardening section&lt;/a&gt; is short, has no diagrams, and reads like a changelog. That is what mature protocol work usually looks like.&lt;/p&gt;

&lt;p&gt;The six SEPs in this section pull MCP authorization closer to how OAuth 2.0 and OpenID Connect already run in production. From the identity side, that is the right kind of work for a protocol at this point.&lt;/p&gt;

&lt;h2 id=&quot;1-iss-validation-on-authorization-responses-sep-2468--rfc-9207&quot;&gt;1. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iss&lt;/code&gt; validation on authorization responses (SEP-2468 / RFC 9207)&lt;/h2&gt;

&lt;p&gt;Mix-up attacks have been a known OAuth problem for almost a decade. RFC 9207 is the fix: the AS includes an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iss&lt;/code&gt; parameter on the response, the client validates it. Most production OAuth deployments either implemented it or shrugged, because they only talk to one AS.&lt;/p&gt;

&lt;p&gt;MCP changes the math. A single host (Claude, Cursor, an IDE plugin) talks to dozens of MCP servers, each potentially fronting a different authorization server. The mix-up attack surface is wider than in any traditional OAuth deployment I have worked on. Making &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iss&lt;/code&gt; validation mandatory now, and signaling that future versions will reject responses without it, is the right call.&lt;/p&gt;

&lt;p&gt;If you run an AS that fronts an MCP resource, start emitting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iss&lt;/code&gt; now.&lt;/p&gt;

&lt;h2 id=&quot;2-application_type-in-dynamic-client-registration-sep-837&quot;&gt;2. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application_type&lt;/code&gt; in Dynamic Client Registration (SEP-837)&lt;/h2&gt;

&lt;p&gt;Anyone who has tried to register a desktop or CLI MCP client via DCR has hit this one. The AS defaults &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application_type&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;web&quot;&lt;/code&gt;, the client sends a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://127.0.0.1&lt;/code&gt; redirect URI, and registration fails because that combination is not allowed for web clients.&lt;/p&gt;

&lt;p&gt;The fix is to have the client declare its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application_type&lt;/code&gt; during DCR. The friction it removes is real: a lot of the integration support tickets I see start with a localhost redirect being rejected by an AS that assumed a server-side client.&lt;/p&gt;

&lt;p&gt;Or, hear me out, you could skip the DCR conversation entirely and go register with &lt;a href=&quot;https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/&quot;&gt;CIMD&lt;/a&gt; instead.&lt;/p&gt;

&lt;h2 id=&quot;3-binding-credentials-to-issuer-re-registering-on-migration-sep-2352&quot;&gt;3. Binding credentials to issuer, re-registering on migration (SEP-2352)&lt;/h2&gt;

&lt;p&gt;A subtle one. If an MCP resource migrates between authorization servers, the previously issued client credentials should not silently keep working against the new AS. SEP-2352 binds registered credentials to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;issuer&lt;/code&gt; they came from and forces re-registration on migration.&lt;/p&gt;

&lt;p&gt;This closes a quiet trust transfer hole. In enterprise deployments where the IdP fronting a resource changes (more common than people admit), you can end up with a client that keeps presenting credentials minted for a different trust domain. Forcing re-registration also pushes client implementers to handle the migration path cleanly, which most do not yet.&lt;/p&gt;

&lt;h2 id=&quot;4-refresh-tokens-from-oidc-style-authorization-servers-sep-2207&quot;&gt;4. Refresh tokens from OIDC-style authorization servers (SEP-2207)&lt;/h2&gt;

&lt;p&gt;OIDC has always had a footnote around refresh tokens: you need the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;offline_access&lt;/code&gt; scope to get one. In practice, several providers were already returning refresh tokens by default without it. The spec just stabilizes that behavior and documents how an MCP client should request refresh tokens against an OIDC AS.&lt;/p&gt;

&lt;p&gt;This is the kind of thing you only appreciate after the third support ticket about “my agent stopped working after an hour.” Long-running agents need refresh tokens. There is now a documented way to ask for them.&lt;/p&gt;

&lt;h2 id=&quot;5-scope-accumulation-during-step-up-sep-2350&quot;&gt;5. Scope accumulation during step-up (SEP-2350)&lt;/h2&gt;

&lt;p&gt;This one is about delegation. Step-up is when an agent has a token with some scopes and needs more to complete a task. The question SEP-2350 answers: do the new scopes replace the old ones, or accumulate?&lt;/p&gt;

&lt;p&gt;Accumulate, in MCP’s model. That matches how a human-driven OAuth flow usually works (you grant a thing, then another thing, both stick). For agents this is the more useful default, because an agent’s task routinely crosses tool boundaries and each new tool can need a different scope.&lt;/p&gt;

&lt;p&gt;The harder question this SEP does not try to solve: when an agent steps up, on whose authority is it stepping up? The user’s, or its own? MCP today assumes the user’s, via the same browser-based consent flow. As agent identity matures (and it will), step-up will need to treat the agent as a distinct identity with its own authority surface, separate from the user’s. Different post.&lt;/p&gt;

&lt;h2 id=&quot;6-well-known-discovery-suffix-sep-2351&quot;&gt;6. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.well-known&lt;/code&gt; discovery suffix (SEP-2351)&lt;/h2&gt;

&lt;p&gt;Pure cleanup. Discovery in MCP has been muddled by inconsistent suffix conventions. SEP-2351 fixes the suffix.&lt;/p&gt;

&lt;h2 id=&quot;the-bigger-picture&quot;&gt;The bigger picture&lt;/h2&gt;

&lt;p&gt;MCP authorization is converging on the OAuth and OIDC patterns that already run in production. That convergence is what makes the protocol safe to deploy behind a real enterprise IdP.&lt;/p&gt;

&lt;p&gt;Adjacent standards work is already covering the agent-specific identity problems. Cross-App Access, ID-JAG, and the IETF drafts on OBO for agents are in flight. MCP does not need to re-invent that work. When those drafts stabilize, MCP can adopt them, and the alignment work in this release is what makes that adoption path clean.&lt;/p&gt;

&lt;p&gt;The operational challenge is the transition period. Client implementations will land at different speeds, and AS operators will need to keep the old behaviors running until enough clients support these SEPs fully. Worth tracking client by client.&lt;/p&gt;

&lt;p&gt;This release removes a long list of small reasons not to run MCP in front of your enterprise IdP. After 2026-07-28, that list is shorter than it has ever been.&lt;/p&gt;
</description>
        <pubDate>Tue, 26 May 2026 02:00:00 +0000</pubDate>
        <link>https://www.alvaroinckot.com/posts/six-small-fixes-that-make-mcp-authorization-less-weird</link>
        <guid isPermaLink="true">https://www.alvaroinckot.com/posts/six-small-fixes-that-make-mcp-authorization-less-weird</guid>
        
        <category>en-US</category>
        
        
        <category>authorization,</category>
        
        <category>mcp,</category>
        
        <category>oauth,</category>
        
        <category>oidc,</category>
        
        <category>identity</category>
        
      </item>
    
      <item>
        <title>My Development Workflow 2026-Q1 Edition</title>
        <description>&lt;p&gt;I’ve been talking to friends and colleagues about what I’ve been building at Runlayer with MCPs, and the same thing keeps coming up: my workflow. Most devs outside our X/LinkedIn bubble don’t know about the current state of the art in software engineering tooling. So here’s my attempt to share what’s working for me: links, approaches, and all.&lt;/p&gt;

&lt;p&gt;Fair warning: this kind of post ages like milk in the sun.&lt;/p&gt;

&lt;h2 id=&quot;youre-probably-not-losing-your-job&quot;&gt;You’re (probably) not losing your job&lt;/h2&gt;

&lt;p&gt;Developers are moving closer to the business. The era of agentic development has begun. I see engineers becoming deeper experts in product and domain areas (identity, SRE, tooling) while the technology to solve these problems becomes cross-cutting. Coding or learning a new language/stack is no longer the bottleneck.&lt;/p&gt;

&lt;p&gt;In the future, I see software engineers writing &lt;em&gt;the software factory&lt;/em&gt; (&lt;a href=&quot;https://openai.com/index/harness-engineering/&quot;&gt;relevant OpenAI paper&lt;/a&gt;) instead of writing production code directly. We should expect new software verticals, like &lt;a href=&quot;https://timesofindia.indiatimes.com/etimes/trending/doctor-builds-an-ai-app-for-medical-documentation-without-writing-code-and-finishes-top-three-at-anthropics-hackathon/articleshow/128698960.cms&quot;&gt;doctors creating software&lt;/a&gt;, the state of the art being pushed forward, but also a “fast food software” era where people spin up small disposable tools for personal use.&lt;/p&gt;

&lt;p&gt;The fastest way to produce meaningful software has changed rapidly: ChatGPT copy-paste, then GitHub Copilot autocomplete, then Cursor, then Claude Code… and something new every week. What all this progress has in common is that the developer’s eyes don’t need to be on every character change anymore.&lt;/p&gt;

&lt;p&gt;I like this analogy: &lt;strong&gt;context is like a scuba tank&lt;/strong&gt;. The longer you can stay underwater, the better. The longer the context window we can feed our tasks with good reasoning, the better the output. Despite some skepticism about LLM architectures hitting a ceiling, we’ve found smart ways to keep this flow efficient. We started with a few tabs and autocomplete suggestions. Now you can have a full 10-hour session of working software being produced with minimal human intervention.&lt;/p&gt;

&lt;h2 id=&quot;the-workflow&quot;&gt;The Workflow&lt;/h2&gt;

&lt;p&gt;I split my workflow into five phases: &lt;strong&gt;brainstorm, design, plan, code, review + improve&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;1-brainstorm--design&quot;&gt;1. Brainstorm &amp;amp; Design&lt;/h3&gt;

&lt;p&gt;The idea phase is straightforward. I create a single markdown file, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docs/IDEA.md&lt;/code&gt; or whatever, and dump everything I’m thinking about the problem. Caveats, possible future issues, codebase tweaks, edge cases. This is the time to say everything. In this phase, I deliberately avoid heavy AI intervention until I’ve fully stressed the outcomes myself.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chatgpt.com/features/deep-research/&quot;&gt;Deep Research on ChatGPT&lt;/a&gt; is genuinely useful here, especially when the work involves an RFC or spec to follow.&lt;/p&gt;

&lt;p&gt;Once the idea file exists, I take one of two paths (usually both, then pick whichever produces the better plan):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A:&lt;/strong&gt; Clean up the idea file for grammar and conciseness, then feed it to Cursor with Opus 4.6 to write a design document.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option B:&lt;/strong&gt; Use the &lt;a href=&quot;https://github.com/obra/superpowers&quot;&gt;Superpower skills in Claude Code&lt;/a&gt;. The brainstorm phase here is excellent: it automates the idea back-and-forth, turning topics into workable features while investigating your codebase. If your guardrails are solid in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IDEA.md&lt;/code&gt; file, it does a great job asking pointed questions and turning your rough ideas into a structured plan.&lt;/p&gt;

&lt;p&gt;The design-before-plan step is a good forcing function. It fills thought gaps, catches missing requirements, and surfaces hallucinations early, before they become code.&lt;/p&gt;

&lt;p&gt;A few MCPs (more on those below) are helpful here: &lt;a href=&quot;https://github.com/upstash/context7&quot;&gt;Context7&lt;/a&gt; for documentation lookups, or your GitHub MCP in brownfield projects where you can pull in issues or previous PRs to give agents richer context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Always ask for negative test cases. 100% code coverage isn’t enough. Multiple layers of tests build confidence, help agents get context, and serve as running documentation for AI agents.&lt;/p&gt;

&lt;p&gt;The output of this phase: a design file with all the context needed for planning.&lt;/p&gt;

&lt;h3 id=&quot;2-plan&quot;&gt;2. Plan&lt;/h3&gt;

&lt;p&gt;This is where automation shines. Feed your favorite agent the design file and let it generate a plan. In Cursor it’s a button. In Claude Code, it’s the Superpower plan skill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Side note:&lt;/strong&gt; You can run multiple worktrees and let agents work in parallel, or clone the repo multiple times. Just make sure each instance runs on different ports and resources. You don’t want to confuse your code/testing agents.&lt;/p&gt;

&lt;p&gt;Take your time reviewing the plan. Usually ~90% of what’s written here is what your codebase will end up with. This is the moment to catch major hallucinations and ensure the final product matches your intent.&lt;/p&gt;

&lt;h3 id=&quot;3-code&quot;&gt;3. Code&lt;/h3&gt;

&lt;p&gt;Now it’s code time. A few things matter here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AGENTS.md&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt; files are critical.&lt;/strong&gt; These are general guidelines scoped to a folder, and you can have specialized instructions in subfolders. That’s why clean architecture with clear boundaries matters: it prevents agents from getting confused and hallucinating.&lt;/p&gt;

&lt;p&gt;You can also craft custom skills to kick off your coding job depending on what you’re working on. Sometimes you’re creating, sometimes condensing, sometimes fixing a single line.&lt;/p&gt;

&lt;p&gt;Classic code metrics still apply. I’ve written before about type safety being your best friend, but cyclomatic complexity, fitness functions, and architectural tests are equally vital for codebase health.&lt;/p&gt;

&lt;p&gt;I use &lt;strong&gt;Sonnet 4.5&lt;/strong&gt; for general coding tasks, sometimes Codex for frontend. If you have best practices for code quality and software engineering in place (now you have time to set them up), you shouldn’t have problems. Let your agents run tests. You can have a dedicated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AGENTS.md&lt;/code&gt; just for testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Side note on bugfixes:&lt;/strong&gt; TDD is your best friend here.&lt;/p&gt;

&lt;h3 id=&quot;4-review&quot;&gt;4. Review&lt;/h3&gt;

&lt;p&gt;Code finished. Now the real bottleneck: human eyes.&lt;/p&gt;

&lt;p&gt;Greenfield projects usually mean a big boom commit with everything for the MVP. Even in brownfield, some cross-cutting features land in a single step, and the volume of changes can hurt.&lt;/p&gt;

&lt;p&gt;Agent reviewers can help catch the obvious things (shout-out to Devin, and a firm boo to Sentry’s reviewer). But your experience is fundamental to ensure the code does what it needs to do without making the codebase worse. Review skills help here too, especially for catching AI slop: oversized comments, weird variable names, unnecessary abstractions. Zoom in and zoom out.&lt;/p&gt;

&lt;h3 id=&quot;5-improve&quot;&gt;5. Improve&lt;/h3&gt;

&lt;p&gt;Your coding session is gold. Lots of assumptions and hallucinations were made along the way. This is the time to review your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AGENTS.md&lt;/code&gt; files, add hooks, or craft new skills for your development process. Each session makes the next one better.&lt;/p&gt;

&lt;h2 id=&quot;a-quick-note-on-mcps&quot;&gt;A Quick Note on MCPs&lt;/h2&gt;

&lt;p&gt;If you’re not familiar with MCPs, here’s a quick intro: they work like AI connectors. Instead of copying and pasting everything, service providers create these connectors so you can automate workflows more efficiently. Connect your favorite MCP client (Cursor, Claude, VSCode, Windsurf) to these connectors and automate all sorts of work:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;“Get the last Datadog issues related to X, open tickets on Linear for each problem, start a sub-agent to triage, and write a plan to fix it.”&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;“Read all my emails and create a task list on Notion for today.”&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The possibilities are only limited by your creativity.&lt;/p&gt;

&lt;h2 id=&quot;security-concerns&quot;&gt;Security Concerns&lt;/h2&gt;

&lt;p&gt;Of course, there are real concerns around security. It’s not easy to create safeguards for all these autonomous tools, and the attack surface for engineering teams is significant: credentials leaking, agents causing outages. This is the problem we solve at &lt;a href=&quot;https://runlayer.com&quot;&gt;Runlayer&lt;/a&gt;. We empower teams to build even more automated workflows with security concerns covered in a single platform.&lt;/p&gt;

&lt;h2 id=&quot;what-a-good-day-looks-like&quot;&gt;What a Good Day Looks Like&lt;/h2&gt;

&lt;p&gt;A good day starts with a prompt asking Cursor to check all my pending PRs, reviewing feedback from coworkers (especially those in other time zones), addressing and responding one by one. The occasional human intervention happens when a tradeoff needs discussion, but if the design is solid and requirements were aligned, no surprises should appear.&lt;/p&gt;

&lt;p&gt;In parallel, I start dissecting new feature request designs by filtering Linear tickets. For mature designs, I create tickets and define priorities for the day, often with a single prompt.&lt;/p&gt;

&lt;p&gt;When emergencies hit, I prompt with the Sentry link, investigate logs on CloudWatch via the AWS MCP, craft a plan, and report progress on Slack in real time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The stack that makes this work:&lt;/strong&gt; GitHub + Sentry + AWS + Linear + Slack bots.&lt;/p&gt;

&lt;p&gt;All of these flows happen in my daily routine. The future is here. Embrace it.&lt;/p&gt;

&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;

&lt;p&gt;If you’re building automated workflows and care about security, check out &lt;a href=&quot;https://runlayer.com&quot;&gt;Runlayer&lt;/a&gt; — it’s the platform we built to let engineering teams automate with MCPs while keeping credentials, access, and blast radius under control.&lt;/p&gt;

&lt;h3 id=&quot;mcps-mentioned-in-this-post&quot;&gt;MCPs mentioned in this post&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/github/github-mcp-server&quot;&gt;GitHub MCP Server&lt;/a&gt; — GitHub’s official MCP server for issues, PRs, repos, and more.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/getsentry/sentry-mcp&quot;&gt;Sentry MCP Server&lt;/a&gt; — Access Sentry issues, errors, and AI analysis from your agent.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/awslabs/mcp&quot;&gt;AWS MCP Servers&lt;/a&gt; — AWS Labs’ collection of 60+ MCP servers for AWS services.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/cline/linear-mcp&quot;&gt;Linear MCP Server&lt;/a&gt; — MCP server for Linear issue tracking.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.slack.dev/ai/mcp-server&quot;&gt;Slack MCP Server&lt;/a&gt; — Slack’s official MCP server for messages, channels, and canvases.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/upstash/context7&quot;&gt;Context7&lt;/a&gt; — Up-to-date documentation lookups for your agents.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;further-reading&quot;&gt;Further reading&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.anthropic.com/news/model-context-protocol&quot;&gt;What is MCP (Model Context Protocol)?&lt;/a&gt; — Anthropic’s introduction to the protocol that standardizes how AI applications connect to tools and data sources.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://skilllm.com/blog/custom-agent-skills-cursor&quot;&gt;What are Agent Skills?&lt;/a&gt; — A guide to creating modular, portable capabilities for AI coding agents in Cursor and Claude Code.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/obra/superpowers&quot;&gt;Superpowers for Claude Code&lt;/a&gt; — The skills framework I use for brainstorming, planning, and code review.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://chatgpt.com/features/deep-research/&quot;&gt;ChatGPT Deep Research&lt;/a&gt; — Useful for the idea and research phase.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Mon, 23 Feb 2026 02:00:00 +0000</pubDate>
        <link>https://www.alvaroinckot.com/posts/my-development-workflow-2026-q1-edition</link>
        <guid isPermaLink="true">https://www.alvaroinckot.com/posts/my-development-workflow-2026-q1-edition</guid>
        
        <category>en-US</category>
        
        
        <category>ai,</category>
        
        <category>workflow,</category>
        
        <category>mcp,</category>
        
        <category>cursor,</category>
        
        <category>engineering</category>
        
      </item>
    
      <item>
        <title>Authorization in a Shifting Maze</title>
        <description>&lt;p&gt;Everyone’s hitting the same wall with OPA (Open Policy Agent). It starts great, externalizing policies, central control, policy-as-code. But once you go past a few dozen rules, things start to feel heavy. Latency creeps in. Your rules grow from clean to unreadable. You add a “deny all” just to keep things safe and now you’re chasing ghosts in staging. And the worst part is, once you finally get a policy to say “yes” or “no”, you still don’t know who else that rule applies to. You know it worked, but not why, or who’s living in the same permission shadow.&lt;/p&gt;

&lt;p&gt;So people start looking elsewhere. ReBAC pops up in the conversation. SpiceDB, ORY, the whole Zanzibar-inspired crowd. The promise is seductive, represent relationships as first-class citizens, turn permissions into something you can query and explain. Who can read this doc? Just ask. Who has access to a project? Query the graph. It feels closer to how we think about access, and a lot closer to how auditors ask questions.&lt;/p&gt;

&lt;p&gt;But it’s not easy. These systems aren’t a library you import. They’re infrastructure. They need care. You model your world in a schema, sync changes, run migrations. And when your policies go beyond simple relationships like time windows, content rules, anomaly triggers, you start stitching back in custom logic, just like before. Still, it’s better than OPA in some cases. You trade raw flexibility for visibility, and a lot of teams are happy to make that trade.&lt;/p&gt;

&lt;p&gt;And then comes AI. Not the fancy demos, the messy, real stuff. Assistants calling APIs on behalf of users. Agents chaining requests. Data flying across embeddings, vectors, context windows. Your policies weren’t written for this. They were written for API calls, for users clicking buttons, not for autonomous workflows making decisions three layers deep.&lt;/p&gt;

&lt;p&gt;The enforcement point is gone. There’s no gateway in the loop. The agent is inside. It can read a tool manifest, call whatever it wants. If you don’t bind its permissions explicitly, it’ll just act. Worse, sometimes it doesn’t even know what it’s doing. It’s reacting, generating, inferring. The idea of deterministic authz starts to bend.&lt;/p&gt;

&lt;p&gt;So now we’re staring at a future with protocols like MCP and A2A trying to formalize how these agents act. They’re early, experimental, mostly scaffolding. But they’re pointing at a real need, to give agents context-aware, time-bound, minimal access. To make authorization dynamic, explainable, and enforced at the function level. To do for agents what we tried to do for users a decade ago.&lt;/p&gt;

&lt;p&gt;We’re in that awkward phase again. The old tools are creaking. The new ones aren’t mature. Everyone’s rewriting the same policies, debugging the same permission holes, patching over the same visibility gaps. It feels like the ground is shifting, but no one’s quite sure where it’s going to settle.&lt;/p&gt;

&lt;p&gt;It’s a good time to be paying attention. Better time to be building. More soon.&lt;/p&gt;
</description>
        <pubDate>Fri, 14 Nov 2025 02:00:00 +0000</pubDate>
        <link>https://www.alvaroinckot.com/posts/authorization-in-a-shifting-maze</link>
        <guid isPermaLink="true">https://www.alvaroinckot.com/posts/authorization-in-a-shifting-maze</guid>
        
        <category>en-US</category>
        
        
        <category>ai,</category>
        
        <category>authorization,</category>
        
        <category>mcp,</category>
        
        <category>a2a,</category>
        
        <category>braindump</category>
        
      </item>
    
      <item>
        <title>Next-Gen Languages, Compilers, and IRs for AI</title>
        <description>&lt;p&gt;AI models keep scaling while fresh silicon (GPUs, TPUs, NPUs, you name it) hits the market every year. That widening hardware zoo leaves a gap: high-level Python builds ever-larger graphs, but each graph still needs hand-tuned kernels to run fast on the latest chip. Yesterday the fix was to write CUDA or OpenCL by hand or wait for cuDNN-style libraries to catch up. Today a different approach is taking over: modern compilers slide an intermediate representation (IR) between model and metal, so one translation step, not bespoke kernels, unlocks every device.&lt;/p&gt;

&lt;p&gt;In 2015 SPIR-V gave GPUs a vendor-neutral bytecode. Three years later TVM showed that an auto-tuner could outpace handwritten CUDA on day one. By 2019 MLIR turned compiler plumbing into reusable Lego blocks. These three breakthroughs (portability, auto-optimization, and modularity) now sit behind the compile button in most ML stacks.&lt;/p&gt;

&lt;h1 id=&quot;mlir--the-modular-backbone&quot;&gt;MLIR — the modular backbone&lt;/h1&gt;

&lt;p&gt;MLIR splits a compiler into dialects that capture successive abstraction layers: tensor graphs, affine loops, hardware intrinsics. A pass added to one dialect (say, loop fusion) automatically benefits every project that reuses that dialect, from IREE to Torch-MLIR. Lowering to LLVM, SPIR-V or bespoke silicon happens late, after the heavy lifting is shared.&lt;/p&gt;

&lt;h1 id=&quot;tvm--the-turnkey-optimizer&quot;&gt;TVM — the turnkey optimizer&lt;/h1&gt;

&lt;p&gt;Feed TVM a saved PyTorch, TensorFlow or ONNX model; it rewrites the graph, lowers to tensor-level IR and brute-forces kernel schedules until the fastest variant wins. That auto-search delivered ~30 % extra throughput on Apple M1 the week the chip shipped—no manual kernels, no vendor lock-ins. TVM then emits tuned binaries for CPUs, GPUs and NPUs in one sweep.&lt;/p&gt;

&lt;h1 id=&quot;spir-v--the-portable-runway&quot;&gt;SPIR-V — the portable runway&lt;/h1&gt;

&lt;p&gt;SPIR-V isn’t a compiler; it’s the last IR hop. Emit it and the same binary runs on NVIDIA, AMD, Intel iGPUs or a mobile Mali as long as a conforming driver is present. By pushing portability down to the driver layer, SPIR-V removes the final hard dependency on CUDA-style ecosystems.&lt;/p&gt;

&lt;h1 id=&quot;how-the-pieces-fit&quot;&gt;How the pieces fit&lt;/h1&gt;

&lt;p&gt;MLIR supplies reusable stages, TVM adds production-grade autotune on top, and SPIR-V is the landing zone for any GPU. In most toolchains they cooperate rather than compete: MLIR dialects feed TVM optimizers, which then lower to SPIR-V for execution on whatever silicon is available.&lt;/p&gt;

&lt;div align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/2025-07-04-next-gen-ai-irs/chart.png&quot; alt=&quot;AI Compiler Stack&quot; /&gt;
&lt;/div&gt;

&lt;h1 id=&quot;impact&quot;&gt;Impact&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;PyTorch 2.0. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;torch.compile()&lt;/code&gt; now routes graphs through MLIR-style passes before handing them to back ends such as Triton or OpenXLA, squeezing double-digit speed-ups on Gaudi-3 and CUDA alike.&lt;/li&gt;
  &lt;li&gt;JAX &amp;amp; TensorFlow. Both lean on OpenXLA, whose StableHLO dialect is implemented in MLIR; JIT-compilation sends those graphs through the same optimization chute before they hit TPUs, GPUs or CPUs.&lt;/li&gt;
  &lt;li&gt;Hugging Face Optimum. One CLI switch compiles a transformer with TVM, generates SPIR-V, and serves it via WebGPU—bringing near-desktop throughput to browsers and Android devices without code changes.&lt;/li&gt;
  &lt;li&gt;Cost &amp;amp; reach. Unified IR pipelines mean fewer bespoke kernels, quicker hardware bring-up, and lower cloud invoices: optimize once, deploy everywhere. As accelerators proliferate, the compiler layer—not bigger models—will decide who ships state-of-the-art inference first.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Hand-tuned kernels aren’t gone yet, but the momentum is clear. With IR-centric compilers bridging Python and metal, the next breakthrough may be the toolchain that lets tomorrow’s model run anywhere, fast.&lt;/p&gt;

&lt;h1 id=&quot;sources-and-recommended-read&quot;&gt;Sources and recommended read&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;A friendly introduction to machine learning compilers and optimizers -&lt;a href=&quot;https://huyenchip.com/2021/09/07/a-friendly-introduction-to-machine-learning-compilers-and-optimizers.html&quot;&gt;Link&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Apache TVM performance claim - &lt;a href=&quot;https://venturebeat.com/ai/octoml-optimizes-apache-tvm-for-apples-m1-beats-core-ml-4-by-29/&quot;&gt;Link&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;MLIR - &lt;a href=&quot;https://mlir.llvm.org/&quot;&gt;Link&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Apache TVM - &lt;a href=&quot;https://tvm.apache.org/&quot;&gt;Link&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;SPIR-V - &lt;a href=&quot;https://www.khronos.org/spirv/&quot;&gt;Link&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Fri, 04 Jul 2025 04:00:00 +0000</pubDate>
        <link>https://www.alvaroinckot.com/posts/next-gen-ai-languages-compilers-irs</link>
        <guid isPermaLink="true">https://www.alvaroinckot.com/posts/next-gen-ai-languages-compilers-irs</guid>
        
        <category>en-US</category>
        
        
        <category>ai,</category>
        
        <category>machine-learning,</category>
        
        <category>braindump</category>
        
      </item>
    
      <item>
        <title>The Day I Built an AI to Predict Tibia Character Prices</title>
        <description>&lt;p&gt;A story about TCAQS: Tibia Character Automated Quotation System&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Portuguese version: &lt;a href=&quot;https://www.alvaroinckot.com/posts/o-dia-em-que-construi-uma-ia-para-prever-precos-de-personagens-de-tibia&quot;&gt;Link&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;the-spark-latenight-2022&quot;&gt;The spark (late‑night 2022)&lt;/h2&gt;

&lt;p&gt;Picture a rainy Sunday in 2022. I’m procrastinating on real‑life chores by scrolling &lt;a href=&quot;https://www.tibia.com/news/?subtopic=latestnews&quot;&gt;Tibia’s brand‑new auction house&lt;/a&gt;, looking at characters priced like beachfront property. &lt;em&gt;Surely&lt;/em&gt; there’s a pattern here, I thought. Fifteen years of playing Tibia had wired my brain to sniff under‑ or over‑priced deals the way other people smell fresh coffee.&lt;/p&gt;

&lt;p&gt;So I opened VS Code and wrote the first line of what would become TCAQS: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async def scrap(url): ...&lt;/code&gt;&lt;br /&gt;
Mission: scrape every single auction record, teach a model to predict fair prices, and maybe—just maybe—save a few souls from paying 6k TC in a skill-less knight in Antica.&lt;/p&gt;

&lt;h2 id=&quot;three-weeks-650000-html-files-one-battered-laptop&quot;&gt;Three weeks, 650 000 HTML files, one battered laptop&lt;/h2&gt;

&lt;p&gt;Tibia’s rate‑limiter is the digital equivalent of an ankle weight. Three requests every second isn’t a suggestion—it’s the law. Multiply that by half a million pages and you get &lt;strong&gt;six days&lt;/strong&gt; of constant crawling (add constant networks drops, and some Tibia website downtime as well). When the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;results/&lt;/code&gt; folder finally hit 650 k files, I zipped it, patted myself on the back, and… promptly moved to the United States.&lt;/p&gt;

&lt;p&gt;Life happened: visas, boxes, a Florida heatwave. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tcaqs/&lt;/code&gt; collected dust in a backup drive.&lt;/p&gt;

&lt;h2 id=&quot;rediscovery-may2024&quot;&gt;Rediscovery (May 2024)&lt;/h2&gt;

&lt;p&gt;Fast‑forward to a spring cleaning session. I’m Marie‑Kondo‑ing old drives when a 14 GB archive labeled &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tibia_auctions_2022.zip&lt;/code&gt; stares back. Does it spark joy? &lt;em&gt;Absolutely.&lt;/em&gt; And AI tooling has exploded since 2022, so why not finish the job?&lt;/p&gt;

&lt;h2 id=&quot;death-by-a-thousand-divs&quot;&gt;Death by a thousand &amp;lt;div&amp;gt;s&lt;/h2&gt;

&lt;p&gt;Parsing those HTML relics felt like fighting 1 000 paper cuts with a wooden shield. I wrote a tiny utility, &lt;strong&gt;html‑scalpel&lt;/strong&gt;, that sliced each page into a dict, dumped it to Parquet, and batched inserts into SQLite. Seven hours later I had:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;650 k rows&lt;/li&gt;
  &lt;li&gt;40+ raw fields (level, vocation, outfits, mounts, quest flags…)&lt;/li&gt;
  &lt;li&gt;Two crucial targets: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;final_bid&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bid_status&lt;/code&gt; (sold vs. minimum‑bid‑unsold)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/alvaroinckot/tcaqs/blob/main/assets/cpu-usage-result.png?raw=true&quot; alt=&quot;cpu goes brrrr&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;model-season-xgboost-vs-my-ego&quot;&gt;Model season: XGBoost vs. my ego&lt;/h2&gt;

&lt;p&gt;I promised myself &lt;strong&gt;90 % R²&lt;/strong&gt; on test data, enough to pass my own Tibian sniff‑test. Here’s how that duel unfolded:&lt;/p&gt;

&lt;h3 id=&quot;v1-baseline-and-reality-check&quot;&gt;v1: Baseline and Reality Check&lt;/h3&gt;

&lt;p&gt;I began with the obvious stats: level, vocation, world type, and a handful of other numeric attributes, thirty columns in total. A quick grid-search on plain XGBoost pushed training R² past 0.94, but test R² stalled at 0.89 while MAPE bounced all over, especially on low-level characters. The model was memorising the training set and learning little about real-world pricing, useful only as a floor for future work.&lt;/p&gt;

&lt;h3 id=&quot;v2-packing-the-lore&quot;&gt;v2: Packing the Lore&lt;/h3&gt;

&lt;p&gt;Next I stuffed in the bragging-rights features that really drive Tibia prices, such as quest flags, rare mounts, outfits, hirelings, and server type, all one-hot encoded and rebalanced. Bayesian hyper-parameter tuning lifted test R² to 0.94 and smoothed predictions for mid- to high-level chars. The new pain point, though, was low-level characters on freshly opened servers. They start overpriced because early adopters have excess gold, then drop rapidly as the server economy matures, so their actual values drift faster than my static scrape could capture, keeping MAPE high in that slice.&lt;/p&gt;

&lt;h3 id=&quot;v3-purging-poisoned-labels&quot;&gt;v3: Purging Poisoned Labels&lt;/h3&gt;

&lt;p&gt;The real breakthrough came from cleaner targets, not extra features. Many auctions ending at the minimum bid had no buyer, so their listed prices were wishful thinking. Filtering those rows, log-transforming gold values, and retuning XGBoost flattened the error curve: overall MAPE fell to 0.42 (under 0.30 for sub-100 chars) and test R² settled at 0.935. CatBoost scored about the same but drank more VRAM, so XGBoost is still the champion for now.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/alvaroinckot/tcaqs/blob/main/assets/top-features.png?raw=true&quot; alt=&quot;Top Features&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;a-few-results&quot;&gt;A few results&lt;/h2&gt;

&lt;p&gt;The feature engineering evolution in numbers:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Model&lt;/th&gt;
      &lt;th&gt;Split&lt;/th&gt;
      &lt;th&gt;MSE&lt;/th&gt;
      &lt;th&gt;RMSE&lt;/th&gt;
      &lt;th&gt;MAE&lt;/th&gt;
      &lt;th&gt;MAPE&lt;/th&gt;
      &lt;th&gt;R2&lt;/th&gt;
      &lt;th&gt;Explained_Variance&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v1&lt;/td&gt;
      &lt;td&gt;Training&lt;/td&gt;
      &lt;td&gt;2289526.25&lt;/td&gt;
      &lt;td&gt;1513.12&lt;/td&gt;
      &lt;td&gt;703.37&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;0.9393&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v1&lt;/td&gt;
      &lt;td&gt;Testing&lt;/td&gt;
      &lt;td&gt;4209464.5&lt;/td&gt;
      &lt;td&gt;2051.7&lt;/td&gt;
      &lt;td&gt;857.07&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;0.8874&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v2&lt;/td&gt;
      &lt;td&gt;Training&lt;/td&gt;
      &lt;td&gt;543840.75&lt;/td&gt;
      &lt;td&gt;737.46&lt;/td&gt;
      &lt;td&gt;376.31&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;0.9856&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v2&lt;/td&gt;
      &lt;td&gt;Testing&lt;/td&gt;
      &lt;td&gt;2172790.25&lt;/td&gt;
      &lt;td&gt;1474.04&lt;/td&gt;
      &lt;td&gt;582.8&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;0.9419&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v2-es&lt;/td&gt;
      &lt;td&gt;Training&lt;/td&gt;
      &lt;td&gt;333324.59&lt;/td&gt;
      &lt;td&gt;577.3427&lt;/td&gt;
      &lt;td&gt;315.0486&lt;/td&gt;
      &lt;td&gt;0.4379&lt;/td&gt;
      &lt;td&gt;0.9912&lt;/td&gt;
      &lt;td&gt;0.9912&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v2-es&lt;/td&gt;
      &lt;td&gt;Testing&lt;/td&gt;
      &lt;td&gt;2140074.75&lt;/td&gt;
      &lt;td&gt;1462.8994&lt;/td&gt;
      &lt;td&gt;577.0405&lt;/td&gt;
      &lt;td&gt;0.5454&lt;/td&gt;
      &lt;td&gt;0.9427&lt;/td&gt;
      &lt;td&gt;0.9427&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v3&lt;/td&gt;
      &lt;td&gt;Training&lt;/td&gt;
      &lt;td&gt;49717.34&lt;/td&gt;
      &lt;td&gt;222.9739&lt;/td&gt;
      &lt;td&gt;149.1993&lt;/td&gt;
      &lt;td&gt;0.3372&lt;/td&gt;
      &lt;td&gt;0.9954&lt;/td&gt;
      &lt;td&gt;0.9954&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v3&lt;/td&gt;
      &lt;td&gt;Testing&lt;/td&gt;
      &lt;td&gt;725773.25&lt;/td&gt;
      &lt;td&gt;851.9233&lt;/td&gt;
      &lt;td&gt;358.3552&lt;/td&gt;
      &lt;td&gt;0.4243&lt;/td&gt;
      &lt;td&gt;0.9349&lt;/td&gt;
      &lt;td&gt;0.9349&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;a-live-crystal-ball&quot;&gt;A live crystal ball&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Demo&lt;/strong&gt;: &lt;a href=&quot;https://huggingface.co/spaces/alvaroinckot/tcaqs&quot;&gt;https://huggingface.co/spaces/alvaroinckot/tcaqs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Code&lt;/strong&gt;: &lt;a href=&quot;https://github.com/alvaroinckot/tcaqs&quot;&gt;https://github.com/alvaroinckot/tcaqs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fill out character info and get an estimate. No more guesswork before you splash the guild’s treasury.&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Fresh crawl&lt;/strong&gt; – New vocation (Monk) &amp;amp; inflation‑adjusted gold means the 2022 snapshot is aging. A distributed crawler on SQS (or any other queue) should cut scraping from weeks to days.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Market context&lt;/strong&gt; – Inject rolling world‑level CPI so the model tracks gold inflation.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Model bake‑off&lt;/strong&gt; – LightGBM, TabPFN, maybe a tiny tabular transformer—because why not?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Public dashboard&lt;/strong&gt; – Daily fair‑price index per vocation/world.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;closing-xp&quot;&gt;Closing XP&lt;/h2&gt;

&lt;p&gt;Shipping &lt;strong&gt;TCAQS&lt;/strong&gt; reminded me that AI glamour rests on unglamorous foundations: stubborn scraping, vicious cleaning, and lots of waiting bars. But bringing together two long‑time passions: Tibia and machine learning, was worth every &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;div&amp;gt;&lt;/code&gt;.&lt;/p&gt;
</description>
        <pubDate>Wed, 11 Jun 2025 04:00:00 +0000</pubDate>
        <link>https://www.alvaroinckot.com/posts/the-day-i-built-an-ai-to-predict-tibia-character-prices</link>
        <guid isPermaLink="true">https://www.alvaroinckot.com/posts/the-day-i-built-an-ai-to-predict-tibia-character-prices</guid>
        
        <category>en-US</category>
        
        
        <category>ai</category>
        
        <category>machine-learning</category>
        
      </item>
    
      <item>
        <title>O Dia em que Construí uma IA para Prever Preços de Personagens de Tibia</title>
        <description>&lt;p&gt;Uma história sobre TCAQS: Tibia Character Automated Quotation System&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;English version: &lt;a href=&quot;https://www.alvaroinckot.com/posts/the-day-i-built-an-ai-to-predict-tibia-character-prices&quot;&gt;Link&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;o-início-final-de-2022&quot;&gt;O início (final de 2022)&lt;/h2&gt;

&lt;p&gt;Imagine um domingo chuvoso em 2022. Eu estava procrastinando tarefas da vida real navegando pelo novíssimo auction house do &lt;a href=&quot;https://www.tibia.com/news/?subtopic=latestnews&quot;&gt;Tibia&lt;/a&gt;, olhando para personagens precificados como propriedades à beira-mar. &lt;em&gt;Certamente&lt;/em&gt; existe um padrão aqui, pensei. Quinze anos jogando Tibia haviam programado meu cérebro para achar negócios sub ou supervalorizados.&lt;/p&gt;

&lt;p&gt;Então abri o VS Code e escrevi a primeira linha do que viria a ser o TCAQS: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async def scrap(url): ...&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Missão: raspar todos os registros de leilão, ensinar um modelo a prever preços justos e talvez—só talvez—salvar algumas almas de pagar 6k TC em um knight sem skills em Antica.&lt;/p&gt;

&lt;h2 id=&quot;três-semanas-650000-arquivos-html-um-laptop-sobrecarregado&quot;&gt;Três semanas, 650.000 arquivos HTML, um laptop sobrecarregado&lt;/h2&gt;

&lt;p&gt;O rate-limiter do Tibia é o equivalente digital a um peso no tornozelo. Três requisições por segundo não é uma sugestão — é a lei. Multiplique isso por meio milhão de páginas e você tem &lt;strong&gt;seis dias&lt;/strong&gt; de scraping constante (adicione quedas constantes de rede e algum tempo de inatividade do site do Tibia também). Quando a pasta &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;results/&lt;/code&gt; finalmente atingiu 650 mil arquivos, compactei-a, dei um tapinhas nas costas e… prontamente me mudei para os Estados Unidos.&lt;/p&gt;

&lt;p&gt;A vida aconteceu: vistos, caixas, uma onda de calor na Flórida. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tcaqs/&lt;/code&gt; juntou poeira em um disco de backup.&lt;/p&gt;

&lt;h2 id=&quot;redescoberta-maio-de-2024&quot;&gt;Redescoberta (Maio de 2024)&lt;/h2&gt;

&lt;p&gt;Enquanto revia backups. Estou dando uma de Marie-Kondo em drives antigos quando um arquivo de 14 GB rotulado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tibia_auctions_2022.zip&lt;/code&gt; me encara. Does it spark joy? &lt;em&gt;Claro&lt;/em&gt;. E as ferramentas de AI explodiram desde 2022, então por que não terminar o trabalho?&lt;/p&gt;

&lt;h2 id=&quot;morte-por-mil-divs&quot;&gt;Morte por mil &amp;lt;div&amp;gt;s&lt;/h2&gt;

&lt;p&gt;Analisar aqueles arquivos HTML foi como lutar lidar contra 1.000 cortes de papel. Escrevi um pequeno snippet, &lt;strong&gt;html-scalpel&lt;/strong&gt;, que dividiu cada página em um dict, despejou-o em Parquet e fez inserções em bulk no SQLite. Sete horas depois, eu tinha:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;650 mil linhas&lt;/li&gt;
  &lt;li&gt;Mais de 40 campos brutos (level, vocation, outfits, mounts, quest flags…)&lt;/li&gt;
  &lt;li&gt;Dois alvos cruciais: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;final_bid&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bid_status&lt;/code&gt; (vendido vs. não-vendido com lance mínimo)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/alvaroinckot/tcaqs/blob/main/assets/cpu-usage-result.png?raw=true&quot; alt=&quot;cpu goes brrrr&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;temporada-de-modelos-xgboost-vs-meu-ego&quot;&gt;Temporada de modelos: XGBoost vs. meu ego&lt;/h2&gt;

&lt;p&gt;Prometi a mim mesmo &lt;strong&gt;90% R²&lt;/strong&gt; em dados de teste, o suficiente para passar em meu próprio teste de olfato Tibiano. Veja como isso se desenrolou:&lt;/p&gt;

&lt;h3 id=&quot;v1-baseline-e-checagem-de-realidade&quot;&gt;v1: Baseline e Checagem de Realidade&lt;/h3&gt;

&lt;p&gt;Comecei com as estatísticas óbvias: level, vocation, world type e um punhado de outros atributos numéricos, trinta colunas no total. Uma rápida busca em grade no XGBoost básico empurrou o R² de treinamento para além de 0,94, mas o R² de teste estacionou em 0,89 enquanto o MAPE oscilava por toda parte, especialmente em personagens de baixo level. O modelo estava memorizando o conjunto de treinamento e aprendendo pouco sobre preços do mundo real, útil apenas como base para trabalhos futuros.&lt;/p&gt;

&lt;h3 id=&quot;v2-empacotando-o-lore&quot;&gt;v2: Empacotando o Lore&lt;/h3&gt;

&lt;p&gt;Em seguida, adicionei as features que realmente impulsionam os preços do Tibia, como quest flags, mounts raros, outfits, hirelings e server type, todos codificados one-hot e reequilibrados. O ajuste de hiperparâmetros elevou o R² de teste para 0,94 e suavizou previsões para chars de médio a alto level. A nova fraquesa, no entanto, eram personagens de baixo level em servidores recém-abertos. Eles começam superfaturados porque os early adopters têm excesso de TC investido, depois caem rapidamente à medida que a economia do servidor amadurece, então seus valores reais flutuam mais rápido do que minha coleta estática poderia capturar, mantendo o MAPE alto nessa faixa.&lt;/p&gt;

&lt;h3 id=&quot;v3-eliminando-um-problema-crucial&quot;&gt;v3: Eliminando um problema crucial&lt;/h3&gt;

&lt;p&gt;O verdadeiro avanço veio de dados mais limpos, não de features extras. Muitos auctions terminando no lance mínimo não tinham comprador, então seus preços listados eram apenas um chute. Filtrando essas linhas, e reajustando o XGBoost, a curva de erro se achatou: o MAPE geral caiu para 0,42 (abaixo de 0,30 para chars abaixo de 100) e o R² de teste estabilizou em 0,935. O CatBoost pontuou quase o mesmo, mas consumiu mais VRAM, então XGBoost ainda é o campeão por enquanto.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/alvaroinckot/tcaqs/blob/main/assets/top-features.png?raw=true&quot; alt=&quot;Top Features&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;alguns-resultados&quot;&gt;Alguns resultados&lt;/h2&gt;

&lt;p&gt;A evolução da engenharia de features em números:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Model&lt;/th&gt;
      &lt;th&gt;Split&lt;/th&gt;
      &lt;th&gt;MSE&lt;/th&gt;
      &lt;th&gt;RMSE&lt;/th&gt;
      &lt;th&gt;MAE&lt;/th&gt;
      &lt;th&gt;MAPE&lt;/th&gt;
      &lt;th&gt;R2&lt;/th&gt;
      &lt;th&gt;Explained_Variance&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v1&lt;/td&gt;
      &lt;td&gt;Training&lt;/td&gt;
      &lt;td&gt;2289526.25&lt;/td&gt;
      &lt;td&gt;1513.12&lt;/td&gt;
      &lt;td&gt;703.37&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;0.9393&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v1&lt;/td&gt;
      &lt;td&gt;Testing&lt;/td&gt;
      &lt;td&gt;4209464.5&lt;/td&gt;
      &lt;td&gt;2051.7&lt;/td&gt;
      &lt;td&gt;857.07&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;0.8874&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v2&lt;/td&gt;
      &lt;td&gt;Training&lt;/td&gt;
      &lt;td&gt;543840.75&lt;/td&gt;
      &lt;td&gt;737.46&lt;/td&gt;
      &lt;td&gt;376.31&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;0.9856&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v2&lt;/td&gt;
      &lt;td&gt;Testing&lt;/td&gt;
      &lt;td&gt;2172790.25&lt;/td&gt;
      &lt;td&gt;1474.04&lt;/td&gt;
      &lt;td&gt;582.8&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;0.9419&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v2-es&lt;/td&gt;
      &lt;td&gt;Training&lt;/td&gt;
      &lt;td&gt;333324.59&lt;/td&gt;
      &lt;td&gt;577.3427&lt;/td&gt;
      &lt;td&gt;315.0486&lt;/td&gt;
      &lt;td&gt;0.4379&lt;/td&gt;
      &lt;td&gt;0.9912&lt;/td&gt;
      &lt;td&gt;0.9912&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v2-es&lt;/td&gt;
      &lt;td&gt;Testing&lt;/td&gt;
      &lt;td&gt;2140074.75&lt;/td&gt;
      &lt;td&gt;1462.8994&lt;/td&gt;
      &lt;td&gt;577.0405&lt;/td&gt;
      &lt;td&gt;0.5454&lt;/td&gt;
      &lt;td&gt;0.9427&lt;/td&gt;
      &lt;td&gt;0.9427&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v3&lt;/td&gt;
      &lt;td&gt;Training&lt;/td&gt;
      &lt;td&gt;49717.34&lt;/td&gt;
      &lt;td&gt;222.9739&lt;/td&gt;
      &lt;td&gt;149.1993&lt;/td&gt;
      &lt;td&gt;0.3372&lt;/td&gt;
      &lt;td&gt;0.9954&lt;/td&gt;
      &lt;td&gt;0.9954&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;results-v3&lt;/td&gt;
      &lt;td&gt;Testing&lt;/td&gt;
      &lt;td&gt;725773.25&lt;/td&gt;
      &lt;td&gt;851.9233&lt;/td&gt;
      &lt;td&gt;358.3552&lt;/td&gt;
      &lt;td&gt;0.4243&lt;/td&gt;
      &lt;td&gt;0.9349&lt;/td&gt;
      &lt;td&gt;0.9349&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;uma-bola-de-cristal-ao-vivo&quot;&gt;Uma bola de cristal ao vivo&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Demo&lt;/strong&gt;: &lt;a href=&quot;https://huggingface.co/spaces/alvaroinckot/tcaqs&quot;&gt;https://huggingface.co/spaces/alvaroinckot/tcaqs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Code&lt;/strong&gt;: &lt;a href=&quot;https://github.com/alvaroinckot/tcaqs&quot;&gt;https://github.com/alvaroinckot/tcaqs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Preencha as informações do personagem e obtenha uma estimativa. Sem mais adivinhações antes de gastar.&lt;/p&gt;

&lt;h2 id=&quot;o-que-vem-a-seguir&quot;&gt;O que vem a seguir?&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Nova coleta&lt;/strong&gt; – Nova vocation (Monk) e gold ajustado à inflação significa que o snapshot de 2022 está envelhecendo. Um crawler distribuído em SQS (ou qualquer outra fila) deve reduzir o scraping de semanas para dias.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Contexto de mercado&lt;/strong&gt; – Injetar CPI de level mundial para que o modelo acompanhe a inflação do gold.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Competição de modelos&lt;/strong&gt; – LightGBM, TabPFN, talvez um pequeno transformer tabular — porque não?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Dashboard público&lt;/strong&gt; – Índice diário de preço justo por vocation/world.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;xp-final&quot;&gt;XP final&lt;/h2&gt;

&lt;p&gt;Lançar o &lt;strong&gt;TCAQS&lt;/strong&gt; me lembrou que o glamour da AI repousa em fundações nada glamorosas: scraping obstinado, limpeza implacável e muitas barras de espera. Mas unir duas paixões de longa data: Tibia e machine learning, valeu cada &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;div&amp;gt;&lt;/code&gt;.&lt;/p&gt;

</description>
        <pubDate>Wed, 11 Jun 2025 04:00:00 +0000</pubDate>
        <link>https://www.alvaroinckot.com/posts/o-dia-em-que-construi-uma-ia-para-prever-precos-de-personagens-de-tibia</link>
        <guid isPermaLink="true">https://www.alvaroinckot.com/posts/o-dia-em-que-construi-uma-ia-para-prever-precos-de-personagens-de-tibia</guid>
        
        <category>pt-BR</category>
        
        
        <category>ai</category>
        
        <category>machine-learning</category>
        
      </item>
    
      <item>
        <title>Skip the Puzzle, Review the Pull Request</title>
        <description>&lt;p&gt;Generative copilots can already spit out textbook LeetCode answers on demand, which means the signal in those questions is evaporating. What remains scarce is the ability to read unfamiliar code, spot hidden risks, and articulate respectful feedback that guides it toward production quality. In other words, review skill is becoming the clearest proxy for day-zero impact on a codebase, and companies that keep filtering only for algorithm speed will keep mistaking autocomplete for engineering judgment.&lt;/p&gt;

&lt;p&gt;This is not about handing candidates a random diff and asking for a style nitpick. A thoughtful review exercise can act as a safe wrapper around a genuine business puzzle: think of a simplified service the team owns, a flaw that recently made it to staging, and a follow-up request from product that forces a design rethink. Give the candidate the context, the failing test, and the freedom to propose a patch or a rewrite. You will see whether they weigh tradeoffs, align with conventions, and offer incremental steps the team could actually merge, all of which map directly to what the role needs on week one. Yes, it costs staff time to craft and maintain these scenarios, but the payoff is hiring engineers who walk into onboarding already fluent in how the company writes software.&lt;/p&gt;

&lt;p&gt;A recent side project drove this home for me. I was sketching a model to price collectible RPG characters (post coming soon.) and let o3 suggest a feature set and algorithm lineup. The reply read like a drinking fountain menu: token count, embedding vectors, gradient boosting, everything evenly chilled. None of it captured the lore quirks that drive bids, quirks I recognized only after years of raiding dungeons and reading forum drama. When I embedded those domain signals the model finally sang. A review-first interview can surface that sort of tacit knowledge because the candidate explains the why behind each line, not only the what.&lt;/p&gt;

&lt;p&gt;Until a true general intelligence can blend raw computation with the lived nuance of every market on earth, we should make the most of this gap. Shift interview energy toward code and pull request review, and invest the effort to craft realistic scenarios that mirror your production beating heart. &lt;strong&gt;The next generation of agentic AI coders will pair brilliantly with humans who excel at critique and context, and those are exactly the engineers you will attract.&lt;/strong&gt; While we do not have AGI, this meantime would be good to do it.&lt;/p&gt;
</description>
        <pubDate>Thu, 29 May 2025 04:00:00 +0000</pubDate>
        <link>https://www.alvaroinckot.com/posts/skip-the-puzzle-review-the-pull-request</link>
        <guid isPermaLink="true">https://www.alvaroinckot.com/posts/skip-the-puzzle-review-the-pull-request</guid>
        
        <category>en-US</category>
        
        
        <category>braindump</category>
        
      </item>
    
      <item>
        <title>Hacking Moleculer and Building Pylecular: A Journey into ML/AI Microservices</title>
        <description>&lt;p&gt;Pylecular started as a genuine experiment. I wanted to combine my background in distributed systems with the lessons I had learned working with &lt;a href=&quot;https://moleculer.services/&quot;&gt;Moleculer.js&lt;/a&gt; a few years back. The goal wasn’t to build a framework or replace anything, it was to see what would happen if I took a powerful, event-driven microservice model and blended it with Python’s machine learning ecosystem.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Check Pylecular at: &lt;a href=&quot;https://github.com/alvaroinckot/pylecular&quot;&gt;https://github.com/alvaroinckot/pylecular&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Python is already rich with ML tools. What it often lacks is a simple, expressive way to plug those tools into a distributed architecture. I was curious: could I take the things Moleculer does so well: brokers, actions, events, services; and apply them in a Pythonic way, letting models and data flows behave like modular agents? Could I create something that made it easier to spin up small, reactive ML systems, without the ceremony of setting up an entire platform?&lt;/p&gt;

&lt;p&gt;I wasn’t trying to solve every problem. I just wanted to connect what I already knew and see how far I could push it.&lt;/p&gt;

&lt;p&gt;Moleculer’s core concept is clean and effective: services register actions, and those actions can be called across the system via a central broker. No HTTP routes, no external APIs, just names and messages.&lt;/p&gt;

&lt;p&gt;Like this:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;broker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And then:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;broker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;math.add&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Simple. Modular. Event aware by default.&lt;/p&gt;

&lt;p&gt;This wasn’t just about reimplementing a concept in Python. One of the design goals is full interoperability with existing Moleculer services written in Node.js. That means a service written in Python using Pylecular can call actions or emit events to a Node.js Moleculer service, and vice versa. They speak the same protocol. They use the same service and action structure.&lt;/p&gt;

&lt;p&gt;This is important because the Moleculer ecosystem is already rich. It has proven patterns for service discovery, load balancing, fault tolerance, and more. There is a whole world of tooling built around it, from API gateways to metrics to transporters like NATS or Redis. With Pylecular, you do not have to start from scratch. You can build Python native ML services that plug directly into that ecosystem and start benefiting from it immediately.&lt;/p&gt;

&lt;p&gt;At this point, I wasn’t trying to innovate. I was trying to learn. Rebuild the mechanism. Understand the gears.&lt;/p&gt;

&lt;p&gt;Here’s what a Pylecular service looks like, inspired by Moleculer’s simplicity:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pylecular.service&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Service&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pylecular.decorators&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MathService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;math&quot;&lt;/span&gt;

    &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And the call:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;broker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;math.add&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It worked.&lt;/p&gt;

&lt;p&gt;Once the core pattern was there, I started thinking about what else it could do.&lt;/p&gt;

&lt;p&gt;That’s when I wrapped a model.&lt;/p&gt;

&lt;p&gt;Just a basic LinearRegression. I gave it a predict method, exposed that as an action, and registered it with the broker.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sklearn.linear_model&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LinearRegression&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MLService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ml&quot;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]])&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LinearRegression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;predict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]])[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, any part of the system could say: “Hey, ml.predict, what’s your answer for x equals 4?”&lt;/p&gt;

&lt;p&gt;No HTTP. No Flask. No REST. Just call the model.&lt;/p&gt;

&lt;p&gt;And then I thought, what if it could also listen?&lt;/p&gt;

&lt;p&gt;In Moleculer, and now in Pylecular, services don’t just respond. They listen. They emit. They react.&lt;/p&gt;

&lt;p&gt;So I added events.&lt;/p&gt;

&lt;p&gt;Imagine this: when a model finishes training, it emits model.trained. Another service, maybe a dashboard or a cache invalidator, is subscribed to that. It reacts in real time.&lt;/p&gt;

&lt;p&gt;In Pylecular, that looks like:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pylecular.decorators&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;model.trained&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handle_trained&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;New model trained. Refreshing cache...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And just like that, your system becomes alive.&lt;/p&gt;

&lt;p&gt;Models aren’t just endpoints. They’re agents. They participate in workflows, listen to signals, respond to change.&lt;/p&gt;

&lt;p&gt;This is what excited me. This was the architecture I wanted.&lt;/p&gt;

&lt;p&gt;Serving ML models isn’t just about exposing a function. It’s about integrating into a system that can adapt, scale, and respond in real time. And doing it in Python, where most ML tooling already lives, makes the entire process feel native.&lt;/p&gt;

&lt;p&gt;With this foundation, I began to imagine what Pylecular could be.&lt;/p&gt;

&lt;p&gt;It’s not trying to be the next ML platform. It’s not even trying to be the next FastAPI or Ray Serve. What it does is make it trivially easy to treat a model as a service. And that service becomes part of a larger network of components, data ingestors, trainers, notifiers, loggers, dashboards, all communicating through actions and events.&lt;/p&gt;

&lt;p&gt;Suddenly, spinning up a minimal ML platform isn’t a two month project. It’s a matter of defining a few services, connecting them through the broker, and letting events flow.&lt;/p&gt;

&lt;p&gt;That modularity accelerates innovation. You can prototype faster, test new ideas, and integrate external tools easily. Want to swap one model for another? Just change the service. Want to broadcast that a new dataset is available? Emit an event. Everything stays decoupled and composable.&lt;/p&gt;

&lt;p&gt;This aligns closely with a modern platform strategy: accelerating innovation through modularity, enabling reuse and leveraging across teams, and pushing routine operations like predictions into the realm of commoditization, something cheap, fast, and reliable.&lt;/p&gt;

&lt;p&gt;And here’s where it gets even more interesting.&lt;/p&gt;

&lt;p&gt;Pylecular naturally aligns with the goals of the &lt;a href=&quot;https://modelcontextprotocol.io/introduction&quot;&gt;Model Context Protocol&lt;/a&gt;. With its Moleculer inspired service registry and event system, services can be dynamically discovered and composed. Tools, models, and workflows become addressable pieces within a shared protocol space. This opens the door for true composability, where each ML component is not just a script or container but a named, living service in the context of a wider system.&lt;/p&gt;

&lt;p&gt;There are mature and powerful tools out there” Kubeflow, KServe, LangChain, and other. They are designed for robustness, scalability, and reliability. They’re essential when the stakes are high and the systems are complex.&lt;/p&gt;

&lt;p&gt;But what about the hackers? The builders who want to spin something up tonight just to see if it works? The people who learn by stress testing ideas and connecting small pieces to see what breaks and what surprises them?&lt;/p&gt;

&lt;p&gt;That’s what Pylecular is for. It’s a playground, not a platform. A way to stretch the tools I already have, to see how far I can take a simple broker, a model, and some events.&lt;/p&gt;

&lt;p&gt;It’s early. It’s messy. But it’s fun.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Models as a service, systems as conversations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And it’s open source. &lt;a href=&quot;https://github.com/alvaroinckot/pylecular&quot;&gt;&lt;strong&gt;&lt;em&gt;Check it out&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;. Play with it. Hack it. Break it.&lt;/p&gt;
</description>
        <pubDate>Mon, 19 May 2025 04:00:00 +0000</pubDate>
        <link>https://www.alvaroinckot.com/posts/hacking-moleculer-and-building-pyleculer-ml-ai-microservices</link>
        <guid isPermaLink="true">https://www.alvaroinckot.com/posts/hacking-moleculer-and-building-pyleculer-ml-ai-microservices</guid>
        
        <category>python</category>
        
        <category>moleculer</category>
        
        <category>pylecular</category>
        
        <category>ml</category>
        
        <category>microservices</category>
        
        <category>en-US</category>
        
        
        <category>microservices</category>
        
        <category>machine-learning</category>
        
      </item>
    
      <item>
        <title>A Chip in a hand</title>
        <description>&lt;p&gt;Six years ago, on a muggy October afternoon in 2019, I walked out of a downtown piercing studio with thirteen millimeters of bioglass and copper sealed beneath the web of skin between my thumb and index finger. The installer wiped away a single bead of blood, snapped off his gloves, and the future settled quietly into my hand.&lt;/p&gt;

&lt;p&gt;The first week was all antiseptic soap and subconscious flinches, little reminders that I‘d just invited hardware to live under my skin. By day ten the swelling was gone; by day thirty I needed the reflection of a phone screen to find the scar. What never faded was the shiver of delight every time a phone buzzed and my personal site bloomed on‑screen. Tap‑to‑URL felt like teleporting a business card straight into someone’s pocket. I locked the tag read‑only on day one, so five years later it still points to the same URL, unaltered.&lt;/p&gt;

&lt;p&gt;Somewhere between changing bandages and high‑fiving friends, I tumbled head‑first into radio‑frequency nerd‑land: late nights dissecting MIFARE command frames, exploring how protocol quirks can be harnessed for stronger security, and occasionally frying Arduino boards with over‑ambitious antenna builds. Curiosity spilled outward: satellite downlink specs, long‑distance RFID tags, &lt;em&gt;any scheme that pushed bits through the air&lt;/em&gt;. The implant turned from party trick to portal, opening an invisible playground every time I powered up the SDR.&lt;/p&gt;

&lt;p&gt;Phones caught up, too. Back in 2019, iPhones needed an app; nowadays a casual bump works out of the lock screen. Most people react with a grin, some with worry, a few with envy, especially when they realise the implant cost less than a dinner in Orlando and never runs out of battery. Occasionally a security guard wants to see ID after the trick; I hand them my plastic card, smile, and wonder which credential really proves more.&lt;/p&gt;

&lt;p&gt;I get asked if I’d do it again. The honest answer is that I already forget it’s there, until I’m shaking hands at a meetup and someone’s phone chirps. In that instant it’s 2019 all over again, and I’m reminded that technology feels magical only when we’re brave enough to let it cross the skin‑boundary.&lt;/p&gt;

&lt;p&gt;The next implant? Probably one that unlocks my front door and kicks on the coffee machine as I step inside. Once you’ve embedded one line of code under your skin, adding a few more feels inevitable.&lt;/p&gt;
</description>
        <pubDate>Tue, 13 May 2025 04:00:00 +0000</pubDate>
        <link>https://www.alvaroinckot.com/posts/a-chip-in-a-hand</link>
        <guid isPermaLink="true">https://www.alvaroinckot.com/posts/a-chip-in-a-hand</guid>
        
        <category>en-US</category>
        
        
        <category>braindump</category>
        
      </item>
    
  </channel>
</rss>
