# The Agent Control Blog — What Your Agents Actually Cost, and How to Control Every Tool Call

Real metered data on AI agent cost and control: Claude Code permissions and deny rules, tool allowlists, per-action cost tracking, MCP security, audit trails, and incident post-mortems.

<div class="acp-section">
  <div class="acp-container">
    <h1 class="acp-hero-h1">Blog</h1>
    <p class="acp-subtitle" style="max-width:780px;">
      What your agents actually cost, and how to control every tool call they make — permissions, allowlists, audit trails, real metered data, and the occasional incident post-mortem.
    </p>

    <div class="acp-topic-hub-row">
      <span class="acp-topic-hub-label">Browse by topic:</span>
      <a href="/blog/claude-code/">Claude Code</a>
      <a href="/blog/agent-costs/">Agent costs</a>
      <a href="/blog/tool-policy/">Tool permissions &amp; policy</a>
      <a href="/blog/mcp-security/">MCP security</a>
    </div>

    <div class="acp-topic-hub-row">
      <span class="acp-topic-hub-label">Browse by series:</span>
      
        
        
        <a href="/series/"> <span style="opacity:0.6;font-weight:500;">()</span></a>
        
      
    </div>

    <!-- Featured / Start here -->
    <div class="acp-featured-block">
      <div class="acp-featured-label">/ START HERE</div>
      <div class="acp-featured-grid">
        <a href="/blog/what-280k-agent-tool-calls-look-like" class="acp-featured-card" data-track="Blog Featured: Cost Teardown">
          <div class="acp-featured-kicker">COST &middot; METERED DATA</div>
          <div class="acp-featured-title">What 285,000 Agent Tool Calls Actually Cost</div>
          <div class="acp-featured-desc">Real metered data, not estimates. The tools are nearly free — the bill is the agentic loop, and one model on it drove 80% of the spend.</div>
        </a>
        <a href="/blog/control-plane-not-gateway" class="acp-featured-card" data-track="Blog Featured: Control Plane">
          <div class="acp-featured-kicker">CATEGORY &middot; WHAT IT IS</div>
          <div class="acp-featured-title">Your AI agents need a control plane, not another gateway</div>
          <div class="acp-featured-desc">API gateways proxy traffic. LLM gateways proxy prompts. Neither governs what an autonomous agent does with your tools. Why the control plane is different.</div>
        </a>
        <a href="/blog/the-three-party-identity-gap" class="acp-featured-card" data-track="Blog Featured: Three-Party">
          <div class="acp-featured-kicker">IDENTITY &middot; THE THREE-PARTY PROBLEM</div>
          <div class="acp-featured-title">Your AI Agent Calls Your API. Whose Permissions Is It Using?</div>
          <div class="acp-featured-desc">Agents call your backend on behalf of users, but your systems can't verify who initiated the request. The identity gap, and the real risk.</div>
        </a>
        <a href="/blog/stop-your-agent-from-deleting-your-database" class="acp-featured-card" data-track="Blog Featured: Stop Delete DB">
          <div class="acp-featured-kicker">RISK &middot; IN THREE STEPS</div>
          <div class="acp-featured-title">Stop your AI agent from deleting your production database</div>
          <div class="acp-featured-desc">If your agent has destructive credentials, it can use them — and recovery is rarely possible. How to put a control plane between its decision and prod.</div>
        </a>
      </div>
    </div>

    <div class="acp-all-posts-label">/ ALL POSTS</div>

    <div id="acp-tag-filter">
      <div class="acp-tag-row">
        <button class="acp-tag-btn acp-tag-active" data-tag="all">All</button>
        <span class="acp-tag-divider"></span>
        <button class="acp-tag-btn" data-tag="architecture">Architecture</button>
        <button class="acp-tag-btn" data-tag="mcp">MCP</button>
        <button class="acp-tag-btn" data-tag="identity">Identity</button>
        <button class="acp-tag-btn" data-tag="defense-in-depth">Safety</button>
        <button class="acp-tag-btn" data-tag="incident">Security Incidents</button>
        <button class="acp-tag-btn" data-tag="compliance">Compliance</button>
        <button class="acp-tag-btn" data-tag="agentgovbench">AgentGovBench</button>
        <button class="acp-tag-btn" data-tag="cost">Cost</button>
        <button class="acp-tag-btn" data-tag="security-research">Security Research</button>
        <button class="acp-tag-btn" data-tag="benchmark">Benchmark</button>
        <button class="acp-tag-btn" data-tag="standards">Standards</button>
        <button class="acp-tag-btn" data-tag="agents-building-agents">Agents building agents</button>
        <button class="acp-tag-btn" data-tag="supply-chain">Supply Chain</button>
        <button class="acp-tag-btn" data-tag="anthropic">Anthropic SDK</button>
        <button class="acp-tag-btn" data-tag="news">News</button>
      </div>

      <div class="acp-tag-row" style="margin-top:8px;">
        <span class="acp-topic-hub-label">Sort:</span>
        <button class="acp-tag-btn acp-sort-btn acp-tag-active" data-sort="editorial">Featured</button>
        <button class="acp-tag-btn acp-sort-btn" data-sort="newest">Newest</button>
        <button class="acp-tag-btn acp-sort-btn" data-sort="oldest">Oldest</button>
      </div>

      <div id="acp-tag-status" class="acp-tag-status"></div>
    </div>

    <div id="acp-post-list">
      
      

       Pinned posts in editorial order. 
      
        
        
        <a href="" class="acp-linkcard acp-blog-card" data-tags="" data-date="">
          <div class="acp-blog-card-header">
            <div class="acp-linkcard-title acp-blog-card-title"></div>
            <div class="acp-blog-card-tags">
              
              <span class="acp-tag-pill"></span>
              
            </div>
          </div>
          <div class="acp-linkcard-desc"></div>
          <div class="acp-blog-card-date"></div>
        </a>
        
      

       Anything not featured and not pinned, by date desc. 
      
        
        <a href="" class="acp-linkcard acp-blog-card" data-tags="" data-date="">
          <div class="acp-blog-card-header">
            <div class="acp-linkcard-title acp-blog-card-title"></div>
            <div class="acp-blog-card-tags">
              
              <span class="acp-tag-pill"></span>
              
            </div>
          </div>
          <div class="acp-linkcard-desc"></div>
          <div class="acp-blog-card-date"></div>
        </a>
        
      
    </div>

    <div id="acp-tag-empty" style="display:none;text-align:center;padding:48px 0;color:var(--color-text-secondary);">
      No posts match this combination of filters.<br>
      <button class="acp-tag-btn" id="acp-tag-clear-empty" style="margin-top:12px;">Clear filters</button>
    </div>
  </div>
</div>

<style>
.acp-topic-hub-row {
  margin-top: 18px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 12px;
  align-items: center;
  font-size: 13px;
}
.acp-topic-hub-label {
  color: var(--color-text-secondary);
  font-size: 13px;
}
.acp-topic-hub-row a {
  display: inline-block;
  padding: 4px 14px;
  border-radius: 100px;
  border: 1px solid var(--color-border);
  color: var(--color-text-secondary);
  text-decoration: none;
  transition: all 0.15s ease;
}
.acp-topic-hub-row a:hover {
  border-color: var(--color-accent);
  color: var(--color-accent);
}
.acp-featured-block {
  margin-top: 32px;
}
.acp-featured-label,
.acp-all-posts-label {
  font-family: var(--acp-font-mono, 'JetBrains Mono', monospace);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  color: var(--color-accent);
  margin-bottom: 12px;
}
.acp-all-posts-label {
  margin-top: 40px;
  color: var(--color-text-secondary);
}
.acp-featured-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}
.acp-featured-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 18px 20px;
  border: 1px solid var(--color-border);
  border-radius: 10px;
  background: var(--color-surface, var(--color-bg));
  text-decoration: none;
  transition: border-color 160ms, transform 160ms, box-shadow 160ms;
}
.acp-featured-card:hover {
  border-color: var(--color-accent);
  transform: translateY(-1px);
  box-shadow: 0 4px 18px rgba(79, 70, 229, 0.08);
}
.acp-featured-kicker {
  font-family: var(--acp-font-mono, 'JetBrains Mono', monospace);
  font-size: 10px;
  letter-spacing: 0.1em;
  color: var(--color-text-secondary);
}
.acp-featured-title {
  font-size: 16px;
  font-weight: 600;
  color: var(--color-text);
  line-height: 1.35;
}
.acp-featured-desc {
  font-size: 13.5px;
  color: var(--color-text-secondary);
  line-height: 1.5;
}
@media (max-width: 720px) {
  .acp-featured-grid { grid-template-columns: 1fr; }
}

