Skip to content

Custom Emitters

The sidecar’s EmitterRegistry allows you to add custom translation targets. This lets AgentCTX translate CTX statements into any format — YAML, Terraform, Kubernetes manifests, or your own DSL.

An emitter is a pure function that converts a CTXStatement AST into a string:

interface Emitter {
emit(ast: CTXStatement): string;
emitBatch?(asts: CTXStatement[]): string; // Optional batch support
}
import type { CTXStatement } from '@agentctx/core';
const yamlEmitter = {
emit(ast: CTXStatement): string {
const lines = [
`operation: ${ast.operator}`,
`plane: ${ast.plane}`,
`target: "${ast.target}"`,
];
if (ast.filters.length > 0) {
lines.push('filters:');
for (const f of ast.filters) {
lines.push(` - type: ${f.type}`);
lines.push(` value: "${f.value}"`);
}
}
if (ast.payload) {
lines.push(`payload: "${ast.payload.raw}"`);
}
return lines.join('\n');
}
};
import { Sidecar, EmitterRegistry } from '@agentctx/core';
const registry = new EmitterRegistry();
registry.register('yaml', yamlEmitter);
const sidecar = new Sidecar(registry);
const result = sidecar.translate(ast, 'yaml');
console.log(result.output);
// operation: ?
// plane: k
// target: "auth patterns"
// filters:
// - type: tag
// value: "code"
// - type: limit
// value: "3"
TargetOutput
humanEnglish prose
surrealqlSurrealQL queries
sqlStandard SQL
restHTTP requests
graphqlGraphQL queries
mcp-jsonrpcMCP JSON-RPC messages

For emitters that can optimize multi-statement output, implement emitBatch:

const csvEmitter = {
emit(ast: CTXStatement): string {
return `${ast.operator},${ast.plane},${ast.target}`;
},
emitBatch(asts: CTXStatement[]): string {
return 'op,plane,target\n' +
asts.map(a => `${a.operator},${a.plane},${a.target}`).join('\n');
}
};