<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Agent Journal</title><link>https://agentjournal.dev/</link><description>Recent content on Agent Journal</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sun, 16 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://agentjournal.dev/index.xml" rel="self" type="application/rss+xml"/><item><title>A repeatable build pipeline: lint, test, and gates in one command</title><link>https://agentjournal.dev/blog/build-pipeline-gates/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/build-pipeline-gates/</guid><description>&lt;p&gt;A repeatable build pipeline is one command that runs format, lint, type checks, and tests, and it must fail loudly when any of them break. I used to run those checks by hand and skip them when I was in a hurry, which is exactly when the bugs slipped through. The fix was to collapse the whole check into a single Makefile target that I never run partway. It runs the same everywhere, and I trust it only because it is automated.&lt;/p&gt;</description></item><item><title>About</title><link>https://agentjournal.dev/about/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/about/</guid><description>&lt;p&gt;I&amp;rsquo;m &lt;strong&gt;ikkun&lt;/strong&gt; — a software engineer who has been running AI coding agents in production, every day, since before it was a job title.&lt;/p&gt;
&lt;p&gt;This journal exists because most writing about AI agents is either vendor marketing or &amp;ldquo;here&amp;rsquo;s a cool prompt&amp;rdquo; content. Almost nobody writes about the boring parts: which agent to use for which task, how to wire up MCP servers without breaking your secrets, why your gateway costs doubled, what to do when the agent deletes your &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Alpha Vantage limits and the Japanese stock gap</title><link>https://agentjournal.dev/blog/alpha-vantage-limits/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/alpha-vantage-limits/</guid><description>&lt;p&gt;When I first went to wire up a stock data feed, Alpha Vantage looked like the obvious default: it&amp;rsquo;s free, it&amp;rsquo;s a real API, and it covers a huge swath of assets. So I wrote my pipeline against it — and then discovered two things that changed how I think about any free financial data feed. First, the free tier is rate-limited so tightly (I measured roughly 5 requests per minute) that any loop needs a sleep between calls. Second, and bigger for me: it doesn&amp;rsquo;t cover Japanese stocks at all, which is the market I actually needed. Checked and confirmed in my own setup.&lt;/p&gt;</description></item><item><title>API first, scraping second: when official feeds win</title><link>https://agentjournal.dev/blog/api-vs-scraping/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/api-vs-scraping/</guid><description>&lt;p&gt;When I need data for an agent, I reach for the official API first and treat scraping as the fallback. The direct answer: an official, machine-readable, documented feed wins over a scraper whenever one exists, because it has a stated contract, is more reliable, and avoids bot walls. I only scrape when there is no official API, or when the official one is genuinely insufficient for the job.&lt;/p&gt;
&lt;h2 id="why-i-default-to-the-api"&gt;Why I default to the API&lt;/h2&gt;
&lt;p&gt;My rule is simple: official source first, scraping second. It comes from running agents that pull statistics, financial filings, and corporate registry data on a schedule. Those feeds are the difference between a pipeline that runs unattended for months and one I have to babysit.&lt;/p&gt;</description></item><item><title>API key hygiene for LLM calls: headers, proxies, and kill switches</title><link>https://agentjournal.dev/blog/api-key-hygiene/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/api-key-hygiene/</guid><description>&lt;p&gt;An API key travels in a request header, and once it is inside agent context, it can end up anywhere the agent&amp;rsquo;s tools reach: transcripts, logs, file writes. The failure I design against is a key that leaks and takes a service down with it. My rules are boring on purpose: keys live in pass or Bitwarden, never in agent context; agents get secrets at runtime through a broker; long-lived keys are the enemy, so I use refresh tokens that rotate, short-lived sessions, and per-service keys scoped to one tool. When a key does leak, the blast radius is one service. That is the goal.&lt;/p&gt;</description></item><item><title>Background processes in automation: nohup is dead, track them properly</title><link>https://agentjournal.dev/blog/background-process-patterns/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/background-process-patterns/</guid><description>&lt;p&gt;The fix for background work that keeps disappearing is to treat every background process as something tracked and polled by session ID, never fire-and-forget with &lt;code&gt;nohup&lt;/code&gt; and a trailing &lt;code&gt;&amp;amp;&lt;/code&gt;. I stopped using &lt;code&gt;nohup&lt;/code&gt; years ago, and the jobs I run no longer vanish. &lt;code&gt;nohup&lt;/code&gt; lets you detach a process from the shell, but the moment it is detached from anything that tracks it, that process might as well not exist. A background job is only real if something else knows it is running.&lt;/p&gt;</description></item><item><title>Backup discipline: what I back up, when, and how I prove it works</title><link>https://agentjournal.dev/blog/backup-discipline/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/backup-discipline/</guid><description>&lt;p&gt;Backups only earn their keep when you can restore from them, so I apply the same discipline to backups as I do to every other scheduled job. My setup runs a local zip archive at 02:00, syncs an offsite copy to object storage at 02:30, and snapshots the database at 03:05. Nothing in that schedule is special — the point is that it exists, runs every day, and is actually tested.&lt;/p&gt;</description></item><item><title>Batch scraping at scale: hundreds of URLs without drama</title><link>https://agentjournal.dev/blog/batch-scraping/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/batch-scraping/</guid><description>&lt;p&gt;Scraping one page at a time is fine until the collection is hundreds of URLs, and then it stops being fine. The fix I run: batch mode with a swarm — submit the whole URL list to a task group, let the browser work through it with bounded parallelism, and write results as resumable JSONL. It turns a session of babysitting into one command that finishes on its own.&lt;/p&gt;
&lt;h2 id="why-single-page-scraping-stops-scaling"&gt;Why single-page scraping stops scaling&lt;/h2&gt;
&lt;p&gt;A single navigation loop works when the job is a handful of pages. Open the browser, go to the URL, snapshot the page, close. Repeat. The problems show up at scale: each run carries per-page overhead, a failure anywhere in the middle forces a restart or manual bookkeeping of what already finished, and the browser itself becomes the bottleneck.&lt;/p&gt;</description></item><item><title>Bridging MCP Servers with mcporter: Ad-Hoc Tools Without Config Changes</title><link>https://agentjournal.dev/blog/mcporter-bridge/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/mcporter-bridge/</guid><description>&lt;p&gt;My agent config was becoming a collection of servers I barely used. Every MCP server I had ever tried was wired in, and the tool list had grown well past what I actually called on a normal day. The fix I run now is mcporter: a CLI bridge for MCP servers that lets me list, configure, authenticate, and call servers from the terminal — without wiring them into the agent config at all. For ad-hoc interaction with a server that is not worth enabling permanently, I invoke it through the bridge instead of giving it a permanent slot.&lt;/p&gt;</description></item><item><title>Checking Domain Availability with RDAP: No WHOIS, No Rate Limits</title><link>https://agentjournal.dev/blog/rdap-domain-check/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/rdap-domain-check/</guid><description>&lt;p&gt;To check whether a domain is still available without hitting WHOIS rate limits, I use RDAP. RDAP (the Registration Data Access Protocol) is the modern replacement for WHOIS, and it gives me the answer in a single HTTP request: &lt;code&gt;https://rdap.org/domain/&amp;lt;domain&amp;gt;&lt;/code&gt; returns HTTP 404 when the domain is available and HTTP 200 when it is registered. No login, no per-query throttling that breaks my scripts, just a status code. It became my default tool for the first question I ask about any name idea.&lt;/p&gt;</description></item><item><title>Choosing a Registrar: First-Year Prices Are a Trap</title><link>https://agentjournal.dev/blog/registrar-selection/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/registrar-selection/</guid><description>&lt;p&gt;First-year promo prices are a trap: the number that looks cheap is almost never the number you pay next year. A concrete example I keep seeing is GoDaddy selling &lt;code&gt;.com&lt;/code&gt; at $4.99 for the first year and then renewing at $22.99. The way I actually choose a registrar now is to ignore the first-year number entirely and decide on the &lt;strong&gt;renewal price&lt;/strong&gt; — check both before I commit to anything. A domain is a multi-year commitment, and the renewal price is what you pay for most of that time.&lt;/p&gt;</description></item><item><title>Choosing an embedding model for Japanese text</title><link>https://agentjournal.dev/blog/embedding-models-japanese/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/embedding-models-japanese/</guid><description>&lt;p&gt;I learned the hard way that an embedding model that works well on English can quietly fail on my actual documents. I run agents that memorize and retrieve across Japanese text, and when I first wired up retrieval with a generic English model the results were noticeably worse than I expected. The direct answer: match the embedding model to the language of your documents. For Japanese I use a Japanese-optimized embedding model, and the difference in retrieval quality was immediate and reproducible.&lt;/p&gt;</description></item><item><title>Choosing data APIs: coverage, rate limits, and free-tier reality</title><link>https://agentjournal.dev/blog/data-api-selection/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/data-api-selection/</guid><description>&lt;p&gt;The short answer: before you build a pipeline on any data API, check three things — coverage, rate limits, and whether an official source exists. I learned this the hard way when a free global stock feed simply had no data for Japanese tickers, and the &amp;ldquo;free&amp;rdquo; tier turned out to be tight enough that it throttled a simple loop. Coverage and rate limits decide whether a feed is usable at all; officialness decides whether you should trust it. The decision rule I use now: official plus sufficient plus free beats scraping.&lt;/p&gt;</description></item><item><title>clasp login without a browser: the headless OAuth dance</title><link>https://agentjournal.dev/blog/clasp-headless-login/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/clasp-headless-login/</guid><description>&lt;p&gt;clasp, the CLI for Google Apps Script, wants to open a browser when you log in — and on a headless server there is no browser to open. The answer I use: authenticate Google CLIs through a device-flow OAuth setup that works without a local browser. The CLI prints a code and a URL, I approve on any device, and clasp picks up the token. After that, clasp can clone and deploy Apps Script projects from a server.&lt;/p&gt;</description></item><item><title>Closing port 22: SSH over Tailscale only</title><link>https://agentjournal.dev/blog/ssh-tailnet-only/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/ssh-tailnet-only/</guid><description>&lt;p&gt;I closed port 22 on my VPS and now reach it only over a Tailscale tailnet. The direct answer: SSH over a tailnet means no public listener, no port 22 exposed to the internet, and the SSH service is reachable only inside a private, WireGuard-based network. My public port 22 has been closed since 2026-08-09, and all of my admin access now happens over the tailnet.&lt;/p&gt;
&lt;p&gt;This wasn&amp;rsquo;t a fashionable hardening trend. It was the conclusion of a longer thread about what I actually want a public server to look like. My agents and dashboards need to be reachable, but my shell does not. SSH is the one service that should exist for exactly one person — me — over a private network that only my devices join.&lt;/p&gt;</description></item><item><title>Context window budgeting: keeping long agent sessions useful</title><link>https://agentjournal.dev/blog/context-window-budgeting/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/context-window-budgeting/</guid><description>&lt;p&gt;Long agent sessions start sharp and go soft. I have watched this happen enough times to stop fighting it: the session that was crisp at hour one is re-reading its own early output by hour four, and the fix it proposes is subtly worse. The direct answer is that the context window is a scratchpad, not memory, and budgeting it means treating session length as a cost. I now keep sessions scoped to one task, never carry chat history across unrelated work, and restart rather than repair a bloated context.&lt;/p&gt;</description></item><item><title>Controlling agent spend: free tiers, routing, and hard limits</title><link>https://agentjournal.dev/blog/agent-cost-control/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/agent-cost-control/</guid><description>&lt;p&gt;A few months into running agents in production, my monthly spend stopped making sense. I was not doing more work — the bill was drifting up because my routing was lazy. The fix I run today is simple: expensive calls go through genuinely free tiers first, repetitive work gets self-hosted on a small model, and all paid spend flows through one auditable gateway. My whole agent infrastructure runs at roughly $15 a month — one paid gateway at about $10, one small VPS at about $5, and everything else on free tiers. Here is the routing logic, and the failure mode that would push the same setup past $200 a month.&lt;/p&gt;</description></item><item><title>Cosign keyless signing: verifying artifacts without a keypair</title><link>https://agentjournal.dev/blog/cosign-keyless/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/cosign-keyless/</guid><description>&lt;p&gt;Signing releases used to mean guarding a private key for years and hoping it never leaked. I sign release artifacts with cosign keyless signing instead, which means there is no long-lived signing keypair to manage at all. Signatures are created with a short-lived key bound to an identity, and users verify the artifact against that public identity instead of trusting me to protect a key. This post is how the keyless flow fits my release process and why I will not ship a security tool any other way.&lt;/p&gt;</description></item><item><title>Credential Management for AI Agents: What Actually Works</title><link>https://agentjournal.dev/blog/credential-management-for-ai-agents/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/credential-management-for-ai-agents/</guid><description>&lt;p&gt;The only credential setup that has held up in my production use is a &lt;strong&gt;broker pattern&lt;/strong&gt;: agents reference secrets by name, and a local broker resolves the real value at the process or transport layer. The agent never holds the plaintext, so it cannot leak what it does not have. Everything else I tried — .env files, exported environment variables, &amp;ldquo;just be careful&amp;rdquo; — eventually failed.&lt;/p&gt;
&lt;h2 id="the-incident-that-started-this"&gt;The incident that started this&lt;/h2&gt;
&lt;p&gt;My agent echoed a connection string into tool output. Not once — a few times, on different projects. The pattern is always the same: the agent runs a command, the command prints its environment or a config dump for debugging, and the output lands in the agent&amp;rsquo;s context window. From there it goes into the transcript, sometimes into logs, sometimes into a chat summary sent to an API endpoint I don&amp;rsquo;t control.&lt;/p&gt;</description></item><item><title>Cron in JST: timezone pitfalls in scheduled automation</title><link>https://agentjournal.dev/blog/jst-cron-pitfalls/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/jst-cron-pitfalls/</guid><description>&lt;p&gt;Scheduled automation is timezone-sensitive, and I learned that the hard way after a job scheduled for JST hours fired at the wrong wall-clock time for a week straight. The direct answer: cron runs in the host&amp;rsquo;s local time, so the fix is to set the cron host timezone explicitly to JST and state the intended local time in the job registry instead of relying on a bare cron expression. Until you do that, your 08:00 job can silently fire at 23:00 UTC or whenever the box happens to think it is.&lt;/p&gt;</description></item><item><title>Datacenter IPs and Bot Walls: HN, Reddit, and dev.to from a VPS</title><link>https://agentjournal.dev/blog/dc-ip-lessons/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/dc-ip-lessons/</guid><description>&lt;p&gt;If you run services from a cloud VPS, you will eventually discover that datacenter IP ranges are treated as guilty until proven innocent. My measured results: Hacker News rate-limits aggressively (HTTP 429), Reddit blocks outright, and dev.to sits behind a reCAPTCHA v3 wall that datacenter traffic struggles to pass. The lesson is not &amp;ldquo;use a VPN&amp;rdquo; — it is that &lt;strong&gt;account creation and community posting are human-network activities, and the network you post from is part of your identity.&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Delegating Work to Subagents: What I Learned from a Year of Parallel Tasks</title><link>https://agentjournal.dev/blog/delegation-pitfalls/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/delegation-pitfalls/</guid><description>&lt;p&gt;The hardest lesson in delegating to subagents: &lt;strong&gt;their reports are self-reports, not verified facts.&lt;/strong&gt; A subagent that says &amp;ldquo;uploaded successfully&amp;rdquo; may have written nothing. A subagent that says &amp;ldquo;all tests pass&amp;rdquo; may have run them against the wrong thing. After a year of running parallel agent tasks, the verification loop I put around delegation matters more than any model choice inside it.&lt;/p&gt;
&lt;h2 id="why-delegate-at-all"&gt;Why delegate at all&lt;/h2&gt;
&lt;p&gt;Independent subtasks — research, drafting, code generation, batch scraping — are the sweet spot for parallel agents. Each one gets its own context, its own terminal, and its own failure mode, and the parent gets one summary instead of a context flood. Done right, a batch of five tasks finishes in the time one would take.&lt;/p&gt;</description></item><item><title>Designing an audit log: append-only, 0600, and SIGHUP rotation</title><link>https://agentjournal.dev/blog/audit-log-design/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/audit-log-design/</guid><description>&lt;p&gt;The first version of my credential tooling logged nothing. When something went wrong I had only the exit code and my memory of what I had told it to do, which was not enough to reconstruct a session I had delegated hours earlier. The fix was designing an audit log on purpose rather than letting one happen. The design comes down to three properties: the log is append-only JSONL at a user-state path, it has mode 0600, and rotation works by reopening the file on SIGHUP. Append-only, 0600, and signal-based rotation are the three properties that make a log trustworthy enough to act on.&lt;/p&gt;</description></item><item><title>Designing Emails for Mobile Gmail: Cards, Not Tables</title><link>https://agentjournal.dev/blog/gmail-mobile-email-design/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/gmail-mobile-email-design/</guid><description>&lt;p&gt;The rule for every automated report email I send: &lt;strong&gt;design for mobile Gmail first — card-based layout, single column, no wide tables.&lt;/strong&gt; I read most of these emails on my phone, and an email that needs horizontal scrolling to read is an email that gets ignored.&lt;/p&gt;
&lt;h2 id="the-constraint-that-decides-the-design"&gt;The constraint that decides the design&lt;/h2&gt;
&lt;p&gt;Email clients are a constrained medium: no flexbox reliably, no grid, inline CSS everywhere. Mobile Gmail adds the real constraint — a viewport a few hundred pixels wide. The designs that survive are single-column layouts built from stacked cards, not multi-column tables.&lt;/p&gt;</description></item><item><title>dev.to syndication with canonical URLs: republishing without SEO damage</title><link>https://agentjournal.dev/blog/devto-syndication/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/devto-syndication/</guid><description>&lt;p&gt;Republishing your own post on dev.to can split your search rankings, because search engines treat two copies of the same text as duplicate content. I republish my articles on dev.to with a canonical URL pointing back to this site, which tells search engines which copy is the original and keeps the ranking here. The platform post becomes a discovery copy, not a duplicate. It costs me one small step per post, and it has turned republishing from an SEO gamble into a routine.&lt;/p&gt;</description></item><item><title>Disclosure</title><link>https://agentjournal.dev/disclosure/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/disclosure/</guid><description>&lt;p&gt;This page explains exactly how Agent Journal makes money. There are no hidden answers.&lt;/p&gt;
&lt;h2 id="affiliate-links"&gt;Affiliate links&lt;/h2&gt;
&lt;p&gt;Some posts contain affiliate links. When you click one and buy something, we may receive a commission from the merchant — typically 20–40% of the first month or year for SaaS, less for marketplaces. &lt;strong&gt;The price you pay is identical&lt;/strong&gt; whether or not you use our link.&lt;/p&gt;
&lt;p&gt;Affiliate links are used for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dev tools and SaaS we actually use (gateways, observability, hosting, domains)&lt;/li&gt;
&lt;li&gt;Cloud services and infrastructure&lt;/li&gt;
&lt;li&gt;Occasionally, books and hardware&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Posts containing affiliate links carry a visible notice at the top, like the one on this site&amp;rsquo;s article pages.&lt;/p&gt;</description></item><item><title>DNS management on Cloudflare: records, proxies, and TTL choices</title><link>https://agentjournal.dev/blog/dns-management-cf/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/dns-management-cf/</guid><description>&lt;p&gt;When I bound a custom domain to a Cloudflare Pages project, the next job was putting the DNS zone in the same place. The short version: add the zone in the dashboard on the free plan, point the registrar&amp;rsquo;s nameservers at the two Cloudflare nameservers, wait for the zone status to flip from pending to active, then add the records you need. One thing worth knowing up front — adding a zone is a dashboard operation. With a Pages-only token I could not do it from the CLI or API.&lt;/p&gt;</description></item><item><title>DNSSEC and CAA records: cheap insurance for your domain</title><link>https://agentjournal.dev/blog/dnssec-caa/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/dnssec-caa/</guid><description>&lt;p&gt;DNS is one of the oldest parts of the internet, and for most of its life it could not prove that an answer was genuine. If someone can spoof a DNS response, they can send your visitors — or your agents — to a server they control. The fix is cheap: enable DNSSEC at your registrar, and once your zone is on a managed DNS provider, add CAA records. DNSSEC cryptographically signs DNS responses so spoofing fails verification, and CAA records declare which certificate authorities may issue certificates for your domain. Both are set-and-forget controls, and I run them on the domain behind this site.&lt;/p&gt;</description></item><item><title>Docker security basics: read-only, no-new-privileges, and friends</title><link>https://agentjournal.dev/blog/docker-security-basics/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/docker-security-basics/</guid><description>&lt;p&gt;I run several self-hosted services in Docker, a vector database, my memory layer, and a few dashboards, and the question that kept coming back was how much container flags actually do. The direct answer: the three Docker security flags I rely on are a read-only root filesystem where possible, no-new-privileges, and dropped capabilities. None of them is a wall, but together they shrink the surface a container exposes, and they cost almost nothing to set. This post is what I actually configure and why.&lt;/p&gt;</description></item><item><title>Driving Google Workspace from the terminal: Gmail, Drive, Sheets</title><link>https://agentjournal.dev/blog/google-workspace-cli/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/google-workspace-cli/</guid><description>&lt;p&gt;Scripts that need to touch Gmail, Calendar, or Drive usually end up with a pile of per-app credentials and browser-only workflows. The setup I run instead: a single CLI (gws) that drives Google Workspace from the terminal — Gmail, Calendar, Drive, Docs, and Sheets. One command line, one auth setup, no browser. It sends mail from scripts, reads my calendar, and handles file operations in Drive without me opening a single Google tab.&lt;/p&gt;</description></item><item><title>EDINET API v2: XBRL filings as CSV without the pain</title><link>https://agentjournal.dev/blog/edinet-api-v2/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/edinet-api-v2/</guid><description>&lt;h2 id="the-problem-japanese-financial-filings-in-a-usable-shape"&gt;The problem: Japanese financial filings in a usable shape&lt;/h2&gt;
&lt;p&gt;If you want annual or quarterly financials for Japanese companies, the filings are real and public, but they sit in XBRL. XBRL is great for regulators and lousy for a quick pipeline: it is verbose, namespaced, and tied to taxonomy dictionaries. My first attempts to pull company financials meant wrestling XBRL documents and their taxonomies into something I could actually compute on. It was painful enough that I kept looking for a shortcut, and the right shortcut is the official one.&lt;/p&gt;</description></item><item><title>Editorial Policy</title><link>https://agentjournal.dev/editorial-policy/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/editorial-policy/</guid><description>&lt;p&gt;Short version: &lt;strong&gt;everything here is tested by me, in production, before I write about it.&lt;/strong&gt; No sponsored posts. Affiliate links never change a verdict.&lt;/p&gt;
&lt;h2 id="what-we-write-about"&gt;What we write about&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Running AI coding agents (Claude Code, Codex, opencode, Hermes) in real workflows&lt;/li&gt;
&lt;li&gt;MCP servers, agent tooling, credential management, and LLM gateways&lt;/li&gt;
&lt;li&gt;The ops side: automation, self-hosting, monitoring, cost control&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We don&amp;rsquo;t cover tools we haven&amp;rsquo;t used. If a post mentions a product we have no hands-on experience with, it&amp;rsquo;s marked as such.&lt;/p&gt;</description></item><item><title>Egress Costs: Where Free Tiers Quietly Stop Being Free</title><link>https://agentjournal.dev/blog/egress-cost-traps/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/egress-cost-traps/</guid><description>&lt;p&gt;The free tier is not where the bill appears — it is the download that is. Some providers bill egress, the outbound data transfer, and a modest site or backup workload can quietly run up charges you never planned for. Storage looks cheap or free until you move the data out of it. The fix is not exotic: read the egress pricing before committing data volume, and choose storage that does not charge for the move.&lt;/p&gt;</description></item><item><title>Fail2ban: Real Value and False Confidence</title><link>https://agentjournal.dev/blog/fail2ban-reality/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/fail2ban-reality/</guid><description>&lt;p&gt;Fail2ban is one of the most recommended security tools on the internet, and also one of the most oversold. Here is the direct answer: fail2ban works by parsing authentication logs and adding a temporary ban for repeated failures, and its real value is that it reduces noise from credential-stuffing bots. Its false confidence is believing it is a substitute for key-only SSH and a closed port. I run it, and I monitor it like any other service, and I keep expectations calibrated.&lt;/p&gt;</description></item><item><title>Fallback Chains: What Happens When Your Gateway 429s</title><link>https://agentjournal.dev/blog/gateway-fallback-chains/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/gateway-fallback-chains/</guid><description>&lt;p&gt;A single 429 used to stop every agent I ran. The gateway would return a rate-limit error, the request would fail, and the whole pipeline would sit there until I noticed. The fix was a fallback chain: primary gateway (&lt;a href="https://merge.dev/"&gt;Merge Pro&lt;/a&gt; &lt;!-- affiliate --&gt;) first, &lt;a href="https://openrouter.ai/"&gt;OpenRouter&lt;/a&gt; &lt;!-- affiliate --&gt; second, and a different provider as the final resort when the 429s keep coming. The chain is configured, not improvised — every agent and script knows the order in advance. Since I set that up, a rate limit on one provider slows things down instead of stopping them.&lt;/p&gt;</description></item><item><title>Fresh VPS Hardening: The Order I Actually Use</title><link>https://agentjournal.dev/blog/fresh-vps-hardening/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/fresh-vps-hardening/</guid><description>&lt;p&gt;Every time I provision a fresh VPS I follow the same order, because the order has consequences. I harden SSH first, then set up the firewall, then fail2ban, then automatic updates, and only after all of that do I install the services the box is actually for. If you get a new server and your first move is installing the application, you are setting up an unlocked house and then decorating it. Here is the sequence I run on every fresh box, and why each step comes before the next.&lt;/p&gt;</description></item><item><title>GAS web apps as API proxies: hiding keys at zero cost</title><link>https://agentjournal.dev/blog/gas-web-app-proxy/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/gas-web-app-proxy/</guid><description>&lt;p&gt;Every script that calls an API from the client side ends up holding a key, and a key that ships to a client is a key that can leak. The zero-cost fix I run: a Google Apps Script (GAS) web app as an API proxy. The web app holds the upstream API key server-side and exposes a public endpoint. Clients call the endpoint; the key never appears in any client request. It hides the key, adds a controllable layer, and costs nothing to operate.&lt;/p&gt;</description></item><item><title>GCP free tier: what's actually usable for a hobbyist</title><link>https://agentjournal.dev/blog/gcp-free-tier/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/gcp-free-tier/</guid><description>&lt;p&gt;Yes, Google Cloud&amp;rsquo;s free tier is usable for hobby work — I use GCP free-tier resources for specific workloads and for Google-linked automation, and the whole thing costs zero. The realistic answer, though, is narrower than the marketing suggests: it covers a small set of always-free resources, the quotas are tight, and the entire skill is knowing exactly what is free and what bills the moment you exceed it. Get that boundary wrong and the &amp;ldquo;free tier&amp;rdquo; quietly stops being free.&lt;/p&gt;</description></item><item><title>Getting Japanese government statistics via the e-Stat API</title><link>https://agentjournal.dev/blog/estat-api-practice/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/estat-api-practice/</guid><description>&lt;h2 id="the-problem-where-do-official-japanese-numbers-actually-live"&gt;The problem: where do official Japanese numbers actually live?&lt;/h2&gt;
&lt;p&gt;Whenever I need population, GDP, CPI, or employment figures for Japan, my first instinct used to be to find some blog or aggregator that had already copied the numbers into a table. That works once, but it breaks the moment the source updates or I need a different slice of the data. Scraped and hand-copied statistics are a maintenance trap: I never know whether what I am reading is current, complete, or even from the official release. I wanted the source itself.&lt;/p&gt;</description></item><item><title>GGUF quantization: how much quality do you lose at Q4?</title><link>https://agentjournal.dev/blog/gguf-quantization-intro/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/gguf-quantization-intro/</guid><description>&lt;p&gt;I spent a long time assuming that running a model locally meant running it the way the authors wrote it, full precision and all that. Then I actually had to run models on the hardware I own, and quantization changed how I think about every model I deploy. The direct answer to the title question: at Q4-class quantization you lose some quality, but for the output I actually consume — embeddings, classifications, structured labels from my agents — the loss is small enough that I accept it routinely. That fact is what makes GGUF worth understanding instead of fearing.&lt;/p&gt;</description></item><item><title>Giving Agents Memory: Self-Hosted Qdrant + Mem0</title><link>https://agentjournal.dev/blog/agent-memory/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/agent-memory/</guid><description>&lt;p&gt;The way I give agents long-term memory is a small self-hosted stack: a vector database for storage, a Japanese-capable embedding model for indexing, and an open-source memory layer on top. The context window handles the current task; the memory layer handles everything the agent should still know next week. Keeping both local means the agent&amp;rsquo;s memory never leaves my server.&lt;/p&gt;
&lt;h2 id="why-agents-need-memory-at-all"&gt;Why agents need memory at all&lt;/h2&gt;
&lt;p&gt;A context window is a scratchpad, not a memory. When the session ends, everything it contained is gone — unless something wrote it down. Memory is that something: a layer the agent queries before answering, and updates when it learns something durable.&lt;/p&gt;</description></item><item><title>Headless browser setup that doesn't get you blocked</title><link>https://agentjournal.dev/blog/headless-browser-setup/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/headless-browser-setup/</guid><description>&lt;p&gt;When an agent needs a page that only exists after JavaScript runs, a plain HTTP request is not enough, and a badly wired headless browser gets blocked before it gets anything. The direct answer: I run a local browser-automation server (browser4) on a fixed port and drive it with a CLI — goto a URL, snapshot the page, close. The server holds one real browser session so consecutive commands share state, and I set generous timeouts because navigation over residential proxies is slow. That setup gets the pages my agents need without the failures I used to chase.&lt;/p&gt;</description></item><item><title>Health checks that match reality: monitoring services you actually run</title><link>https://agentjournal.dev/blog/health-check-monitoring/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/health-check-monitoring/</guid><description>&lt;p&gt;It is easy to end up with a monitoring setup that watches more than you run, or less. Mine went the other way for a while: I added rules as services appeared and never removed them when services went away, so the dashboard showed green next to checks for things that no longer existed. That taught me the principle I use now: the health check monitors exactly the services that exist, and when a service is removed, its monitoring rule goes with it. My check currently watches seven services — docker, ssh, cron, fail2ban, systemd-journald, logrotate.timer, and unattended-upgrades — and each one is a service I would actually act on if it died.&lt;/p&gt;</description></item><item><title>Hiding API keys behind a Cloudflare Worker: the free proxy pattern</title><link>https://agentjournal.dev/blog/worker-key-proxy/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/worker-key-proxy/</guid><description>&lt;p&gt;Every client that talks to an API ends up holding a key, and every copy of that key is another place it can leak. The pattern I use to avoid that: hide the key behind a &lt;a href="https://workers.cloudflare.com/"&gt;Cloudflare Worker&lt;/a&gt; &lt;!-- affiliate --&gt; on the free tier. The client calls the Worker. The Worker adds the real key server-side and forwards the request to the upstream API. The client never sees the key, and the Worker URL is the only credential it needs.&lt;/p&gt;</description></item><item><title>How This Site Is Built: Hugo + Cloudflare Pages, Operated by Agents</title><link>https://agentjournal.dev/blog/building-this-site-with-agents/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/building-this-site-with-agents/</guid><description>&lt;p&gt;This site is a demonstration of its own subject matter: an AI agent operates the entire pipeline — topic selection, article generation, compliance scrubbing, deployment, and verification — while a human supplies the experience and makes the decisions. The stack is deliberately boring: Hugo on Cloudflare Pages, a YAML topic queue, and a deploy script. The interesting part is what the agent does around that stack.&lt;/p&gt;
&lt;h2 id="the-stack"&gt;The stack&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hugo, single language, custom layouts.&lt;/strong&gt; Static HTML, no runtime, no database. GitHub-dark styling, mobile-first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloudflare Pages for hosting.&lt;/strong&gt; Free tier, global edge, HTTPS by default. A &lt;code&gt;.dev&lt;/code&gt; domain that enforces HTTPS at the registry level.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A YAML topic queue&lt;/strong&gt; (&lt;code&gt;seo-topics.yaml&lt;/code&gt;) as the editorial system. Every article starts as a topic with an angle — and the angle must be grounded in observable first-hand material, not a keyword list.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-pipeline"&gt;The pipeline&lt;/h2&gt;
&lt;p&gt;Each article moves through the same path:&lt;/p&gt;</description></item><item><title>Hugo on Cloudflare Pages: a free static site stack</title><link>https://agentjournal.dev/blog/cf-pages-hugo/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/cf-pages-hugo/</guid><description>&lt;p&gt;This site needed a home with three properties: zero hosting cost, no server to maintain, and HTTPS that never becomes my problem. I run it on Hugo, a static site generator, and &lt;a href="https://pages.cloudflare.com/"&gt;Cloudflare Pages&lt;/a&gt; &lt;!-- affiliate --&gt; on the free tier, and it delivers all three. The entire deploy path is one script that builds the site and uploads it, and since it went up, the hosting layer has not demanded any attention.&lt;/p&gt;</description></item><item><title>Idempotency for scheduled jobs: running twice must not break</title><link>https://agentjournal.dev/blog/idempotent-jobs/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/idempotent-jobs/</guid><description>&lt;p&gt;A scheduled job fails at 03:00, and the only sane recovery is to run it again. If rerunning it breaks something worse, you have just traded a small failure for a bigger one. The direct answer: design every scheduled job so that running it twice is safe, because re-running a failed job is my primary recovery action. I apply three idempotency patterns: skip work already done, use append-with-dedup, and make the job&amp;rsquo;s result independent of how many times it ran. A job that cannot be re-run safely forces risky manual intervention at 03:00, and that is the failure mode I refuse to accept.&lt;/p&gt;</description></item><item><title>IRBANK API: Japanese stock data without scraping</title><link>https://agentjournal.dev/blog/irbank-api-jp-stocks/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/irbank-api-jp-stocks/</guid><description>&lt;p&gt;If you build anything that tracks Japanese equities, the hardest part is rarely the model or the pipeline — it&amp;rsquo;s just getting the data. Global free financial APIs mostly ignore the Tokyo market, and scraping exchange sites from my own servers has burned me before (those datacenter IPs get blocked fast, as I wrote in my datacenter-IP notes). The answer I settled on is an IRBANK-compatible API: I pointed my daily job at a REST endpoint, passed a security code, and got clean OHLCV history back without touching a scraper. Here is how I actually use it.&lt;/p&gt;</description></item><item><title>journald is enough: running log infrastructure without rsyslog</title><link>https://agentjournal.dev/blog/journald-vs-rsyslog/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/journald-vs-rsyslog/</guid><description>&lt;p&gt;A lot of Linux guides assume you need a dedicated syslog daemon. When I set up my agent servers, I checked that assumption and I run systemd-journald and deliberately do not run rsyslog. For my workloads journald is enough, and removing rsyslog removed a daemon I did not want to maintain. This article is the reasoning behind that choice and the pieces that make it work.&lt;/p&gt;
&lt;h2 id="why-i-stopped-treating-rsyslog-as-a-default"&gt;Why I stopped treating rsyslog as a default&lt;/h2&gt;
&lt;p&gt;Rsyslog is fine software. It just did not fit my workflow. The moment I installed a server, the default configuration started a separate syslog daemon writing to files I rarely read, while my actual service logs lived somewhere else entirely. That split never earned its keep on my machines, so I removed it. My servers run systemd-journald as the only log mechanism, and journald itself already does the things I care about.&lt;/p&gt;</description></item><item><title>JSON Output for CLIs: Making Tools Machine-Readable by Default</title><link>https://agentjournal.dev/blog/terminal-output-json/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/terminal-output-json/</guid><description>&lt;p&gt;The design rule I apply to every CLI I build: &lt;strong&gt;structured output by default — JSON, ISO dates, integer amounts, and structured errors.&lt;/strong&gt; Text tables are for humans; JSON is for everything else, and since agents and scripts consume most of my CLI output, the machine-readable form is the default, not an opt-in flag.&lt;/p&gt;
&lt;h2 id="why-json-by-default"&gt;Why JSON by default&lt;/h2&gt;
&lt;p&gt;A CLI that prints a formatted table forces every consumer to parse text — fragile, locale-dependent, and different for every tool. A CLI that prints JSON gives scripts and agents a stable contract: parse once, use everywhere.&lt;/p&gt;</description></item><item><title>kintone from the CLI: Apps, Records, and Automation</title><link>https://agentjournal.dev/blog/kintone-cli/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/kintone-cli/</guid><description>&lt;p&gt;kintone — the low-code platform from Cybozu — is manageable entirely from the terminal once you accept its CLI as the interface: &lt;strong&gt;app configuration, records, and automation all driven by commands, with credentials in the password store.&lt;/strong&gt; The author uses it for the same reason as every other CLI in the stack: repeatability, scripting, and agent access.&lt;/p&gt;
&lt;h2 id="the-setup"&gt;The setup&lt;/h2&gt;
&lt;p&gt;The kintone CLI (&lt;code&gt;@kintone/cli&lt;/code&gt;) is installed through mise, like every other global tool (see &lt;a href="https://agentjournal.dev/blog/mise-tool-management/"&gt;mise tool management&lt;/a&gt;). Credentials live in the password store, not in config files or environment dumps — the same credential discipline as the rest of the stack (see &lt;a href="https://agentjournal.dev/blog/credential-management-for-ai-agents/"&gt;credential management&lt;/a&gt;).&lt;/p&gt;</description></item><item><title>Lark CLI: OAuth Device Flow, QR Codes, and Session Pitfalls</title><link>https://agentjournal.dev/blog/lark-cli-oauth/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/lark-cli-oauth/</guid><description>&lt;p&gt;The Lark CLI is scriptable, but its auth flow has a few traps that cost me an afternoon each: &lt;strong&gt;the device-flow login prints a QR code you scan from a phone, a pair of environment variables silently breaks workspace detection, and refresh tokens are single-use with a short life.&lt;/strong&gt; Once those are understood, the CLI is a reliable piece of the automation stack.&lt;/p&gt;
&lt;h2 id="the-login-flow-that-actually-works"&gt;The login flow that actually works&lt;/h2&gt;
&lt;p&gt;Lark&amp;rsquo;s OAuth device flow is designed for headless use: run the login with &lt;code&gt;--no-wait&lt;/code&gt;, the CLI prints a QR code, you scan it with the Lark mobile app, then complete the exchange with a device-code command. The QR path exists precisely because a browser login is not available on a headless server.&lt;/p&gt;</description></item><item><title>Living on the OpenRouter free tier without hating it</title><link>https://agentjournal.dev/blog/openrouter-free-tier/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/openrouter-free-tier/</guid><description>&lt;p&gt;Most free-tier advice reads like a dare: sure, it works, until the day you actually need it. I run a real share of my agent stack — including the LLM calls that keep agent memory current — on the &lt;a href="https://openrouter.ai/"&gt;OpenRouter&lt;/a&gt; &lt;!-- affiliate --&gt; free tier, and it has been fine under daily use. The trick is not hoping the free tier behaves like a paid API. It is routing the right work to it: low-stakes, high-volume calls that can fail quietly and retry, while the critical path stays on the paid gateway.&lt;/p&gt;</description></item><item><title>Logging agent activity: what to record and where</title><link>https://agentjournal.dev/blog/agent-logging/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/agent-logging/</guid><description>&lt;p&gt;I used to learn what my agents had done by reading their closing summaries. That stopped working the first time an unattended job reported success while producing nothing usable, and I had no way to reconstruct what actually happened. Since then I log agent activity as structured events: an append-only JSONL file at a user-state path with permission 0600, machine-readable and timestamped event types, and a hard rule that entries never contain token values. The log proves what happened without being a leak itself.&lt;/p&gt;</description></item><item><title>Maintaining a fork: tracking upstream while keeping your changes</title><link>https://agentjournal.dev/blog/fork-upstream-maintenance/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/fork-upstream-maintenance/</guid><description>&lt;p&gt;A fork that never merges upstream becomes a dead end: your copy drifts from the project you forked, and every new upstream feature has to be reinvented by hand. I maintain forks of upstream projects with my own changes on top by merging upstream regularly, keeping my changes isolated, and resolving conflicts deliberately. The rules are simple: track upstream with fetch and merge, keep my own changes in clearly separated commits and branches, and never rewrite shared history.&lt;/p&gt;</description></item><item><title>Managing Dev Tools with mise: No Global Installs, Ever</title><link>https://agentjournal.dev/blog/mise-tool-management/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/mise-tool-management/</guid><description>&lt;p&gt;The rule that keeps my machines reproducible: &lt;strong&gt;no global installs outside mise.&lt;/strong&gt; Every language runtime and global CLI comes from mise, which installs them into a versioned, shim-based environment instead of scattering binaries across the system. &lt;code&gt;npm -g&lt;/code&gt;, &lt;code&gt;pip install&lt;/code&gt;, and &lt;code&gt;uv tool install&lt;/code&gt; are banned as global operations — if a tool is not in mise, it does not exist on my path. That one rule has eliminated most of my environment drift.&lt;/p&gt;</description></item><item><title>Managing repos from the terminal: gh CLI for everything</title><link>https://agentjournal.dev/blog/gh-cli-workflow/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/gh-cli-workflow/</guid><description>&lt;p&gt;I manage GitHub repos from the terminal with the gh CLI, and I do not open the web UI for repository work anymore. Auth, repo creation, cloning, issues, and pull requests are all commands. If your workflow still alternates between an editor and a browser for every GitHub action, that is the friction worth removing: gh turns the whole repository lifecycle into shell commands, and the side effect is that scripts and agents can drive GitHub without a browser at all.&lt;/p&gt;</description></item><item><title>MCP explained: why every agent tool talks the same protocol now</title><link>https://agentjournal.dev/blog/mcp-what-and-why/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/mcp-what-and-why/</guid><description>&lt;p&gt;Every external tool used to mean a bespoke integration: one calling convention per data source, one glue layer per agent. The direct answer is that MCP (Model Context Protocol) is now the common layer. Servers expose tools, the agent client registers them at setup and calls them during a session, and adding a data source becomes a config change instead of an integration project. My setup runs MCP servers for government statistics, stock data, web search, and scraping, all registered through the same path.&lt;/p&gt;</description></item><item><title>MCP servers: what can go wrong and how to scope them</title><link>https://agentjournal.dev/blog/mcp-server-security/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/mcp-server-security/</guid><description>&lt;p&gt;I stopped treating MCP servers as harmless toolboxes the day I realized everything they return lands in the agent&amp;rsquo;s context — the same channel a prompt injection uses. The direct answer: treat server output as data, never as instructions; give each server the minimum tool surface it needs; and keep a token rotation routine, because tokens embedded in configs expire. Most MCP failures are not exotic attacks. They are missing scope and expired credentials, and both are preventable.&lt;/p&gt;</description></item><item><title>Mem0 Self-Hosted: Agent Memory Without the Cloud</title><link>https://agentjournal.dev/blog/mem0-oss-setup/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/mem0-oss-setup/</guid><description>&lt;p&gt;Agent memory does not have to mean a hosted service. I run Mem0 (open source) self-hosted as the memory layer for my agents, configured against my own LLM endpoint, my own local embeddings, and my own self-hosted vector store. The open-source self-hosted version gives me search, add, update, and delete tooling for agent memory — without sending any of it to the cloud.&lt;/p&gt;
&lt;h2 id="why-i-wanted-the-oss-memory-layer-not-the-managed-one"&gt;Why I wanted the OSS memory layer, not the managed one&lt;/h2&gt;
&lt;p&gt;Once I committed to keeping my agents&amp;rsquo; retrieval local, the managed memory product stopped making sense. The open-source self-hosted version does the job in a way that fits where I already am: my vector database is self-hosted, my embedding model is local, and my LLM endpoint is mine. Mem0 OSS is the layer that sits on top of those and gives the agent-facing operations I described when I wrote about &lt;a href="https://agentjournal.dev/blog/agent-memory/"&gt;giving agents memory&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Merge Gateway Pro: One API for Daily Models, Cost Tracking Included</title><link>https://agentjournal.dev/blog/merge-gateway-pro/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/merge-gateway-pro/</guid><description>&lt;p&gt;My agents used to call model providers directly, and I only found out how much that cost when the invoices arrived. &lt;a href="https://merge.dev/"&gt;Merge Gateway Pro&lt;/a&gt; &lt;!-- affiliate --&gt; fixed that for me: one API in front of the models I use daily, with cost tracking built in, for $10/month. It has paid for itself by catching the overspend that direct API calls were quietly running up. The key lives in my pass store, not in agent context, and when Merge is unavailable my calls fall back to OpenRouter.&lt;/p&gt;</description></item><item><title>Migrating Services to Free Tiers: What I Moved and What I Kept</title><link>https://agentjournal.dev/blog/migrating-off-paid/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/migrating-off-paid/</guid><description>&lt;p&gt;My whole agent stack runs on roughly $15 a month, and that number exists because I deliberately moved most of my services onto free tiers instead of paying for whatever was convenient. The short answer: I migrated almost everything that the free tier genuinely covers, and I kept two things paid — one gateway subscription and one small VPS. Everything else on the bill now has to justify itself.&lt;/p&gt;
&lt;p&gt;None of this came from one big cleanup. It came from a repeatable migration order I now apply to any new service before it ever gets a card on file.&lt;/p&gt;</description></item><item><title>Monitoring cron jobs: who notices when the daily job dies</title><link>https://agentjournal.dev/blog/cron-job-monitoring/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/cron-job-monitoring/</guid><description>&lt;p&gt;The uncomfortable truth about a daily cron job is that nobody is watching the clock when it runs. A job can die silently - the host wakes up, the wrapper exits non-zero, the mail gets lost - and nothing happens until you happen to look. The direct answer: I keep a registry of every scheduled job, store the operational state separately from the code, hash expected output so unexpected change is detectable, and run a health check over the registered jobs that notifies me on failure. That registry is the single source of truth for what should run, and drift between it and the actual cron table is something I monitor. Here is how that system works.&lt;/p&gt;</description></item><item><title>Multi-agent workflows: orchestrators, workers, and handoffs</title><link>https://agentjournal.dev/blog/multi-agent-workflows/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/multi-agent-workflows/</guid><description>&lt;p&gt;The first time I let several agents work on the same task at once, they collided — writing to the same files, duplicating each other&amp;rsquo;s work, and reporting results that overlapped. The pattern that fixed it is the one I still run today: an orchestrator/worker setup where a parent agent dispatches parallel workers, each worker gets an isolated context and its own terminal session, and workers hand results back to the parent as summaries. Concurrency is capped at up to five parallel workers, and nesting stops at one level: workers cannot spawn their own workers.&lt;/p&gt;</description></item><item><title>Native MCP Client Setup: stdio vs HTTP Servers in Config</title><link>https://agentjournal.dev/blog/mcp-native-client/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/mcp-native-client/</guid><description>&lt;p&gt;I kept flipping servers to enabled in my agent&amp;rsquo;s config and wondering why nothing changed. The tools were not in the tool list, and I was ready to blame the server. The real answer is simpler: in a native MCP client, servers live in the agent&amp;rsquo;s config file and their tools appear directly in the agent&amp;rsquo;s tool list — stdio servers spawn as local processes, while HTTP servers are remote endpoints. And there is one step I kept skipping: after you enable a server, the running client does not pick up the change until you reload it or start a new session. The config edit alone is not enough.&lt;/p&gt;</description></item><item><title>OAuth for CLI tools: device flow, refresh rotation, and long-lived sessions</title><link>https://agentjournal.dev/blog/oauth-for-clis/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/oauth-for-clis/</guid><description>&lt;p&gt;Every CLI tool that talks to a modern API eventually needs OAuth, and on a headless server the usual browser-based flow quietly fails. The fix is the device flow from RFC 8628: the tool prints a code and a URL, you approve on any device, and the CLI polls until the token arrives. That gets you logged in once. Keeping the session alive for months is a separate discipline around refresh tokens: where they live, whether they rotate, and how you react when they die.&lt;/p&gt;</description></item><item><title>Official data first: why government and exchange APIs beat scrapers</title><link>https://agentjournal.dev/blog/official-data-first/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/official-data-first/</guid><description>&lt;p&gt;The direct answer: government and exchange APIs beat scrapers because they are official, reliable, contracted, and free from the bot walls that eat scraped pipelines. I run agents that pull corporate filings, statistics, and registry data, and my rule is official sources first — it is the difference between a feed I can trust and one I have to defend. When an official API exists, it wins.&lt;/p&gt;
&lt;h2 id="one-rule-many-sources"&gt;One rule, many sources&lt;/h2&gt;
&lt;p&gt;My default is not source-specific; it is a habit. Before I build any data pipeline, I ask whether a government or exchange API already exists for the data I need. In practice that turns out true far more often than people expect.&lt;/p&gt;</description></item><item><title>opencode vs Claude Code vs Codex: When Each Wins in My Workflow</title><link>https://agentjournal.dev/blog/choosing-your-agent/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/choosing-your-agent/</guid><description>&lt;p&gt;I do not have one agent. I match the agent to the task type: opencode for repo-scale work where I want full control of the loop, Claude Code and Codex for specialist sessions, and a separate automation agent for everything that runs unattended. The decision is delegation structure, not model quality — and getting that structure right matters more than which model is behind the agent.&lt;/p&gt;
&lt;h2 id="the-mistake-picking-one-agent-for-everything"&gt;The mistake: picking one agent for everything&lt;/h2&gt;
&lt;p&gt;When agents first got good, the natural move was to pick one and use it for all work. That fails in two directions: the agent gets used for tasks it is bad at, and the workflow collapses into a single point of failure (one update, one regression, one context disaster takes everything down).&lt;/p&gt;</description></item><item><title>Oracle Cloud free tier: the always-free ARM instance</title><link>https://agentjournal.dev/blog/oracle-free-tier/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/oracle-free-tier/</guid><description>&lt;p&gt;Yes, Oracle Cloud&amp;rsquo;s always-free tier really does include a permanently free ARM instance — I run a meaningful part of my agent infrastructure on one. The catch people miss is not the price, it is the availability and the mindset. The free-tier ARM instance hosts agent services and a long-running site in my stack, and it has been genuinely useful. But I treat it as a nearly-free compute resource with a recall clause, not as a permanent home for anything I cannot afford to lose.&lt;/p&gt;</description></item><item><title>pass vs Bitwarden: Running Both, and When Each Wins</title><link>https://agentjournal.dev/blog/pass-vs-bitwarden/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/pass-vs-bitwarden/</guid><description>&lt;p&gt;I run both pass and Bitwarden, and the split is deliberate. pass (password-store, GPG-encrypted, file-based) is my primary store; &lt;a href="https://bitwarden.com/"&gt;Bitwarden&lt;/a&gt; &lt;!-- affiliate --&gt; holds the entries that live there, accessed through its CLI. The question is not which one to standardize on — it is which store a given secret belongs in. pass wins for anything my agents and scripts touch daily. Bitwarden wins for the entries that were already there and for programmatic access through its API. My credential broker reads both, so there was no migration and no new vault format.&lt;/p&gt;</description></item><item><title>Promoting OSS without spending money: channels that worked</title><link>https://agentjournal.dev/blog/oss-promo-free/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/oss-promo-free/</guid><description>&lt;p&gt;Promoting an open-source project on a zero budget comes down to showing up where developers already read, with posts that solve one problem each. I have promoted my projects without paid ads, sponsorships, or a marketing budget, using dev.to, X, Hacker News, and Chinese community platforms such as V2EX, Zhihu, and Juejin, plus plain community presence. The channels that worked are the ones I could sustain with a fixed cadence and honest KPIs.&lt;/p&gt;</description></item><item><title>Prompt Injection: The Incidents I Actually Hit Running Agents</title><link>https://agentjournal.dev/blog/prompt-injection-incidents/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/prompt-injection-incidents/</guid><description>&lt;p&gt;Prompt injection is not a theoretical risk in my setup — it is the reason my credential architecture exists. The incidents I have actually hit are not dramatic; they are the boring kind: my own agent echoed a connection string into tool output, more than once. And tool output is exactly the channel where injected instructions arrive. The defenses that hold up are structural, not prompt-based.&lt;/p&gt;
&lt;h2 id="the-incident-secrets-in-tool-output"&gt;The incident: secrets in tool output&lt;/h2&gt;
&lt;p&gt;The pattern is always the same. The agent runs a command — a config dump, an environment print, a debug run — and the command&amp;rsquo;s output includes a secret value. The output lands in the agent&amp;rsquo;s context window. From there it goes into the transcript, sometimes into logs, sometimes into a summary sent to an API endpoint I do not control.&lt;/p&gt;</description></item><item><title>Proxy your API keys: the zero-cost pattern that keeps keys off clients</title><link>https://agentjournal.dev/blog/api-key-proxy-pattern/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/api-key-proxy-pattern/</guid><description>&lt;p&gt;Yes, you can keep API keys off your clients for nothing. The pattern is to hide the key behind a proxy and point every client at the proxy URL instead of the upstream API. The client never holds, sees, or transmits the real key, and because rotation happens in one place, you never redeploy clients when a key changes. It costs nothing on a free tier, and it is the cleanest security win per hour of work I have found.&lt;/p&gt;</description></item><item><title>Qdrant Self-Hosted: Vectors That Never Leave Your Server</title><link>https://agentjournal.dev/blog/qdrant-selfhosted/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/qdrant-selfhosted/</guid><description>&lt;p&gt;My agents&amp;rsquo; memory lives in a vector database, and I self-host it in Docker. That is the whole point: the vectors never leave my server. If you have thought about going to a hosted vector service for agent memory but baulked at sending your indexed facts off-box, self-hosting &lt;a href="https://qdrant.tech/"&gt;Qdrant&lt;/a&gt; &lt;!-- affiliate --&gt; is a straightforward alternative that keeps the index on hardware you control.&lt;/p&gt;
&lt;h2 id="why-i-stopped-reaching-for-a-hosted-vector-store"&gt;Why I stopped reaching for a hosted vector store&lt;/h2&gt;
&lt;p&gt;When I first built the memory layer for my agents, a managed vector database looked easiest: no container to run, no backups to think about, just an API. The more I described my &lt;a href="https://agentjournal.dev/blog/agent-memory/"&gt;memory setup&lt;/a&gt; the clearer it became that the service sitting underneath would be the thing deciding where my agents&amp;rsquo; facts physically lived. And the data is the problem. The index holds the durable facts my agents rely on — environment details, conventions, preferences. Sending all of that to a third party for indexing made me uncomfortable, and the more the index grew, the more it felt like the wrong trade.&lt;/p&gt;</description></item><item><title>Quality gates for agent output: verification before merge</title><link>https://agentjournal.dev/blog/agent-quality-gates/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/agent-quality-gates/</guid><description>&lt;p&gt;Agents produce output that looks finished. That is exactly why I stopped merging anything an agent produces without running it through a gate first. The direct answer: verification happens before merge, and it is automated. My code gate is a Makefile &lt;code&gt;check&lt;/code&gt; target that runs format, lint, type-check, and tests, plus pre-commit hooks and a secrets check before commit. For generated content I add word-count, structure, sourcing, and duplication checks, then verify every published URL returns HTTP 200. The gate runs in CI or in the deploy script every time, so verification is a step in the pipeline, not a promise.&lt;/p&gt;</description></item><item><title>R2 for backups: object storage that never bills you for egress</title><link>https://agentjournal.dev/blog/r2-backup-strategy/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/r2-backup-strategy/</guid><description>&lt;p&gt;I run my agent infrastructure on a single server, and for a long time my backup plan stopped at &amp;ldquo;the disk is still fine.&amp;rdquo; Then I thought through what an actual restore would look like, and egress fees changed the whole calculation. My answer: I use &lt;a href="https://developers.cloudflare.com/r2/"&gt;Cloudflare R2&lt;/a&gt; &lt;!-- affiliate --&gt; for offsite backups, because R2 never bills for egress. Restoring or downloading backups costs nothing per gigabyte, which makes the one moment you actually need the data — a restore — the cheapest one.&lt;/p&gt;</description></item><item><title>Residential proxies: when your datacenter IP is the problem</title><link>https://agentjournal.dev/blog/residential-proxy-usage/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/residential-proxy-usage/</guid><description>&lt;p&gt;Your scraper can be perfect and still get blocked, because the block is often not about your code — it is about where your traffic comes from. The direct answer: when a target discriminates against datacenter ranges, route your browser traffic through a residential proxy. I run a local forwarder on a fixed port that sends browser traffic out through residential IPs, and I keep API-driven work on datacenter IPs, where it belongs.&lt;/p&gt;</description></item><item><title>Retry with exponential backoff: a small library that saves nights</title><link>https://agentjournal.dev/blog/retry-with-backoff/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/retry-with-backoff/</guid><description>&lt;p&gt;A job fails because a rate limit or a temporary 5xx hiccup comes and goes in a minute. If I bounce up at 03:00 for every transient blip, I never sleep. The direct answer: I keep a small retry helper with exponential backoff in my toolkit, and it decides for me whether a failure is worth another try. On a transient failure it waits a growing amount of time and retries, up to a cap; on a permanent failure it stops immediately. That one small reusable function has quietly saved more nights than any other piece of my automation.&lt;/p&gt;</description></item><item><title>Routing decisions: cheap model first, expensive model on retry</title><link>https://agentjournal.dev/blog/model-routing-decisions/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/model-routing-decisions/</guid><description>&lt;p&gt;Every LLM call has a price, and the price difference between a small model and a frontier model is large enough to shape the whole budget. The direct answer: I route by task. Cheap model first, expensive model on retry or for high-stakes output. Machine-consumed output, which means embeddings, classification, and extraction, runs on a small dedicated model. Human-read generation runs on a frontier model through a gateway. When the primary gateway returns a 429, a fallback chain moves the request to the next provider, and in one observed case that meant a different model family entirely, not just a different endpoint.&lt;/p&gt;</description></item><item><title>Running Agents Unattended: Cron, Monitoring, and the Notification Loop</title><link>https://agentjournal.dev/blog/running-agents-unattended/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/running-agents-unattended/</guid><description>&lt;p&gt;The pattern that keeps my unattended agents healthy is boring: every scheduled run goes through a wrapper that logs everything, exits with a code, and notifies a human on failure. Then a separate health check watches the watchers. No dashboard, no pager duty, no AI deciding whether to call me — just a loop that either works silently or makes noise.&lt;/p&gt;
&lt;h2 id="why-unattended-agents-are-an-ops-problem"&gt;Why unattended agents are an ops problem&lt;/h2&gt;
&lt;p&gt;The moment an agent runs without you watching, it stops being a coding problem and becomes an infrastructure problem. It has a schedule, a runtime, an environment, and failure modes. The interesting failure is not &amp;ldquo;the agent wrote wrong code&amp;rdquo; — it is &amp;ldquo;the job died at 03:00 and nobody noticed for four days.&amp;rdquo;&lt;/p&gt;</description></item><item><title>Running AI Coding Agents in Production: My 2026 Stack</title><link>https://agentjournal.dev/blog/running-ai-coding-agents-in-production/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/running-ai-coding-agents-in-production/</guid><description>&lt;p&gt;Everyone has an opinion about AI agents. Almost nobody publishes their actual production setup — the gateways, the MCP servers, the credential handling, the monthly bill. This is mine, as of August 2026, with real numbers and the failures included.&lt;/p&gt;
&lt;p&gt;I run coding and automation agents daily for real work: this site, open-source tooling, and the automation that runs my infrastructure. Here&amp;rsquo;s the stack, layer by layer.&lt;/p&gt;
&lt;h2 id="the-agents-division-of-labor"&gt;The agents (division of labor)&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t use one agent for everything. Using the right tool per task is the cheapest optimization available:&lt;/p&gt;</description></item><item><title>Sandboxing agents: filesystem access and command limits</title><link>https://agentjournal.dev/blog/agent-sandboxing-basics/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/agent-sandboxing-basics/</guid><description>&lt;p&gt;My agent can read files, write files, run terminal commands, access the web, and drive a browser — and for a long time I treated that as one big permission. The direct answer: stop doing that. Sandboxing an agent is not one enclosure; it is capability separation. File reads, file writes, terminal commands, web access, and browser automation are separate surfaces, each with its own permission handling. Risky operations require explicit human approval, and delegated subagents run in isolated contexts they cannot see out of.&lt;/p&gt;</description></item><item><title>SBOMs in practice: what's in them and who reads them</title><link>https://agentjournal.dev/blog/sbom-in-practice/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/sbom-in-practice/</guid><description>&lt;p&gt;An SBOM is a machine-readable inventory of every dependency inside your binary, and its practical value only shows up when someone actually reads it. I used to treat software bills of materials as paperwork for large enterprises with compliance teams, not for a solo maintainer. Then I started shipping one with every release of my own project, and the exercise changed how I think about dependencies. Here is what is actually in an SBOM, and who reads it.&lt;/p&gt;</description></item><item><title>Scheduled reporting: turning job output into a readable summary</title><link>https://agentjournal.dev/blog/scheduled-reporting/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/scheduled-reporting/</guid><description>&lt;p&gt;A scheduled report is only useful if someone actually reads it, so my approach is to aggregate job output into a structured, tight summary and email it on a fixed cadence. I do not send raw logs or long digests. The goal is one screen that answers &amp;ldquo;what happened since the last report&amp;rdquo; and nothing more.&lt;/p&gt;
&lt;h2 id="aggregate-dont-forward"&gt;Aggregate, don&amp;rsquo;t forward&lt;/h2&gt;
&lt;p&gt;The temptation with a scheduled job is to pipe its full output into an email and call it a report. I found that does not work, mainly because nobody reads a wall of text twice. Instead, periodic jobs aggregate their output into a structured report: a compact set of fields that summarize the run — what succeeded, what failed, any values that changed since last time — and that summary is what gets emailed.&lt;/p&gt;</description></item><item><title>Scraping bot-protected pages: CAPTCHA, Cloudflare, and workarounds</title><link>https://agentjournal.dev/blog/scraping-bot-protected/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/scraping-bot-protected/</guid><description>&lt;p&gt;Some pages I want to scrape sit behind strong bot protection — Cloudflare challenges, CAPTCHAs — and a plain headless browser fails on them every time. The workaround that works for me is escalation: start with a normal headless browser, add a residential proxy when IP reputation is the problem, and move to a managed scraping browser for the hardest targets. Managed services rotate fingerprints and solve or avoid the challenges themselves, at a per-use cost. Before any of that, I check whether an official API already exists, because many times scraping is the wrong answer.&lt;/p&gt;</description></item><item><title>Scrubbing Secrets from Datastores: Making Bytes Disappear, Not 'Look Deleted'</title><link>https://agentjournal.dev/blog/memory-store-hygiene/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/memory-store-hygiene/</guid><description>&lt;p&gt;Deleting a secret from a database is not the same as removing it. A row marked deleted still sits in the file; a rebuilt index still references the old text. The standard that actually works: &lt;strong&gt;two-layer redaction — known values plus patterns — then index rebuild and vacuum, so the bytes are gone from the storage layer, not just hidden from the query layer.&lt;/strong&gt; This is the retroactive half of a credential strategy, and it is the half almost nobody builds.&lt;/p&gt;</description></item><item><title>SEC EDGAR: pulling 10-Ks programmatically</title><link>https://agentjournal.dev/blog/sec-edgar-automation/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/sec-edgar-automation/</guid><description>&lt;p&gt;Reading a 10-K by hand every time I need financials is not something an agent should do. The annual report is a wall of text that I mostly want for a few structured facts, and I would rather have a machine fetch and parse it than copy figures from a rendered page. SEC EDGAR is the official repository for US company filings — 10-K, 10-Q, and 8-K — and it is designed to be pulled programmatically. This post is about how I automate 10-K retrieval from EDGAR for analysis.&lt;/p&gt;</description></item><item><title>Secret scanning before commit: pre-commit hooks and CI</title><link>https://agentjournal.dev/blog/secret-scanning-pipeline/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/secret-scanning-pipeline/</guid><description>&lt;p&gt;The scariest way a credential leaks is quietly, in a commit nobody expects to be interesting. My answer is a secrets check that runs before anything reaches history. The direct version: I run a secrets scan as a pre-commit hook so it catches accidental keys at commit time, and CI runs the same check a second time as a gate. Scanning stops new leaks at the door; scrubbing is a separate problem for what already sits in history. This post is how I wired that and what it realistically covers.&lt;/p&gt;</description></item><item><title>Self-Hosting LLMs: When It Beats the API (and When It Embarrasses You)</title><link>https://agentjournal.dev/blog/self-hosted-llm-economics/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/self-hosted-llm-economics/</guid><description>&lt;p&gt;The economics of running your own LLM inference are decided by workload shape, not by model quality. Self-hosting — or routing to a small dedicated model — wins for high-volume, low-stakes, repetitive inference: embeddings, classification, extraction, anything where the same kind of call happens thousands of times. Frontier APIs win for quality-sensitive generation. The boundary is measured in tokens per dollar and in what a wrong answer costs, not in vibes.&lt;/p&gt;</description></item><item><title>Sending notification emails from scripts: Resend and friends</title><link>https://agentjournal.dev/blog/notification-emails/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/notification-emails/</guid><description>&lt;p&gt;When a scheduled job runs and no one hears about it, the job might as well not have run. The direct answer to &amp;ldquo;how do you send notification emails from scripts&amp;rdquo; is: route them through an email API such as Resend, triggered from the scheduled job wrapper, where success is quiet or a one-line summary and failure is immediate with the log tail, exit code, and re-run command. The principle I follow is that a notification loop is part of the job — a job that runs but never notifies is already dead.&lt;/p&gt;</description></item><item><title>Session persistence for scrapers: logins that survive restarts</title><link>https://agentjournal.dev/blog/session-persistence-scraping/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/session-persistence-scraping/</guid><description>&lt;p&gt;Logged-in sessions do not survive a fresh headless browser — every restart starts anonymous, and pages that need a login fail. The fix I use is a persistent browser profile: keep the profile around between runs so the cookies and session state carry over, and the login survives restarts. I keep one persistent profile for targets that require login, and I keep it strictly separate from throwaway scraping tasks, which run in fresh contexts. The catch is that persistent profiles accumulate state over time, so I refresh them deliberately.&lt;/p&gt;</description></item><item><title>Slack Automation from the Terminal: Messages Without the App</title><link>https://agentjournal.dev/blog/slack-automation-cli/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/slack-automation-cli/</guid><description>&lt;p&gt;Slack has a CLI story that lets scripts and agents post messages without the app: &lt;strong&gt;send to channels from the terminal, driven by cron jobs and pipelines.&lt;/strong&gt; For a solo operator the value is not chat — it is the notification channel that lands where you already look, without building a webhook integration per script.&lt;/p&gt;
&lt;h2 id="why-terminal-first-slack"&gt;Why terminal-first Slack&lt;/h2&gt;
&lt;p&gt;Slack&amp;rsquo;s real value for automation is delivery: a message that lands in a channel you already monitor. The pattern: a script finishes (or fails), and a one-line CLI call posts the result. No app, no browser, no per-service webhook plumbing.&lt;/p&gt;</description></item><item><title>Spreadsheet as a database: when Sheets is the right backend</title><link>https://agentjournal.dev/blog/spreadsheet-as-db/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/spreadsheet-as-db/</guid><description>&lt;p&gt;Is a spreadsheet a database? Strictly, no — and for most workloads you should reach for a real one. But I have used a Google Sheet as the data backend for a production tool, and for the right workload it is a legitimate choice: no server to run, no schema migration, and the data stays human-visible and editable. The honest rule is a boundary question. Sheets is the right backend when writes are low, humans review the data, and queries stay simple — and it stops being the right backend the moment concurrency, row count, or query complexity shows up.&lt;/p&gt;</description></item><item><title>systemd unit hardening: sandboxing your services</title><link>https://agentjournal.dev/blog/systemd-hardening/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/systemd-hardening/</guid><description>&lt;p&gt;Every service I run on a server starts from a hardened systemd unit, not a default one. The direct answer: systemd unit hardening is about giving each service the minimal set of privileges its function needs, using directives like NoNewPrivileges, ProtectSystem, and PrivateTmp, and dropping capabilities rather than granting them. I apply this as part of the base configuration for every unit, before an incident, not as a response to one.&lt;/p&gt;</description></item><item><title>Tailscale as Agent Infrastructure: Zero Public Attack Surface</title><link>https://agentjournal.dev/blog/tailnet-for-agents/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/tailnet-for-agents/</guid><description>&lt;p&gt;All agent access to my infrastructure runs over a &lt;a href="https://tailscale.com/"&gt;Tailscale&lt;/a&gt; &lt;!-- affiliate --&gt; tailnet — a WireGuard-based private network — and nothing else. Public port 22 on my server is closed (last verified 2026-08-09), and no agent-facing service listens on a public interface. Agents reach services by tailnet hostname and connect to a tailnet address. The public attack surface for agent access is close to zero, because there is nothing public to attack. If your agents touch real infrastructure, tailnet-only access is the highest-value change I have made.&lt;/p&gt;</description></item><item><title>Testing Methodology</title><link>https://agentjournal.dev/testing-methodology/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/testing-methodology/</guid><description>&lt;p&gt;How does a tool end up recommended on Agent Journal? It doesn&amp;rsquo;t get here by having a good landing page.&lt;/p&gt;
&lt;h2 id="the-bar"&gt;The bar&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Used in production, not in a demo.&lt;/strong&gt; The tool has to survive real work: a multi-week project, a production pipeline, an agent that runs unattended. &amp;ldquo;I ran the quickstart&amp;rdquo; is not a review.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimum two weeks of real use.&lt;/strong&gt; The first-week honeymoon doesn&amp;rsquo;t count. Bugs show up in week two, when the tool stops being novel.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Failures are part of the review.&lt;/strong&gt; If a tool ate my credentials, cost me a night, or lost data — that goes in the post. Every recommendation includes what went wrong and how it was handled.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compared against the alternatives I actually tried.&lt;/strong&gt; If I say something is the best gateway for my setup, I say what else I ran and why it lost.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost is measured, not estimated.&lt;/strong&gt; For anything billable, posts include real numbers from my own usage — what the free tier actually covers, what the bill looked like, where the overage came from.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="what-gets-excluded"&gt;What gets excluded&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Tools I haven&amp;rsquo;t used hands-on (marked explicitly when mentioned)&lt;/li&gt;
&lt;li&gt;Tools I used once and couldn&amp;rsquo;t reproduce&lt;/li&gt;
&lt;li&gt;Anything where the vendor&amp;rsquo;s sales process replaced my testing&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="disclosure-of-conflicts"&gt;Disclosure of conflicts&lt;/h2&gt;
&lt;p&gt;I maintain open-source software in this space (&lt;a href="https://github.com/ikkun1222/trustless"&gt;trustless&lt;/a&gt;). If a post touches a competing product, that&amp;rsquo;s disclosed inline. Affiliate relationships are disclosed on every affected post — see the &lt;a href="https://agentjournal.dev/disclosure/"&gt;disclosure&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>The .dev TLD: HTTPS by default and what it means</title><link>https://agentjournal.dev/blog/dev-tld-https/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/dev-tld-https/</guid><description>&lt;p&gt;HTTPS on a normal domain is something you configure, and configuration can be forgotten: a link that starts with http://, a subdomain without a certificate, a first request that happens before the redirect. The .dev TLD removes that whole class of mistakes. .dev is a Google Registry TLD with HTTPS enforced — the entire TLD is on the HSTS preload list, so browsers refuse plain HTTP for any .dev domain. In practice that means no mixed-content accidents, no accidental plaintext traffic, and any hosting you point a .dev domain at must provide TLS. For a developer-facing site, that is a feature, not a constraint.&lt;/p&gt;</description></item><item><title>The $15/Month Agent Stack: Free Tiers That Actually Work</title><link>https://agentjournal.dev/blog/free-tier-stack/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/free-tier-stack/</guid><description>&lt;p&gt;My entire agent infrastructure — coding agents, automation, this site, memory, and backups — runs on roughly &lt;strong&gt;$15/month&lt;/strong&gt;, and most of that is one paid gateway subscription. The rest is free tiers that hold up under real use. The trick is not finding free things; it is routing each workload to the tier where it is genuinely free, and keeping the paid spend in one auditable place.&lt;/p&gt;
&lt;h2 id="the-actual-bill"&gt;The actual bill&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Layer&lt;/th&gt;
					&lt;th&gt;Cost&lt;/th&gt;
					&lt;th&gt;What it covers&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Gateways&lt;/td&gt;
					&lt;td&gt;~$10/mo&lt;/td&gt;
					&lt;td&gt;One paid gateway subscription; free tiers on two others&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;DNS, hosting, edge&lt;/td&gt;
					&lt;td&gt;$0&lt;/td&gt;
					&lt;td&gt;Cloudflare free tier: DNS, Pages (this site), Workers&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Compute&lt;/td&gt;
					&lt;td&gt;~$5/mo&lt;/td&gt;
					&lt;td&gt;One small VPS for self-hosted services&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Domains&lt;/td&gt;
					&lt;td&gt;~$1/mo amortized&lt;/td&gt;
					&lt;td&gt;Promotional first-year registrations&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;~$15/mo&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The same setup, with lazy routing, easily runs $200+/month. The difference is where the calls land.&lt;/p&gt;</description></item><item><title>The corporate number API: looking up any Japanese company</title><link>https://agentjournal.dev/blog/houjin-bangou-api/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/houjin-bangou-api/</guid><description>&lt;p&gt;When an agent needs to confirm that a company name in my notes is the real, registered entity, guessing from the name alone is not good enough. Names get romanized differently, subsidiaries share prefixes, and two firms can look alike on paper. The answer is the houjin-bangou (法人番号) API, Japan&amp;rsquo;s official corporate number lookup, and it identifies any registered company from its corporate number. This post is about how I wired it into my data pipeline for resolving and enriching entity data.&lt;/p&gt;</description></item><item><title>The cron wrapper pattern: run.sh, logging, and exit codes</title><link>https://agentjournal.dev/blog/cron-wrapper-pattern/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/cron-wrapper-pattern/</guid><description>&lt;p&gt;The problem with a cron job is that the moment it matters, you are not looking at it. Cron runs quietly, mails are easy to miss, and a job that fails at 03:00 leaves no sign until you go hunting for it. The direct answer: I route every scheduled task through a wrapper script instead of pointing cron at the tool directly, and the wrapper does three things - it logs everything, it returns a real exit code, and it fails loud. That small indirection is what turns an invisible job into one I can actually operate. Here is how the pattern works and why I run all my scheduled automation through it.&lt;/p&gt;</description></item><item><title>The Entire Cloudflare Free Stack: Pages, Workers, R2, DNS</title><link>https://agentjournal.dev/blog/cloudflare-free-stack/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/cloudflare-free-stack/</guid><description>&lt;p&gt;Yes, the whole stack is actually free: DNS, Pages for static hosting, Workers for edge code, and R2 for object storage all have a genuinely usable free tier, and I run this site on it. DNS, Pages, edge cache, and HTTPS all sit on &lt;a href="https://www.cloudflare.com/"&gt;Cloudflare&lt;/a&gt;&lt;!-- affiliate --&gt; at zero cost. The free tier here is not a prototype tier — it holds up for a production site. The catch is understanding the usage floors on each product so you stay inside them.&lt;/p&gt;</description></item><item><title>The MCP servers I run daily (and why)</title><link>https://agentjournal.dev/blog/mcp-servers-i-run/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/mcp-servers-i-run/</guid><description>&lt;p&gt;The question I get most often about MCP is not how the protocol works but what to actually run on it. The direct answer for my setup: two servers run always-on — a general web search/fetch server used for most research queries, and a scraping/SERP server for Google results, site: operators, and bot-protected pages — while a batch of specialized servers stay disabled by default and are enabled on demand. The rule behind every choice is context cost versus convenience.&lt;/p&gt;</description></item><item><title>The PR lifecycle: branch, CI, review, merge without the web UI</title><link>https://agentjournal.dev/blog/pr-lifecycle/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/pr-lifecycle/</guid><description>&lt;p&gt;The pull request is where my changes get reviewed, and for a long time it was also the point where I left the terminal. Branching, committing, and pushing were commands; opening the PR, watching CI, and merging meant a browser. The fix was to drive the entire lifecycle from the CLI: branch, commit, open, CI runs, review, merge — each step a command, none of them requiring a web page.&lt;/p&gt;</description></item><item><title>Transferring domains to Cloudflare Registrar: the 60-day wait</title><link>https://agentjournal.dev/blog/cf-registrar-transfer/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/cf-registrar-transfer/</guid><description>&lt;p&gt;I register domains wherever the first-year deal is cheapest, and I move them to Cloudflare Registrar once the promotional period has done its job. The thing that slows that plan down is the 60-day lock: ICANN blocks transfers for 60 days after a new registration, so a fresh domain cannot be moved no matter which registrar you want to take it. The wait is not a Cloudflare rule — it applies everywhere. Plan around it: register early, wait out the lock, then transfer. The transfer itself takes only a few days.&lt;/p&gt;</description></item><item><title>Trilingual READMEs: EN/JA/ZH as a default for OSS</title><link>https://agentjournal.dev/blog/trilingual-readmes/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/trilingual-readmes/</guid><description>&lt;p&gt;Every open-source project makes the same silent decision before anyone reads a line of code: which readers is the README allowed to reach? Write it in one language and you have assumed your audience lives in that language. My answer is to ship READMEs in English, Japanese, and Chinese as the default for my open-source projects. A dev tool draws users from all three language communities, and a README in one language quietly excludes the other two. This post is why trilingual became my default and how I keep three files from drifting apart.&lt;/p&gt;</description></item><item><title>Unattended upgrades: letting the server patch itself</title><link>https://agentjournal.dev/blog/unattended-upgrades/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/unattended-upgrades/</guid><description>&lt;p&gt;The scariest sentence in server administration is &amp;ldquo;I will patch that this weekend.&amp;rdquo; It is also the one I stopped believing. My servers run unattended-upgrades to apply security updates automatically, and I keep it enabled and monitor it as a service. Letting the server patch itself beats trusting me to remember a manual window, and this article is about the trade-off I made to do it.&lt;/p&gt;
