ECCP
exine

layer3/client.ts

A client for builders who prefer the sharp edges visible.

exine is a code-shaped ECCP client. It keeps keyboard-first workflows, structured output, and plugin hooks close at hand so developers and operators can compose their own interface without rewriting the protocol.

exine / host shell

$ exine login --homeserver https://node.eccp.dev

$ exine rooms watch --tag incident-response --format ndjson

$ exine plugins enable bot-host --capability rooms:write

$ exine sync tail --since state://shadow-room/main

CLI-native

Pipe room events into scripts, tail sync state, and automate operational workflows from the same client surface.

Plugin host

Extensions can subscribe to events, add commands, and host automation without forking the entire application.

Composable output

Structured results make exine useful inside CI systems, moderation dashboards, and custom bot operators.

Plugin API

Bot host capability in plain TypeScript.

Plugins can register commands, inspect federation peers, and host automation inside the client with explicit capability grants instead of hidden side channels.

plugins/ops-bot-host.ts

TypeScript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { definePlugin } from "@eccp/exine-sdk";

export default definePlugin({
  name: "ops-bot-host",
  capabilities: ["rooms:read", "rooms:write", "bot:host"],
  async activate(host) {
    host.on("message.received", async (event) => {
      if (!event.room.tags.includes("ops")) return;

      await host.bot.reply(event.roomId, {
        body: \`ack \${event.eventId}\`,
        shadow: true
      });
    });

    await host.commands.register("peers", async () => {
      const peers = await host.federation.listPeers();
      return peers.map(({ serverName, latencyMs }) => ({
        serverName,
        latencyMs
      }));
    });
  }
});

Why exine exists

ECCP needs a client that treats automation, observability, and extensibility as product features. exine is that Layer 3 surface.