# How Career-Ops Integrates with Claude Code, OpenCode, and Codex: An AI-Agnostic Architecture

> Discover how CareerOps achieves AI-agnostic integration with Claude Code, OpenCode, and Codex. Learn about its centralized registry and Markdown prompt execution for seamless CLI management. Explore the santifer/career-ops repo...

- Repository: [Santiago Fernández de Valderrama/career-ops](https://github.com/santifer/career-ops)
- Tags: architecture
- Published: 2026-07-03

---

**Career-Ops integrates with AI coding CLIs through a centralized registry in [`web/src/lib/clis.ts`](https://github.com/santifer/career-ops/blob/main/web/src/lib/clis.ts) that maps each tool to its specific invocation syntax, while keeping all business logic in Markdown prompt files under `modes/` that any CLI can execute.**

The `santifer/career-ops` repository implements an AI-agnostic architecture that decouples job-search automation logic from specific LLM providers. As documented in [`ARCHITECTURE.md`](https://github.com/santifer/career-ops/blob/main/ARCHITECTURE.md), the system stores core logic in plain Markdown files and uses a lightweight CLI registry to translate commands for Claude Code, OpenCode, Codex, and other supported agents.

## The CLI Registry: Mapping Commands to Binaries

At the heart of Career-Ops' multi-CLI support lies a lightweight registry that translates generic user intents into tool-specific command lines. This registry lives in [`web/src/lib/clis.ts`](https://github.com/santifer/career-ops/blob/main/web/src/lib/clis.ts) and defines the exact binary names, flags, and argument patterns required for each AI coding assistant.

### How the Registry Works

The `CLIS` array exported from [`web/src/lib/clis.ts`](https://github.com/santifer/career-ops/blob/main/web/src/lib/clis.ts) contains configuration objects for each supported tool. Each entry specifies the binary name, the base command, and a function that formats the prompt into CLI-specific arguments:

```typescript
// web/src/lib/clis.ts
export const CLIS = [
  { id: "claude",   name: "Claude Code",  bin: "claude",   run: "claude -p",   url: "https://claude.ai/code",               args: p => ["-p", p] },
  { id: "opencode", name: "OpenCode",    bin: "opencode", run: "opencode run", url: "https://opencode.ai",                 args: p => ["run", p] },
  { id: "codex",    name: "Codex",       bin: "codex",    run: "codex exec",   url: "https://github.com/openai/codex-cli", args: p => [p] },
];

```

When the Career-Ops web interface detects a CLI binary on your system, it consults this registry to suggest the correct invocation pattern. For example, **Claude Code** requires the `-p` flag to pass prompts, while **OpenCode** uses the `run` subcommand, and **Codex** expects the `exec` subcommand followed immediately by the prompt text.

## Shared Prompt Architecture

Career-Ops achieves AI-agnosticism by keeping all business logic in plain Markdown files rather than embedding tool-specific code. This means any AI coding CLI can execute the same job-search workflows.

### The `modes/` Directory

All user-visible behavior—such as evaluating job descriptions, generating PDFs, or scanning portals—is defined in the `modes/` directory. These files contain standard Markdown templates that serve as prompts for the LLM. Because the content is plain text, any CLI can read and execute these instructions without modification.

### Universal Agent Instructions ([`AGENTS.md`](https://github.com/santifer/career-ops/blob/main/AGENTS.md))

To ensure consistent behavior across different tools, Career-Ops maintains a shared instruction set in [`AGENTS.md`](https://github.com/santifer/career-ops/blob/main/AGENTS.md). This file defines slash commands, skill definitions, and safety rules that remain identical regardless of which CLI you use.

For **OpenCode** specifically, the repository includes an [`OPENCODE.md`](https://github.com/santifer/career-ops/blob/main/OPENCODE.md) wrapper that imports [`AGENTS.md`](https://github.com/santifer/career-ops/blob/main/AGENTS.md), ensuring OpenCode understands the same configuration as Claude Code:

```markdown
<!-- OPENCODE.md (first line) -->
<!-- OpenCode config — imports AGENTS.md, same as CLAUDE.md -->

```

This wrapper is referenced in [`DATA_CONTRACT.md`](https://github.com/santifer/career-ops/blob/main/DATA_CONTRACT.md), establishing a contractual guarantee that OpenCode will treat the repository exactly like Claude Code.

## Running Career-Ops Across Different CLIs

You can invoke Career-Ops modes using the native syntax of whichever AI coding CLI you have installed. The underlying prompt remains identical; only the wrapper command changes:

**Claude Code**

```bash
claude -p "career-ops evaluate https://example.com/job"

```

**OpenCode**

```bash
opencode run "career-ops evaluate https://example.com/job"

```

**Codex**

```bash
codex exec "career-ops evaluate https://example.com/job"

```

Each command feeds the same `evaluate` mode prompt to the respective LLM backend. The CLI registry selects the appropriate entry and appends your arguments using the pattern defined in the `args` function.

## The One-Command Installer

When you first clone the repository, the scaffolder script in `scaffolder/bin/cli.mjs` prints a reference table of supported agents and their exact command lines. This installer helps you verify that your chosen CLI is properly configured and shows the precise invocation syntax for Career-Ops workflows.

## Why This Integration Works

The seamless integration across disparate AI coding tools relies on four architectural principles:

1. **Uniform prompt format** – Every mode is a plain-text Markdown file; the CLI only needs to stream that text to the LLM.
2. **CLI-specific runners** – Each entry in [`clis.ts`](https://github.com/santifer/career-ops/blob/main/clis.ts) knows how to call its binary (`claude -p`, `opencode run`, `codex exec`), abstracting tool-specific syntax away from the business logic.
3. **No hard-coded models** – The LLM endpoint is chosen by the CLI's configuration, allowing you to swap providers (Claude, OpenAI, OpenRouter, Ollama) without touching Career-Ops code.
4. **Shared agent configuration** – [`AGENTS.md`](https://github.com/santifer/career-ops/blob/main/AGENTS.md) provides identical instructions to both Claude Code and OpenCode, guaranteeing that slash-commands and safety rules remain consistent.

## Adding a New CLI to Career-Ops

Extending support to a new AI coding tool requires only a single line entry in the registry. For example, to add a hypothetical "MyAI" binary:

```typescript
// Extend web/src/lib/clis.ts
export const CLIS = [
  // ... existing entries
  { id: "myai", name: "MyAI", bin: "myai", run: "myai prompt", url: "https://myai.example.com", args: p => ["prompt", p] },
];

```

After adding this entry, the Career-Ops UI will automatically suggest "MyAI" when it detects the binary on your PATH, requiring no changes to the core job-search logic.

## Programmatic Invocation

For automation scripts, you can invoke Career-Ops programmatically by mapping CLI IDs to their respective command strings:

```javascript
import { execSync } from "child_process";

function runCareerOps(cliId, prompt) {
  const cliMap = {
    claude: `claude -p "${prompt}"`,
    opencode: `opencode run "${prompt}"`,
    codex: `codex exec "${prompt}"`,
  };
  const cmd = cliMap[cliId];
  if (!cmd) throw new Error("Unsupported CLI");
  return execSync(cmd, { encoding: "utf8" });
}

// Example: ask OpenCode to generate a PDF of the CV
console.log(runCareerOps("opencode", "career-ops pdf"));

```

This Node.js script demonstrates how the abstract CLI registry translates into concrete system commands, enabling you to build tooling that works across multiple AI assistants.

## Summary

- Career-Ops maintains a **CLI registry** in [`web/src/lib/clis.ts`](https://github.com/santifer/career-ops/blob/main/web/src/lib/clis.ts) that maps tool-specific invocation patterns for Claude Code, OpenCode, Codex, and others.
- All job-search logic resides in **Markdown files** under `modes/` and shared instructions in [`AGENTS.md`](https://github.com/santifer/career-ops/blob/main/AGENTS.md), making the system AI-agnostic.
- **OpenCode** support is implemented via [`OPENCODE.md`](https://github.com/santifer/career-ops/blob/main/OPENCODE.md), which imports the same [`AGENTS.md`](https://github.com/santifer/career-ops/blob/main/AGENTS.md) used by Claude Code.
- Adding new CLI support requires only a **single-line entry** in the registry, with no changes to core business logic.
- The architecture delegates LLM provider selection to the CLI configuration, allowing seamless swaps between Anthropic, OpenAI, and local models.

## Frequently Asked Questions

### Does Career-Ops require a specific AI model or API key?

No. Career-Ops is **AI-agnostic** by design. The repository stores logic in Markdown files and delegates LLM execution to whichever AI coding CLI you have installed. Your API keys and model selection are configured in the CLI tool itself (Claude Code, OpenCode, etc.), not in Career-Ops.

### How do I switch between Claude Code and OpenCode for the same task?

Simply use the command syntax specific to your installed CLI. For example, to evaluate a job description URL, use `claude -p "career-ops evaluate [URL]"` for Claude Code or `opencode run "career-ops evaluate [URL]"` for OpenCode. Both commands execute the same prompt file from the `modes/` directory.

### Where are the prompt templates and business logic stored?

All executable workflows and prompt templates are stored in the **`modes/`** directory as plain Markdown files. Shared agent instructions that define slash commands and safety rules live in **[`AGENTS.md`](https://github.com/santifer/career-ops/blob/main/AGENTS.md)** at the repository root, which is imported by both Claude Code and OpenCode configurations.

### Can I use Career-Ops with a local LLM like Ollama or via OpenRouter?

Yes. Because Career-Ops delegates LLM execution to the underlying CLI, you can use any model supported by your chosen AI coding tool. If your CLI (such as Codex or a custom OpenCode configuration) points to Ollama, OpenRouter, or another provider, Career-Ops will work with those endpoints without configuration changes.