#acp-tag-filter {
  margin-top: 24px;
}
.acp-tag-group {
  margin-top: 14px;
}
.acp-tag-group-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-secondary);
  margin-bottom: 6px;
}
.acp-tag-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.acp-tag-divider {
  height: 1px;
  width: 100%;
  background: var(--color-border);
  margin: 4px 0 8px;
}
.acp-tag-btn {
  padding: 6px 14px;
  border-radius: 100px;
  border: 1px solid var(--color-border);
  background: var(--color-bg);
  color: var(--color-text-secondary);
  font-size: 13px;
  font-family: var(--acp-font-sans);
  cursor: pointer;
  transition: all 0.15s ease;
}
.acp-tag-btn:hover {
  border-color: var(--color-accent);
  color: var(--color-accent);
}
.acp-tag-btn.acp-tag-active {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: #ffffff;
}
.acp-tag-status {
  margin-top: 16px;
  font-size: 13px;
  color: var(--color-text-secondary);
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.acp-tag-status .count {
  font-weight: 600;
  color: var(--color-text);
}
.acp-tag-status button.clear {
  font-size: 12px;
  background: none;
  border: none;
  color: var(--color-accent);
  cursor: pointer;
  padding: 0;
  text-decoration: underline;
  font-family: var(--acp-font-sans);
}
.acp-tag-pill {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 100px;
  background: var(--color-accent-light);
  color: var(--color-accent);
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
}

/* Post-list layout lives here in the stylesheet, NOT in an inline style
   attribute: the tag-filter script re-shows the list by clearing
   `listEl.style.display` (setting it to ''), which *removes* the property
   from the inline style attribute. When display:grid was inline, that
   wiped the grid on every page load and the <a> cards degraded to inline
   boxes with fragmented backgrounds (worst on mobile). With the rule
   here, clearing the inline property falls back to grid. */
#acp-post-list {
  margin-top: 20px;
  display: grid;
  gap: 16px;
}
/* Honest degrade: cards stay block-level even if the list ever stops
   being a grid (grid items are blockified, but don't depend on it). */
.acp-blog-card {
  display: block;
}

/* Blog card responsive layout. On wide screens, title and tags share
   a row with tags right-aligned. On narrow screens (<700px), the row
   stacks so long titles aren't squeezed by tag pills. */
.acp-blog-card-header {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  flex-wrap: wrap;
}
.acp-blog-card-title {
  flex: 1 1 240px;
  min-width: 0;
  word-break: break-word;
}
.acp-blog-card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  flex-shrink: 0;
}
.acp-blog-card-date {
  margin-top: 6px;
  font-family: var(--acp-font-mono, 'JetBrains Mono', monospace);
  font-size: 11px;
  color: var(--color-text-secondary);
  letter-spacing: 0.04em;
}

@media (max-width: 700px) {
  .acp-blog-card-header {
    flex-direction: column;
    gap: 8px;
  }
  .acp-blog-card-title {
    flex: 1 1 auto;
    font-size: 15px;
  }
  .acp-blog-card-tags {
    order: 2;
  }
  .acp-blog-card-tags .acp-tag-pill {
    font-size: 11px;
    padding: 2px 8px;
  }
  .acp-tag-btn {
    padding: 5px 12px;
    font-size: 13px;
  }
}
</style>

