lean-ctx 3.9.9

Context Runtime for AI Agents with CCP. 71 MCP tools, 10 read modes, 95+ compression patterns, cross-session memory (CCP), persistent AI knowledge with temporal facts + contradiction detection, multi-agent context sharing, LITM-aware positioning, AAAK compact format, adaptive compression with Thompson Sampling bandits. Supports 24+ AI tools. Reduces LLM token consumption by up to 99%.
Documentation
<!doctype html>
<html lang="en" data-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="dark light">
<title>lean-ctx · Gateway Console</title>
<link rel="stylesheet" href="/static/fonts/fonts.css">
<link rel="stylesheet" href="/static/admin.css">
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='7' fill='%2309090b'/%3E%3Cpath d='M10 8v16h12' stroke='%2334d399' stroke-width='3' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E">
</head>
<body>

<!-- ── Login ─────────────────────────────────────────────────────────── -->
<div id="login" class="login-wrap" hidden>
  <div class="login-card">
    <div class="login-brand">
      <span class="login-glyph"></span>
      <div>
        <div class="login-title">Gateway Console</div>
        <div class="login-sub">lean-ctx · self-hosted org gateway</div>
      </div>
    </div>
    <label class="login-label" for="token-input">Admin token</label>
    <form id="login-form" autocomplete="off">
      <input id="token-input" class="login-input" type="password"
             placeholder="LEAN_CTX_GATEWAY_ADMIN_TOKEN" spellcheck="false" autofocus>
      <button id="login-btn" class="btn btn-primary" type="submit">Sign in</button>
    </form>
    <div id="login-error" class="login-error" hidden></div>
    <div class="login-hint">
      The token is the value of <code>LEAN_CTX_GATEWAY_ADMIN_TOKEN</code> on the
      gateway host. It is kept in this tab's session only — never in URLs or
      persistent storage. Failed attempts are rate-limited and logged.
    </div>
  </div>
</div>

<!-- ── App ───────────────────────────────────────────────────────────── -->
<div id="app" hidden>
  <header class="topbar">
    <div class="topbar-brand">
      <span class="topbar-glyph"></span>
      <div class="topbar-names">
        <span id="org-label" class="topbar-org">Gateway Console</span>
        <span class="topbar-product">lean-ctx gateway <span id="version" class="mono"></span></span>
      </div>
    </div>
    <div class="topbar-right">
      <span id="updated" class="updated" hidden><i class="pulse-dot"></i><span id="updated-text">live</span></span>
      <div id="window-picker" class="seg" role="tablist" aria-label="Time window">
        <button class="seg-btn" data-days="1">24h</button>
        <button class="seg-btn" data-days="7">7d</button>
        <button class="seg-btn active" data-days="30">30d</button>
        <button class="seg-btn" data-days="90">90d</button>
      </div>
      <button id="refresh-btn" class="icon-btn" title="Refresh"></button>
      <button id="theme-btn" class="icon-btn" title="Toggle theme"></button>
      <button id="logout-btn" class="icon-btn" title="Sign out"></button>
    </div>
  </header>

  <main class="content">
    <!-- Health strip: store / drops / routing / providers -->
    <section id="health-strip" class="health-strip" aria-label="Gateway status"></section>

    <!-- KPI grid -->
    <section class="kpi-grid">
      <div class="kpi-card">
        <div class="kpi-label">Spend <span class="kpi-window-label"></span></div>
        <div class="kpi-value mono" id="kpi-spend"></div>
        <div class="kpi-foot" id="kpi-spend-foot"></div>
      </div>
      <div class="kpi-card kpi-accent">
        <div class="kpi-label">Saved <span class="kpi-window-label"></span></div>
        <div class="kpi-value mono accent" id="kpi-saved"></div>
        <div class="kpi-foot" id="kpi-saved-foot"></div>
      </div>
      <div class="kpi-card">
        <div class="kpi-label">Requests</div>
        <div class="kpi-value mono" id="kpi-requests"></div>
        <div class="kpi-foot" id="kpi-requests-foot"></div>
      </div>
      <div class="kpi-card">
        <div class="kpi-label">Active people</div>
        <div class="kpi-value mono" id="kpi-persons"></div>
        <div class="kpi-foot" id="kpi-persons-foot"></div>
      </div>
      <div class="kpi-card kpi-projection">
        <div class="kpi-label">Org projection <span class="info-dot" title="Per-active-person savings × configured seats, scaled to a 30-day month. A planning extrapolation — not a billing number.">i</span></div>
        <div class="kpi-value mono" id="kpi-projection"></div>
        <div class="kpi-foot" id="kpi-projection-foot"></div>
      </div>
    </section>

    <!-- Trend chart -->
    <section class="panel">
      <div class="panel-head">
        <h2>Spend &amp; savings trend</h2>
        <div class="legend">
          <span class="legend-item"><i class="dot dot-cost"></i>Spend</span>
          <span class="legend-item"><i class="dot dot-saved"></i>Saved</span>
          <span class="legend-item"><i class="dot dot-ref"></i>Baseline (avoided-cost reference)</span>
        </div>
      </div>
      <div class="chart-wrap"><canvas id="trend-chart" height="240"></canvas></div>
      <div id="trend-empty" class="empty empty-onboard" hidden>
        <p><b>No usage in this window yet.</b> Point a client at the gateway and events appear within seconds:</p>
        <pre class="mono">export ANTHROPIC_BASE_URL=http://&lt;gateway-host&gt;:8484
