diff --git a/dashboard/observablehq.config.js b/dashboard/observablehq.config.js
index 92b0a42..d7fc3b2 100644
--- a/dashboard/observablehq.config.js
+++ b/dashboard/observablehq.config.js
@@ -27,6 +27,7 @@ export default {
{ name: "Progress", path: "/progress" },
{ name: "Services (TPSC)", path: "/tpsc" },
{ name: "Todo", path: "/todo" },
+ { name: "Tools & Apps", path: "/tools" },
// ── Sections (alphabetical) ───────────────────────────────────────────────
{
name: "Policies",
diff --git a/dashboard/src/tools.md b/dashboard/src/tools.md
new file mode 100644
index 0000000..5754f74
--- /dev/null
+++ b/dashboard/src/tools.md
@@ -0,0 +1,203 @@
+---
+title: Tools & Apps
+---
+
+```js
+import {API} from "./components/config.js";
+```
+
+```js
+// Probe local services — best-effort, timeout after 2s
+async function probe(url) {
+ try {
+ const ctrl = new AbortController();
+ const tid = setTimeout(() => ctrl.abort(), 2000);
+ const r = await fetch(url, {signal: ctrl.signal, mode: "no-cors"});
+ clearTimeout(tid);
+ return true; // no-cors = opaque response, but no throw = reachable
+ } catch { return false; }
+}
+
+// Only probe local services the browser can actually reach
+const [apiUp, giteaUp, pgadminUp] = await Promise.all([
+ probe(`${API}/state/health`),
+ probe("http://92.205.130.254:32166"),
+ probe("http://127.0.0.1:5050"),
+]);
+
+// Cluster services — mark as "unknown" unless we can check
+// (browser can't reach coulomb.social without the cluster being up;
+// just show them as static links without a live probe)
+```
+
+```js
+function dot(up) {
+ if (up === null) return html`●`;
+ return up
+ ? html`●`
+ : html`●`;
+}
+
+function appCard({name, desc, url, label, status, icon, note}) {
+ const linkEl = url
+ ? html`${label ?? url}`
+ : html`${label ?? "local app"}`;
+ return html`
+
+
${desc}
+ ${linkEl}
+ ${note ? html`
${note}
` : ""}
+
`;
+}
+```
+
+# Tools & Apps
+
+Connected applications, services, and local tools used across the Custodian ecosystem.
+
+## Local Services
+
+```js
+display(html`
+ ${appCard({
+ icon: "🗄️", name: "State Hub API", status: apiUp,
+ desc: "FastAPI backend — the source of truth for all workstream, task, and decision data.",
+ url: "http://127.0.0.1:8000/docs", label: "127.0.0.1:8000 · Swagger UI",
+ })}
+ ${appCard({
+ icon: "🔑", name: "KeePassXC", status: null,
+ desc: "Primary credential store. Holds all service secrets in the FOS group hierarchy. Single root of trust per the Credential Management Standard.",
+ label: "local desktop app",
+ note: "Standard: canon/standards/credential-management_v0.1.md",
+ })}
+ ${appCard({
+ icon: "🐘", name: "pgAdmin", status: pgadminUp,
+ desc: "PostgreSQL admin UI for the state-hub database. Start with: make db in state-hub/.",
+ url: "http://127.0.0.1:5050", label: "127.0.0.1:5050",
+ note: pgadminUp ? "" : "Start with: cd ~/the-custodian/state-hub && docker compose --profile pgadmin up -d",
+ })}
+ ${appCard({
+ icon: "🌉", name: "ops-bridge", status: null,
+ desc: "SSH reverse tunnel lifecycle manager. Keeps CoulombCore and Railiance nodes connected to the local state hub.",
+ label: "~/ops-bridge · CLI",
+ note: "bridge up / bridge status / bridge logs",
+ })}
+
`);
+```
+
+## Source Control
+
+```js
+display(html`
+ ${appCard({
+ icon: "🦊", name: "Gitea", status: giteaUp,
+ desc: "Self-hosted git server. All domain repos are mirrored here. Coulomb organisation hosts the primary remotes.",
+ url: "http://92.205.130.254:32166", label: "92.205.130.254:32166",
+ note: "Org: coulomb · also accessible as gitea.local on LAN",
+ })}
+
`);
+```
+
+## Identity & Auth (NetKingdom)
+
+Services deployed on the k3s cluster. Require cluster to be running (ThreePhoenix / CoulombCore).
+
+```js
+display(html`
+ ${appCard({
+ icon: "🪪", name: "KeyCape", status: null,
+ desc: "Lightweight OIDC orchestration layer. Binds LLDAP, Authelia, and privacyIDEA into a single IAM profile.",
+ url: "https://id.coulomb.social", label: "id.coulomb.social",
+ note: "OIDC discovery: /.well-known/openid-configuration",
+ })}
+ ${appCard({
+ icon: "🔐", name: "Authelia", status: null,
+ desc: "Authentication and authorisation server. Handles password auth, session management, and OIDC relying-party flows.",
+ url: "https://auth.coulomb.social", label: "auth.coulomb.social",
+ })}
+ ${appCard({
+ icon: "📱", name: "privacyIDEA", status: null,
+ desc: "MFA token management. Issues TOTP challenges via trigger-admin API. Backs all second-factor authentication.",
+ url: "https://pink.coulomb.social", label: "pink.coulomb.social",
+ note: "Admin portal — credentials in KeePassXC net-kingdom/privacyidea/pi-admin",
+ })}
+ ${appCard({
+ icon: "📂", name: "LLDAP", status: null,
+ desc: "Lightweight LDAP directory. Stores user accounts and group memberships queried by Authelia and KeyCape.",
+ url: "https://ldap.coulomb.social", label: "ldap.coulomb.social",
+ note: "Admin UI at :17170 · credentials in KeePassXC net-kingdom/lldap",
+ })}
+
`);
+```
+
+## Dev Tooling
+
+```js
+display(html`
+ ${appCard({
+ icon: "🤖", name: "Claude Code", status: null,
+ desc: "Primary AI coding assistant. Registered with the state-hub via MCP SSE server on :8001. The tool you're using right now.",
+ label: "local CLI · claude",
+ note: "MCP server: http://127.0.0.1:8001/sse · registered at user scope in ~/.claude.json",
+ })}
+ ${appCard({
+ icon: "📦", name: "uv", status: null,
+ desc: "Python package and project manager. Manages all Python environments across custodian, state-hub, ops-bridge, and domain repos.",
+ label: "local CLI · uv",
+ note: "uv sync · uv run · uv add",
+ })}
+
`);
+```
+
+