# How to Integrate OpenClaude into CI/CD Pipelines Using Its gRPC Service

> Integrate OpenClaude into CI/CD pipelines using its gRPC service. Automate prompt execution, stream results, and manage conversational state for seamless workflows.

- Repository: [Gitlawb/openclaude](https://github.com/Gitlawb/openclaude)
- Tags: how-to-guide
- Published: 2026-09-05

---

**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`](https://github.com/Gitlawb/openclaude/blob/main/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`](https://github.com/Gitlawb/openclaude/blob/main/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 same `session_id`.
- **Tool permission flow** – When the model invokes a tool (e.g., `run_command`), the server emits a `tool_start` event followed by an `action_required` message. The CI client must respond with a permission reply, after which the server returns the `tool_result`.
- **Streaming response protocol** – The server streams `text_chunk` events for incremental output, terminates with a `done` message 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:

```protobuf
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:

```bash

# 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:

```bash

# 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`](https://github.com/Gitlawb/openclaude/blob/main/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:

```typescript
// 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:

```typescript
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:

```typescript
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:

```typescript
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:

```yaml

# .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:

```yaml

# .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.Chat` duplex 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_id` values; the server stores up to 1,000 sessions in memory.
- **Tool execution** requires handling `action_required` messages to approve commands; CI implementations should auto‑respond with `'y'` to prevent blocking.
- **Token metrics** in the `done` message 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`](https://github.com/Gitlawb/openclaude/blob/main/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`](https://github.com/Gitlawb/openclaude/blob/main/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`](https://github.com/Gitlawb/openclaude/blob/main/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`](https://github.com/Gitlawb/openclaude/blob/main/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`](https://github.com/Gitlawb/openclaude/blob/main/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.