fix: correct Abiba platform label (pi not openclaw), add plugin skeletons, shared config, fix health port

- Replace all 'openclaw' references with 'pi' (pi coding harness)
- Fix Git remote URL in CONTEXT.md
- Harmonize health port to 9200 across all docs
- Add config.yaml.example with full schema
- Add pi-zulip-extension skeleton (TypeScript, pi Extension API)
- Add hermes-zulip-plugin skeleton (Python, BasePlatformAdapter)
- Add agent-zero-plugin skeleton (Python, A0 plugin API)
- Update ADR-007 with pi extension docs reference
- Document private topic ACL v1 limitation in CONTEXT.md
This commit is contained in:
Abiba (pi)
2026-06-19 23:55:19 +00:00
parent fe434553a8
commit 66c6d4966e
13 changed files with 320 additions and 56 deletions
+22
View File
@@ -0,0 +1,22 @@
{
"name": "pi-zulip-extension",
"version": "0.1.0",
"description": "pi extension for Zulip agent communication — connects Abiba to the Sysloggh agent mesh",
"main": "src/index.ts",
"type": "module",
"scripts": {
"build": "tsc",
"check": "tsc --noEmit"
},
"dependencies": {
"zulip-js": "^2.0.0",
"yaml": "^2.0.0"
},
"devDependencies": {
"@earendil-works/pi-coding-agent": "*",
"typescript": "^5.0.0"
},
"keywords": ["pi", "zulip", "agent", "abiba", "sysloggh"],
"license": "UNLICENSED",
"private": true
}
+120
View File
@@ -0,0 +1,120 @@
/**
* pi-zulip-extension — Zulip agent communication plugin for pi agents
*
* Deploy to: ~/.pi/agent/extensions/zulip.ts
* Config: config.yaml (alongside extension, or symlinked)
*
* Connects a pi agent (Abiba) to the Sysloggh Zulip agent mesh.
* Listens for @mentions of abiba-bot in #agent-hub and forwards
* to the pi agent. Responses are posted back to the same Zulip topic.
*
* @see ADR-007: Platform-native plugin contracts
* @see docs/ARCHITECTURE.md
*/
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { readFileSync } from "fs";
import { parse } from "yaml";
// ---------------------------------------------------------------------------
// Config
// ---------------------------------------------------------------------------
interface ZulipConfig {
agent: {
name: string;
display_name: string;
zulip_bot_name: string;
owner_email: string;
private_topic: string;
};
zulip: {
server_url: string;
email: string;
api_key: string;
stream: string;
all_bots_user_id: number;
};
error_handling: {
timeout_seconds: number;
retry_count: number;
retry_delay_seconds: number;
graceful_message: string;
};
monitoring: {
health_endpoint_enabled: boolean;
health_port: number;
log_level: string;
};
}
function loadConfig(): ZulipConfig {
const raw = readFileSync("config.yaml", "utf-8");
const cfg = parse(raw) as ZulipConfig;
cfg.zulip.api_key = process.env["ZULIP_API_KEY"] ?? cfg.zulip.api_key;
return cfg;
}
// ---------------------------------------------------------------------------
// Extension entry point
// ---------------------------------------------------------------------------
export default function (pi: ExtensionAPI) {
const config = loadConfig();
// Health endpoint
if (config.monitoring.health_endpoint_enabled) {
startHealthServer(config);
}
pi.on("session_start", async (_event, ctx) => {
ctx.ui.notify(
`Zulip extension loaded for ${config.agent.display_name} (${config.agent.zulip_bot_name})`,
"info"
);
});
// Diagnostic tool
pi.registerTool({
name: "zulip_status",
label: "Zulip Status",
description: "Check Zulip connection status and bot identity",
parameters: {},
execute: async () => ({
connected: false, // TODO: track connection state
bot: config.agent.zulip_bot_name,
stream: config.zulip.stream,
server: config.zulip.server_url,
owner: config.agent.owner_email,
private_topic: config.agent.private_topic,
}),
});
}
// ---------------------------------------------------------------------------
// Health endpoint
// ---------------------------------------------------------------------------
function startHealthServer(config: ZulipConfig) {
const http = require("http") as typeof import("http");
const port = config.monitoring.health_port;
const startTime = Date.now();
http
.createServer((_req: any, res: any) => {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(
JSON.stringify({
status: "ok",
agent: config.agent.name,
uptime_seconds: Math.floor((Date.now() - startTime) / 1000),
zulip_connected: false,
last_message_time: null,
timestamp: new Date().toISOString(),
})
);
})
.listen(port, "127.0.0.1", () => {
console.log(`[zulip-extension] Health endpoint on :${port}`);
});
}
+14
View File
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"outDir": "dist",
"rootDir": "src",
"declaration": true,
"skipLibCheck": true
},
"include": ["src/**/*.ts"]
}