export ANTHROPIC_AUTH_TOKEN=&lt;personal key — see `lean-ctx gateway keys add`&gt;</pre>
      </div>
    </section>

    <!-- Breakdown -->
    <section class="panel">
      <div class="panel-head">
        <h2>Usage breakdown</h2>
        <div class="panel-tools">
          <div class="seg seg-sm" id="group-picker" role="tablist" aria-label="Group by">
            <button class="seg-btn active" data-group="person">People</button>
            <button class="seg-btn" data-group="project">Projects</button>
            <button class="seg-btn" data-group="model">Models</button>
            <button class="seg-btn" data-group="provider">Providers</button>
          </div>
          <input id="filter-input" class="filter-input" type="search" placeholder="Filter…" spellcheck="false">
          <button id="export-breakdown" class="tool-btn" title="Download the current view as CSV">CSV ↓</button>
        </div>
      </div>
      <div class="table-wrap">
        <table class="data-table" id="breakdown-table">
          <thead><tr id="breakdown-head"></tr></thead>
          <tbody id="breakdown-body"></tbody>
        </table>
      </div>
      <div id="breakdown-empty" class="empty" hidden>Nothing matches.</div>
    </section>

    <!-- Tool channel (MCP observe, GL#91) -->
    <section class="panel" id="mcp-panel" hidden>
      <div class="panel-head">
        <h2>Tool channel <span class="muted">MCP · observed</span></h2>
        <div class="panel-tools">
          <button id="export-mcp" class="tool-btn" title="Download tool activity as CSV">CSV ↓</button>
        </div>
      </div>
      <div id="mcp-strip" class="health-strip" aria-label="MCP servers"></div>
      <div class="kpi-grid kpi-grid-sub">
        <div class="kpi-card">
          <div class="kpi-label">Tool calls <span class="kpi-window-label"></span></div>
          <div class="kpi-value mono" id="mcp-kpi-calls"></div>
          <div class="kpi-foot" id="mcp-kpi-calls-foot"></div>
        </div>
        <div class="kpi-card">
          <div class="kpi-label">Context tokens <span class="info-dot" title="Tokens of tool results flowing back into agent sessions — context the org pays for on every subsequent model turn.">i</span></div>
          <div class="kpi-value mono" id="mcp-kpi-tokens"></div>
          <div class="kpi-foot" id="mcp-kpi-tokens-foot"></div>
        </div>
        <div class="kpi-card">
          <div class="kpi-label">Context cost <span class="info-dot" title="Tool-result tokens priced at the reference model's input rate — what this context costs each time it is sent to a model.">i</span></div>
          <div class="kpi-value mono" id="mcp-kpi-cost"></div>
          <div class="kpi-foot" id="mcp-kpi-cost-foot"></div>
        </div>
        <div class="kpi-card">
          <div class="kpi-label">Changed definitions <span class="info-dot" title="Tools whose definition fingerprint (SHA-256) changed since first seen — review them: a silent redefinition is the MCP 'rug pull' pattern.">i</span></div>
          <div class="kpi-value mono" id="mcp-kpi-changed"></div>
          <div class="kpi-foot" id="mcp-kpi-changed-foot"></div>
        </div>
      </div>
      <div class="table-wrap">
        <table class="data-table" id="mcp-table">
          <thead>
            <tr>
              <th>Server</th>
              <th>Tool</th>
              <th class="num">Calls</th>
              <th class="num">Errors</th>
              <th class="num">People</th>
              <th class="num">Result tok</th>
              <th class="num">Context cost</th>
              <th class="num">p50 ms</th>
              <th>Definition</th>
            </tr>
          </thead>
          <tbody id="mcp-body"></tbody>
        </table>
      </div>
      <div id="mcp-empty" class="empty empty-onboard" hidden>
        <p><b>No MCP servers registered yet.</b> The tool channel monitors every MCP tool your org uses — calls, errors, latency, context cost, and schema drift (rug-pull detection).</p>
        <p style="margin-top:8px">Register an upstream server in <code>config.toml</code>:</p>
        <pre class="mono">[[gateway_server.mcp_servers]]
id = "my-server"
url = "http://host:port"
auth_env = "MY_SERVER_TOKEN"   # optional</pre>
        <p style="margin-top:8px;color:var(--muted)">Then point MCP clients at the gateway: <code>http://&lt;gateway&gt;:8484/mcp/my-server</code></p>
      </div>
    </section>

    <!-- Detail: raw rows -->
    <section class="panel">
      <div class="panel-head">
        <h2>All segments <span class="muted">person × project × model × provider</span></h2>
        <div class="panel-tools">
          <button id="export-detail" class="tool-btn" title="Download all segments as CSV">CSV ↓</button>
        </div>
      </div>
      <div class="table-wrap">
        <table class="data-table data-table-sm" id="detail-table">
          <thead>
            <tr>
              <th data-sort="person">Person</th>
              <th data-sort="project">Project</th>
              <th data-sort="model">Model</th>
              <th data-sort="provider">Provider</th>
              <th class="num" data-sort="requests">Req</th>
              <th class="num" data-sort="input_tokens">In tok</th>
              <th class="num" data-sort="output_tokens">Out tok</th>
              <th class="num" data-sort="saved_usd">Saved</th>
              <th class="num" data-sort="cost_usd">Cost</th>
            </tr>
          </thead>
          <tbody id="detail-body"></tbody>
        </table>
      </div>
      <div id="detail-empty" class="empty" hidden>No segments in this window.</div>
    </section>

    <footer class="foot">
      <span id="foot-window" class="mono"></span>
      <span>numbers from <code>usage_events</code> + <code>mcp_events</code> · projection is an extrapolation, not billing</span>
    </footer>
  </main>
</div>

<div id="toast" class="toast" hidden></div>

<script src="/static/vendor/chart.umd.min.js"></script>
<script src="/static/admin.js"></script>
</body>
</html>