---
title: Interface Changes
---

```js
import {API} from "./components/config.js";
```

```js
const [published, draft, repos] = await Promise.all([
  fetch(`${API}/interface-changes/?status=published`).then(r => r.ok ? r.json() : []),
  fetch(`${API}/interface-changes/?status=draft`).then(r => r.ok ? r.json() : []),
  fetch(`${API}/repos/`).then(r => r.ok ? r.json() : []),
]);
```

```js
const repoMap = Object.fromEntries(repos.map(r => [r.slug, r]));

const CHANGE_TYPE_COLOR = {
  breaking:    "#ef4444",
  removal:     "#f97316",
  deprecation: "#f59e0b",
  additive:    "#22c55e",
};

function changeBadge(type) {
  const color = CHANGE_TYPE_COLOR[type] ?? "#6b7280";
  return htl.html`<span style="
    background:${color};color:#fff;font-size:11px;font-weight:700;
    padding:2px 7px;border-radius:10px;text-transform:uppercase;letter-spacing:.04em
  ">${type}</span>`;
}

function interfaceBadge(type) {
  return htl.html`<span style="
    background:#3b82f6;color:#fff;font-size:10px;font-weight:600;
    padding:1px 6px;border-radius:8px
  ">${type}</span>`;
}
```

# Interface Changes

Track breaking and additive mutations to published interfaces across repos.
Publishing a change sends inbox notifications to all affected agents.

<div style="display:flex;gap:16px;margin-bottom:24px">
  <div style="background:#fef2f2;border:1px solid #fca5a5;border-radius:8px;padding:12px 20px;text-align:center">
    <div style="font-size:28px;font-weight:700;color:#dc2626">${published.filter(c => c.change_type === "breaking").length}</div>
    <div style="font-size:12px;color:#6b7280">Breaking (live)</div>
  </div>
  <div style="background:#fff7ed;border:1px solid #fdba74;border-radius:8px;padding:12px 20px;text-align:center">
    <div style="font-size:28px;font-weight:700;color:#ea580c">${published.filter(c => c.change_type === "deprecation").length}</div>
    <div style="font-size:12px;color:#6b7280">Deprecations (live)</div>
  </div>
  <div style="background:#f0fdf4;border:1px solid #86efac;border-radius:8px;padding:12px 20px;text-align:center">
    <div style="font-size:28px;font-weight:700;color:#16a34a">${published.filter(c => c.change_type === "additive").length}</div>
    <div style="font-size:12px;color:#6b7280">Additive (live)</div>
  </div>
  <div style="background:#f9fafb;border:1px solid #d1d5db;border-radius:8px;padding:12px 20px;text-align:center">
    <div style="font-size:28px;font-weight:700;color:#374151">${draft.length}</div>
    <div style="font-size:12px;color:#6b7280">Drafts</div>
  </div>
</div>

## Planned changes

```js
const planned = [...published, ...draft].filter(c => c.planned_for);
planned.sort((a, b) => a.planned_for.localeCompare(b.planned_for));
```

```js
if (planned.length === 0) {
  display(htl.html`<p style="color:#6b7280;font-style:italic">No changes with a planned date.</p>`);
} else {
  display(htl.html`<table style="width:100%;border-collapse:collapse;font-size:13px">
    <thead><tr style="border-bottom:2px solid #e5e7eb">
      <th style="text-align:left;padding:6px 8px">Date</th>
      <th style="text-align:left;padding:6px 8px">Change</th>
      <th style="text-align:left;padding:6px 8px">Repo</th>
      <th style="text-align:left;padding:6px 8px">Status</th>
    </tr></thead>
    <tbody>
      ${planned.map(c => htl.html`<tr style="border-bottom:1px solid #f3f4f6">
        <td style="padding:6px 8px;white-space:nowrap;color:#374151">${c.planned_for}</td>
        <td style="padding:6px 8px">${changeBadge(c.change_type)} ${c.title}</td>
        <td style="padding:6px 8px;color:#6b7280">${c.origin_repo_slug ?? c.repo_slug}</td>
        <td style="padding:6px 8px">${c.status}</td>
      </tr>`)}
    </tbody>
  </table>`);
}
```

## Published changes

```js
if (published.length === 0) {
  display(htl.html`<p style="color:#6b7280;font-style:italic">No published changes.</p>`);
} else {
  display(htl.html`<div style="display:flex;flex-direction:column;gap:12px">
    ${published.map(c => htl.html`
      <div style="border:1px solid #e5e7eb;border-radius:8px;padding:14px 16px">
        <div style="display:flex;align-items:center;gap:8px;margin-bottom:6px;flex-wrap:wrap">
          ${changeBadge(c.change_type)}
          ${interfaceBadge(c.interface_type)}
          <strong style="font-size:14px">${c.title}</strong>
        </div>
        <div style="font-size:12px;color:#6b7280;margin-bottom:6px">
          Repo: <strong>${c.origin_repo_slug ?? c.repo_slug}</strong>
          ${c.published_at ? htl.html` · Published ${c.published_at.slice(0,10)}` : ""}
          ${c.affected_repo_slugs?.length ? htl.html` · Affects: ${c.affected_repo_slugs.join(", ")}` : ""}
        </div>
        <details style="font-size:13px;color:#374151">
          <summary style="cursor:pointer;color:#6b7280">Description</summary>
          <pre style="margin-top:6px;white-space:pre-wrap;font-family:inherit">${c.description}</pre>
        </details>
        ${c.affected_paths?.length ? htl.html`
          <div style="margin-top:6px;font-size:12px">
            <strong>Paths:</strong>
            ${c.affected_paths.map(p => htl.html`<code style="background:#f3f4f6;padding:1px 5px;border-radius:4px;margin:0 2px">${p}</code>`)}
          </div>` : ""}
      </div>
    `)}
  </div>`);
}
```

## Drafts

```js
if (draft.length === 0) {
  display(htl.html`<p style="color:#6b7280;font-style:italic">No draft changes.</p>`);
} else {
  display(htl.html`<table style="width:100%;border-collapse:collapse;font-size:13px">
    <thead><tr style="border-bottom:2px solid #e5e7eb">
      <th style="text-align:left;padding:6px 8px">Title</th>
      <th style="text-align:left;padding:6px 8px">Repo</th>
      <th style="text-align:left;padding:6px 8px">Type</th>
      <th style="text-align:left;padding:6px 8px">Affected</th>
    </tr></thead>
    <tbody>
      ${draft.map(c => htl.html`<tr style="border-bottom:1px solid #f3f4f6">
        <td style="padding:6px 8px">${c.title}</td>
        <td style="padding:6px 8px;color:#6b7280">${c.repo_slug}</td>
        <td style="padding:6px 8px">${changeBadge(c.change_type)} ${interfaceBadge(c.interface_type)}</td>
        <td style="padding:6px 8px;color:#6b7280">${(c.affected_repo_slugs ?? []).join(", ") || "—"}</td>
      </tr>`)}
    </tbody>
  </table>`);
}
```
