ari-fastify-gateway
Fastify gateway patterns for ARI's loopback-only security boundary
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Fastify gateway patterns for ARI's loopback-only security boundary
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Discord slash commands, approval routing, channel policy, button interaction patterns for OpenClaw/ARI Discord integration
Obsidian vault integration patterns — vault-analyzer.ts, /ari-vault-* commands, morning briefing snippet, PARA structure, read-only enforcement
OpenClaw plugin development patterns — hooks, manifest structure, plugin SDK, APEX/CODEX enforcement
NOVA's P1 PayThePryce pipeline — market signal ingest, card detection, price monitoring, script generation, thumbnail generation, video assembly, approval gate
CHASE's P2 Pryceless Solutions pipeline — lead discovery, 5-criteria audit, LLM qualification, Prompt Forge 4-pass lock, demo generation, outreach approval gate
NOVA's thumbnail generation pipeline — Ideogram V3 via Fal.ai (primary) + DALL-E 3 fallback, 4-variant strategy, Pokemon TCG copyright rules,
| name | ari-fastify-gateway |
| description | Fastify gateway patterns for ARI's loopback-only security boundary |
| triggers | ["gateway setup","fastify route","api endpoint","loopback server"] |
Manage ARI's Fastify-based gateway with enforced loopback-only binding (ADR-001).
Gateway MUST bind to 127.0.0.1 exclusively. This is HARDCODED and non-configurable.
// src/kernel/gateway.ts
import fastify from 'fastify';
const gateway = fastify({
logger: pinoLogger,
});
// HARDCODED - DO NOT CHANGE
const HOST = '127.0.0.1';
const PORT = config.gateway?.port ?? 3141;
await gateway.listen({ host: HOST, port: PORT });
gateway.post('/message', {
schema: {
body: MessageSchema,
response: { 200: ResponseSchema }
},
preHandler: [sanitizeMiddleware, auditMiddleware],
handler: async (request, reply) => {
const sanitized = sanitizer.sanitize(request.body);
await eventBus.emit('message:accepted', sanitized);
return { status: 'accepted', id: sanitized.id };
}
});
gateway.get('/health', async () => ({
status: 'healthy',
version: config.version,
uptime: process.uptime()
}));
gateway.get('/audit/verify', async () => {
const result = await audit.verifyChain();
return { valid: result.valid, events: result.eventCount };
});
const sanitizeMiddleware = async (request) => {
const risk = sanitizer.assessRisk(request.body);
if (risk >= 0.8) {
throw new SecurityError('Request blocked: high risk score');
}
};
const auditMiddleware = async (request) => {
await eventBus.emit('audit:log', {
action: 'request_received',
method: request.method,
path: request.url,
timestamp: new Date().toISOString()
});
};
gateway.setErrorHandler(async (error, request, reply) => {
await eventBus.emit('audit:log', {
action: 'request_error',
error: error.message,
statusCode: error.statusCode || 500
});
reply.status(error.statusCode || 500).send({
error: 'Internal Server Error',
// Never expose internal error details
});
});
# Start gateway
npm run gateway:start
# Test health
curl http://127.0.0.1:3141/health
# Test message (will be sanitized)
curl -X POST http://127.0.0.1:3141/message \
-H "Content-Type: application/json" \
-d '{"content": "test message"}'