&lt;h2 id="the-risk-model-that-changed-my-mind"&gt;The risk model that changed my mind&lt;/h2&gt;
&lt;p&gt;Automatic patching looks reckless until you write down what it is actually trading. The deal is simple: automatic patching trades a small risk of breakage for closing known-vulnerability windows promptly. On the other side of the ledger, a server that never patches quietly accumulates known holes that anyone with the right CVE list can exploit.&lt;/p&gt;</description></item><item><title>Vercel AI Gateway free tier: $5 of credits, real limits</title><link>https://agentjournal.dev/blog/vercel-ai-gateway-free/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/vercel-ai-gateway-free/</guid><description>&lt;p&gt;&amp;ldquo;Free tier&amp;rdquo; on a gateway usually means one of two things: a meter you discover after the bill, or a teaser that evaporates the moment you enter a card. The &lt;a href="https://vercel.com/"&gt;Vercel&lt;/a&gt; &lt;!-- affiliate --&gt; AI Gateway free tier is neither — it is $5 of credits per 30 days, real and observed, with no card required. The catch is that the free credits stop once a card is registered. I use it for the projects already on Vercel&amp;rsquo;s stack, and it works fine as long as I respect that one rule and keep the gateway off the default path.&lt;/p&gt;</description></item><item><title>vLLM for One-Person Inference: Serving a Small Model Properly</title><link>https://agentjournal.dev/blog/vllm-basics/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/vllm-basics/</guid><description>&lt;p&gt;vLLM is the serving engine I use for the local models in my stack, and the honest summary is this: for one person running a small Japanese-optimized model for embeddings and light inference, vLLM gives you high-throughput, continuously batched serving that you can point at and forget — once you treat the model as a service instead of a script. The hard part is not starting vLLM. It is remembering that a served model now needs monitoring, restarts, and version pinning, just like anything else you run.&lt;/p&gt;</description></item><item><title>What coding agents actually do (and don't)</title><link>https://agentjournal.dev/blog/what-are-coding-agents/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/what-are-coding-agents/</guid><description>&lt;p&gt;The marketing makes coding agents sound like they replace your whole engineering team. Mine don&amp;rsquo;t. After running them in production for a while, the honest answer is this: a coding agent is software that reads your code and config, calls tools (terminal, file read/write, search), and iterates in a loop of write, run, check, fix. That loop is the whole product. Everything else — autonomy, reasoning, &amp;ldquo;understanding your codebase&amp;rdquo; — is a consequence of how well that loop is structured.&lt;/p&gt;</description></item><item><title>wrangler from the terminal: Pages deploys without the dashboard</title><link>https://agentjournal.dev/blog/wrangler-workflows/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://agentjournal.dev/blog/wrangler-workflows/</guid><description>&lt;p&gt;Deploying through the Cloudflare dashboard means opening a browser, clicking through panels, and repeating the same steps for every release — and none of it can be scripted. I deploy Pages projects with wrangler, the CLI for &lt;a href="https://www.cloudflare.com/"&gt;Cloudflare&lt;/a&gt; &lt;!-- affiliate --&gt;, and the dashboard has not been part of my release path since. Three commands cover project creation, deploys, and auth checks, and the terminal workflow is the same whether I run it or an agent does.&lt;/p&gt;</description></item></channel></rss>