<script>
(function() {
  var buttons = document.querySelectorAll('.acp-tag-btn[data-tag]');
  var posts = document.querySelectorAll('#acp-post-list .acp-linkcard');
  var allBtn = document.querySelector('.acp-tag-btn[data-tag="all"]');
  var statusEl = document.getElementById('acp-tag-status');
  var emptyEl = document.getElementById('acp-tag-empty');
  var listEl = document.getElementById('acp-post-list');
  var clearBtnInEmpty = document.getElementById('acp-tag-clear-empty');

  /** Active tag set (Set<string>). Empty = "all". */
  var active = new Set();

  // ── Sort control: editorial (pinned-first, as rendered) / newest / oldest ──
  var sortBtns = document.querySelectorAll('.acp-sort-btn');
  var originalOrder = Array.prototype.slice.call(posts);
  function applySort(mode) {
    var nodes;
    if (mode === 'editorial') {
      nodes = originalOrder.slice();
    } else {
      nodes = Array.prototype.slice.call(posts).sort(function(a, b) {
        var da = parseInt(a.getAttribute('data-date') || '0', 10);
        var db = parseInt(b.getAttribute('data-date') || '0', 10);
        return mode === 'newest' ? db - da : da - db;
      });
    }
    nodes.forEach(function(n) { listEl.appendChild(n); });
    sortBtns.forEach(function(b) {
      b.classList.toggle('acp-tag-active', b.getAttribute('data-sort') === mode);
    });
  }
  sortBtns.forEach(function(b) {
    b.addEventListener('click', function() { applySort(b.getAttribute('data-sort')); });
  });

  function syncButtons() {
    buttons.forEach(function(b) {
      var tag = b.getAttribute('data-tag');
      if (tag === 'all') {
        b.classList.toggle('acp-tag-active', active.size === 0);
      } else {
        b.classList.toggle('acp-tag-active', active.has(tag));
      }
    });
  }

  function applyFilter() {
    var visibleCount = 0;
    posts.forEach(function(post) {
      if (active.size === 0) {
        post.style.display = '';
        visibleCount++;
        return;
      }
      var postTags = (post.getAttribute('data-tags') || '').split(',').map(function(s) { return s.trim(); });
      // AND logic: post must include every active tag
      var matches = Array.from(active).every(function(t) { return postTags.indexOf(t) !== -1; });
      post.style.display = matches ? '' : 'none';
      if (matches) visibleCount++;
    });

    // Status line
    if (active.size === 0) {
      statusEl.innerHTML = '<span><span class="count">' + posts.length + '</span> posts</span>';
    } else {
      var tagsHtml = Array.from(active).map(function(t) { return '<span class="acp-tag-pill">' + t + '</span>'; }).join(' ');
      statusEl.innerHTML =
        '<span><span class="count">' + visibleCount + '</span> matching: ' + tagsHtml + '</span>' +
        ' <button class="clear" type="button">Clear filters</button>';
      var clearBtn = statusEl.querySelector('button.clear');
      if (clearBtn) clearBtn.addEventListener('click', clearAll);
    }

    if (visibleCount === 0 && active.size > 0) {
      listEl.style.display = 'none';
      emptyEl.style.display = '';
    } else {
      listEl.style.display = '';
      emptyEl.style.display = 'none';
    }
  }

  function syncUrl() {
    var url;
    if (active.size === 0) {
      url = '/blog/';
    } else {
      url = '/blog/?tags=' + encodeURIComponent(Array.from(active).join(','));
    }
    history.replaceState(null, '', url);
  }

  function toggleTag(tag) {
    if (tag === 'all') {
      clearAll();
      return;
    }
    if (active.has(tag)) {
      active.delete(tag);
    } else {
      active.add(tag);
    }
    syncButtons();
    applyFilter();
    syncUrl();
  }

  function clearAll() {
    active.clear();
    syncButtons();
    applyFilter();
    syncUrl();
  }

  buttons.forEach(function(btn) {
    btn.addEventListener('click', function() {
      toggleTag(btn.getAttribute('data-tag'));
    });
  });

  if (clearBtnInEmpty) {
    clearBtnInEmpty.addEventListener('click', clearAll);
  }

  // Initial state from URL
  var params = new URLSearchParams(location.search);
  var tagsParam = params.get('tags');
  if (tagsParam) {
    tagsParam.split(',').forEach(function(t) {
      var trimmed = t.trim();
      if (trimmed) active.add(trimmed);
    });
  } else {
    // Backwards-compat with old single-tag URLs
    var singleTag = params.get('tag');
    if (singleTag) active.add(singleTag);
  }
  syncButtons();
  applyFilter();
})();
</script>
