How to Integrate OpenClaude into CI/CD Pipelines Using Its gRPC Service
OpenClaude exposes a full‑featured duplex streaming gRPC API through the AgentService.Chat RPC, enabling automated CI/CD systems to execute prompts, stream incremental results, handle tool permissions, and maintain conversational state across pipeline stages.
The open‑source Gitlawb/openclaude repository provides a language‑agnostic gRPC interface that allows any continuous integration system to leverage AI‑driven automation. By integrating the gRPC service into your CI/CD workflows, you can trigger the model to run linting, execute tests, or perform deployments while retaining context across multiple job stages.
Understanding the OpenClaude gRPC Architecture
The gRPC implementation centers on a duplex streaming model defined in src/proto/openclaude.proto and implemented in src/grpc/server.ts. This architecture enables real‑time bidirectional communication between your CI runner and the AI agent.
Core Server Components
The GrpcServer class in src/grpc/server.ts instantiates a native grpc.Server, registers the AgentService.Chat method, and manages the streaming lifecycle. When a CI client connects, the server initializes a QueryEngine instance through the handleChat function to process the request.
Key architectural elements include:
- Session persistence – An in‑memory
Map<string, Message[]>stored in the server maintains conversation history for up to 1,000 concurrent sessions, allowing CI pipelines to resume context across discrete steps by reusing the samesession_id. - Tool permission flow – When the model invokes a tool (e.g.,
run_command), the server emits atool_startevent followed by anaction_requiredmessage. The CI client must respond with a permission reply, after which the server returns thetool_result. - Streaming response protocol – The server streams
text_chunkevents for incremental output, terminates with adonemessage containing the full response text and token usage metrics (prompt_tokens,completion_tokens).
The Protocol Buffer Service Definition
The service contract lives in src/proto/openclaude.proto and is loaded at runtime using @grpc/proto-loader. The AgentService exposes a single bidirectional streaming RPC:
service AgentService {
rpc Chat(stream ChatRequest) returns (stream ChatResponse);
}
This design permits the CI client to send configuration updates or permission responses while simultaneously receiving streamed output from the model.
Setting Up the gRPC Server in CI/CD Environments
Before any client can interact with OpenClaude, the gRPC server must be running as a background process within your CI environment. The server binds to port 50051 by default.
Start the server from your CI configuration:
# Start the gRPC server in the background
node -r ./src/grpc/server.ts &
echo $! > server.pid
# Or using the built distribution
node dist/grpc/server.js &
Verify the server is ready by checking for the startup log:
# Wait for server initialization
until grep -q "gRPC Server running at localhost:50051" server.log; do
sleep 1
done
Building a CI/CD Client for OpenClaude
Any CI system capable of running a gRPC client (Node.js, Python, Go, etc.) can interact with OpenClaude. The reference implementation in scripts/grpc-cli.ts demonstrates the required interaction patterns.
Connecting to the Service
Establish an insecure connection (suitable for localhost CI environments) using the generated service definition:
// ci-client.ts
import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';
import path from 'path';
const PROTO_PATH = path.resolve(import.meta.dirname, '../src/proto/openclaude.proto');
const pkg = protoLoader.loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
});
const { openclaude } = grpc.loadPackageDefinition(pkg) as any;
const client = new openclaude.v1.AgentService(
'localhost:50051',
grpc.credentials.createInsecure()
);
Handling Streamed Responses
Open a duplex streaming call and handle the message types appropriately:
const call = client.Chat();
call.on('data', (msg) => {
if (msg.text_chunk) {
process.stdout.write(msg.text_chunk.text);
}
if (msg.done) {
console.log('\n--- FINAL OUTPUT ---\n', msg.done.full_text);
console.log('Token usage:', {
prompt: msg.done.prompt_tokens,
completion: msg.done.completion_tokens
});
process.exit(0);
}
});
call.on('error', (err) => {
console.error('gRPC stream error:', err.message);
process.exit(1);
});
Send the initial request with a persistent session identifier:
call.write({
request: {
session_id: 'ci-pipeline-123',
message: 'Run `npm run lint` then `npm test` and report the outcome.',
working_directory: process.cwd(),
model: 'claude-3-5-sonnet-20240620'
}
});
Managing Tool Permissions Automatically
In CI environments, you typically auto‑approve safe operations rather than waiting for human input. Handle the action_required message to programmatically approve tool execution:
call.on('data', (msg) => {
if (msg.action_required) {
// Auto‑approve command execution in CI context
call.write({
input: {
prompt_id: msg.action_required.prompt_id,
reply: 'y'
}
});
}
if (msg.tool_start) {
console.log(`Executing tool: ${msg.tool_start.tool_name}`);
}
if (msg.tool_result) {
console.log('Tool output:', msg.tool_result.stdout);
}
});
This pattern ensures that when the QueryEngine invokes run_command or other tools, the pipeline continues without interruption.
Complete CI/CD Integration Examples
GitLab CI Configuration
Integrate OpenClaude into a GitLab pipeline by starting the server as a background service and running the client as a script job:
# .gitlab-ci.yml
stages:
- lint
- test
variables:
OPENCLAUDE_PORT: "50051"
start-openclaude:
stage: .pre
image: node:22
script:
- bun install
- node src/grpc/server.ts > server.log 2>&1 &
- |
until grep -q "gRPC Server running at localhost:$OPENCLAUDE_PORT" server.log; do
sleep 1
done
- echo "Server ready"
artifacts:
paths:
- server.log
- node_modules/
ai-lint:
stage: lint
image: node:22
dependencies:
- start-openclaude
script:
- node ci-client.ts "Run ESLint and fix any auto-fixable issues, then report remaining errors"
ai-test:
stage: test
image: node:22
dependencies:
- start-openclaude
- ai-lint
script:
- node ci-client.ts "Execute the test suite and analyze any failures. Use session_id: ci-pipeline-123"
GitHub Actions Workflow
For GitHub Actions, use a job step to initialize the server and subsequent steps to interact with it:
# .github/workflows/ai-ci.yml
name: AI-Driven CI
on: [push]
jobs:
ai-validation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install dependencies
run: bun install
- name: Start OpenClaude gRPC Server
run: |
node src/grpc/server.ts &
echo "SERVER_PID=$!" >> $GITHUB_ENV
sleep 3
- name: Run AI Linting
run: node ci-client.ts "Run npm run lint and summarize findings"
env:
SESSION_ID: ${{ github.run_id }}
- name: Run AI Tests
run: node ci-client.ts "Run npm test with coverage. Use session_id: ${{ github.run_id }}"
- name: Cleanup Server
if: always()
run: kill $SERVER_PID || true
Summary
- OpenClaude's gRPC service provides a
AgentService.Chatduplex streaming RPC that enables real‑time AI automation within CI/CD pipelines. - Session persistence allows you to maintain context across pipeline stages by reusing
session_idvalues; the server stores up to 1,000 sessions in memory. - Tool execution requires handling
action_requiredmessages to approve commands; CI implementations should auto‑respond with'y'to prevent blocking. - Token metrics in the
donemessage enable cost tracking and usage monitoring for budget-conscious CI environments. - Language independence means you can implement clients in Node.js, Python, Go, or any gRPC‑supported language, as demonstrated by the reference CLI in
scripts/grpc-cli.ts.
Frequently Asked Questions
How do I persist conversation context across multiple CI/CD stages?
Pass a consistent session_id string in each request message sent to the Chat stream. The server implementation in src/grpc/server.ts maintains an in‑memory Map<string, Message[]> that associates your session ID with the conversation history, allowing subsequent pipeline steps to reference previous tool results and AI decisions.
What is the default port for the OpenClaude gRPC server, and can it be customized?
The default port is 50051, as indicated by the server startup log message. You can override this by modifying the server configuration in src/grpc/server.ts before instantiation, or by setting the appropriate environment variable if the implementation supports it (check the server initialization code for process.env references).
How should I handle errors when the AI attempts to execute commands in a CI environment?
Implement the action_required handler in your client to programmatically respond to tool permission prompts. In src/grpc/server.ts, when a tool is invoked, the server emits an action_required message containing a prompt_id. Your CI client must write an input message back to the stream with the matching prompt_id and reply: 'y' to authorize execution, preventing the pipeline from hanging indefinitely.
Can I use the provided CLI script for CI integration, or do I need a custom client?
You can use scripts/grpc-cli.ts for prototyping and simple pipelines, as it handles the duplex streaming, tool permissions, and session management interactively. However, for production CI/CD workflows, a custom client is recommended because it allows you to programmatically handle the done message for exit codes, parse token usage metrics, and implement specific error handling logic tailored to your deployment requirements.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →