Note: This file is specifically designed for AI coding agents. For human-readable project information, see README.md and CONTRIBUTING.md.
This document provides detailed technical context that AI agents need to effectively work with the Coveo CLI codebase. It complements the README with precise, agent-focused guidance about architecture, testing, and development conventions.
- Project Overview
- Architecture
- Technology Stack
- Development Setup
- Testing
- Code Conventions
- Monorepo Management
- Common Patterns
- Troubleshooting
Coveo CLI is a command-line interface for interacting with the Coveo platform. It provides:
- Project scaffolding for Coveo Headless and Atomic implementations
- Organization and resource management
- Source management for Coveo Push API
- Query execution and debugging tools
Target Users: Developers building search experiences with Coveo, DevOps engineers automating deployments.
Repository Type: Monorepo with multiple interconnected packages.
Coveo CLI Monorepo
│
├── CLI Layer
│ ├── cli-commons-dev (Foundation: Dev tools, test helpers)
│ ├── cli-commons (Core: Config, platform client, utilities)
│ ├── core (Application: CLI commands, business logic)
│ └── source (Feature: Source-specific commands)
│
├── UI Layer
│ ├── Scaffolding templates (React, Vue, Angular)
│ └── Component libraries (Atomic, Headless)
│
└── Infrastructure
├── E2E tests (cli-e2e)
└── Build utilities (utils/)
Critical Rule: Packages must respect this dependency order:
cli-commons-dev (no internal deps)
↓
cli-commons (depends on commons-dev)
↓
core (depends on commons, commons-dev)
Never create circular dependencies or reverse dependencies.
- cli-commons-dev: Shared development tooling (ESLint configs, test utilities, build helpers)
- cli-commons: Shared production code (config management, platform API client, error classes, utilities)
- core: Main CLI application (commands, CLI-specific logic, user interactions)
- source: Commands for managing Coveo Push API sources
- ui/*: Project templates and scaffolding for UI frameworks
| Technology | Purpose | Version |
|---|---|---|
| TypeScript | Primary language | 4.9.5 |
| Node.js | Runtime | ≥18 |
| npm | Package manager | ≥8.5.4 |
| oclif | CLI framework | 3.x |
| Jest | Testing framework | Latest |
| nx | Monorepo orchestration | Latest |
- @oclif/core: CLI framework providing command structure, flags, plugins
- @coveo/platform-client: Official Coveo platform API client
- ts-dedent: Multi-line string formatting for descriptions
- yargs: Command-line parsing (in some utilities)
- ESLint: Code linting with custom configurations
- Prettier: Code formatting
- Husky: Git hooks for pre-commit checks
- lint-staged: Run linters on staged files
- commitlint: Enforce conventional commits
# Clone and install
git clone https://github.com/coveo/cli.git
cd cli
npm install # Installs all workspace dependencies and links local packagesKnown issue: On systems with an externally-managed Python environment (PEP 668, e.g. Homebrew Python on macOS), npm install can fail with error: externally-managed-environment. This comes from packages/cli-e2e's postinstall script, which runs pip install -r mitmproxy/requirements.txt --user for E2E test tooling. If you hit this and don't need to run E2E tests, install with:
npm install --ignore-scriptsDev mode (with hot TypeScript compilation):
./packages/cli/core/bin/dev [command] [flags]
# Examples:
./packages/cli/core/bin/dev --version
./packages/cli/core/bin/dev auth:login
./packages/cli/core/bin/dev ui:create:react myappProduction build:
npm run build
node packages/cli/core/bin/run [command]# Build all packages (respects dependency order)
npm run build
# Run all tests
npm run test
# Lint and format check
npm run lint
# Run specific workspace tests
npm run test --workspace=@coveo/cli
# Clean builds
rm -rf packages/*/lib && npm run build- Make changes in appropriate package (usually
packages/cli/core/src) - Test in dev mode:
./packages/cli/core/bin/dev your:command - Write/update tests: Co-locate
.spec.tsfiles with implementation - Run tests:
npm run test - Build:
npm run build(or just the affected package) - Lint:
npm run lint - Commit: Use conventional commit format
Co-location: Tests live next to implementation files:
src/commands/auth/login.ts
src/commands/auth/login.spec.ts
Naming: Use .spec.ts extension (not .test.ts).
- Jest: Core testing framework
- @oclif/test: CLI-specific testing utilities
Basic structure:
import {test} from '@oclif/test';
describe('my:command', () => {
// Setup
beforeEach(() => {
// Reset mocks
});
// Tests
test
.stdout()
.command(['my:command', '--flag', 'value'])
.it('should do something', (ctx) => {
expect(ctx.stdout).toContain('expected output');
});
});Mocking pattern:
// At file top, before imports
jest.mock('../../lib/oauth/oauth');
jest.mock('@coveo/cli-commons/config/config');
// Import and get typed mocks
import {OAuth} from '../../lib/oauth/oauth';
const mockedOAuth = jest.mocked(OAuth);
// In test
mockedOAuth.mockImplementation(() => ({
/* mock */
}));# All tests
npm run test
# Watch mode
npm run test -- --watch
# Specific package
npm run test --workspace=@coveo/cli
# With coverage
npm run test -- --coverage
# Update snapshots
npm run test -- -u- Mock external dependencies: Config, platform client, OAuth, file system
- Reset mocks: Use
beforeEach(() => jest.clearAllMocks()) - Test behavior, not implementation: Focus on outputs and effects
- Test error cases: Don't just test happy paths
- Use descriptive names: Clear behavior-focused descriptions
- Keep tests fast: No real network calls or file I/O
Order: Node built-ins → External packages → Internal packages → Relative imports
// Node built-ins (with node: prefix)
import {join} from 'node:path';
import {existsSync} from 'node:fs';
// External packages
import {Flags} from '@oclif/core';
import dedent from 'ts-dedent';
// Internal packages
import {CLICommand} from '@coveo/cli-commons/command/cliCommand';
import {Config} from '@coveo/cli-commons/config/config';
// Relative imports
import {OAuth} from '../../lib/oauth/oauth';All CLI commands extend CLICommand:
import {CLICommand} from '@coveo/cli-commons/command/cliCommand';
import {Flags} from '@oclif/core';
import dedent from 'ts-dedent';
export default class MyCommand extends CLICommand {
public static description = dedent`
Clear, concise description.
Can be multi-line using ts-dedent.
`;
public static examples = [
'$ coveo my:command',
'$ coveo my:command --flag value',
];
public static flags = {
myFlag: Flags.string({
char: 'f',
description: 'Flag description',
helpValue: 'exampleValue',
}),
};
public async run() {
const {flags} = await this.parse(MyCommand);
// Implementation
}
}Async/await over promises:
// Good
const result = await someAsyncOperation();
// Avoid
someAsyncOperation().then((result) => {
/* ... */
});Strict typing:
// Good - explicit types
const config: Config = new Config(this.config.configDir);
// Avoid - implicit any
const config = getSomeConfig();Error handling:
import {InternalError} from '@coveo/cli-commons/errors/internalError';
if (!isValid(input)) {
throw new InternalError('Descriptive error message');
}Windows uses PowerShell for spawned processes:
import {appendCmdIfWindows} from '@coveo/cli-commons/utils/os';
spawnSync(appendCmdIfWindows`npm`, ['install'], {
shell: process.platform === 'win32' ? 'powershell' : undefined,
});Path handling:
// Always use node:path module
import {join, resolve} from 'node:path';
const fullPath = join(baseDir, 'subdir', 'file.txt');- Formatting: Handled by Prettier (runs on pre-commit)
- Linting: ESLint with custom rules (check with
npm run lint) - Line length: Prefer ≤80 characters, max 120
- Naming:
- Classes: PascalCase (
MyCommand) - Functions/methods: camelCase (
runCommand()) - Constants: UPPER_SNAKE_CASE (
DEFAULT_TIMEOUT) - Files: kebab-case (
my-command.ts)
- Classes: PascalCase (
Uses npm workspaces for package management:
{
"workspaces": ["packages/*", "packages/ui/*", "packages/cli/*", "utils/*"]
}nx manages build order and caching:
# Build respects dependency graph automatically
npm run build
# Rebuild specific package and dependents
nx run @coveo/cli:build
# Clear cache if needed
nx reset# Add external dependency to specific package
npm install some-package --workspace=@coveo/cli
# Add internal dependency (in package.json)
{
"dependencies": {
"@coveo/cli-commons": "workspace:*"
}
}Packages use project references for incremental builds:
// tsconfig.build.json
{
"extends": "./tsconfig.json",
"references": [{"path": "../commons-dev"}, {"path": "../commons"}]
}This enables:
- Incremental compilation
- Proper build order
- Type checking across packages
import {Config} from '@coveo/cli-commons/config/config';
const config = new Config(this.config.configDir);
// Get configuration
const cfg = config.get();
console.log(cfg.organization);
// Set configuration
config.set({
organization: 'myOrg',
region: 'us',
});import {AuthenticatedClient} from '@coveo/cli-commons/platform/authenticatedClient';
const client = new AuthenticatedClient();
// List organizations
const orgs = await client.getAllOrgsUserHasAccessTo();
// Check access
const hasAccess = await client.getUserHasAccessToOrg('myOrg');// Info logging
this.log('Operation completed successfully');
// Warnings
this.warn('This feature is deprecated');
// Errors (exits with code 1)
this.error('Operation failed: invalid input');
// Formatting utilities
import {formatOrgId} from '@coveo/cli-commons/utils/ux';
this.log(`Organization: ${formatOrgId(orgId)}`);Common flags are exported from lib/flags/:
import {withRegion, withEnvironment} from '../../lib/flags/platformCommonFlags';
export default class MyCommand extends CLICommand {
public static flags = {
...withRegion(),
...withEnvironment(),
customFlag: Flags.string({
description: 'Custom flag',
}),
};
}Trackable decorator for analytics:
import {Trackable} from '@coveo/cli-commons/preconditions/trackable';
@Trackable({eventName: 'command executed'})
public async run() {
// Command implementation
}Stale TypeScript compilation:
rm -rf packages/*/lib
npm run buildnx cache issues:
nx reset
npm run buildBroken workspace links:
rm -rf node_modules package-lock.json
rm -rf packages/*/node_modules
npm installOutdated dependencies:
npm update --workspace=@coveo/cliStale mocks:
- Ensure
jest.clearAllMocks()inbeforeEach - Check mock setup order
Tests passing locally but failing in CI:
- Check for race conditions in async tests
- Verify no reliance on local state or file system
- Ensure mocks are properly isolated
Cannot find module '@coveo/cli-commons/*':
- Build the dependency first:
npm run build --workspace=@coveo/cli-commons - Check
tsconfig.jsonpath mappings
Module resolution issues:
- Clear and rebuild:
rm -rf packages/*/lib && npm run build - Check TypeScript project references in
tsconfig.build.json
Command not found in dev mode:
# Make sure you're running from repo root
./packages/cli/core/bin/dev --helpChanges not reflected:
- Dev mode uses ts-node, should hot-compile
- If issues persist, try full rebuild:
npm run build
| Purpose | Location |
|---|---|
| CLI commands | packages/cli/core/src/commands/ |
| Shared utilities | packages/cli/commons/src/ |
| Test helpers | packages/cli/commons-dev/src/testUtils/ |
| E2E tests | packages/cli-e2e/ |
| Build scripts | scripts/ |
| Configuration | Root package.json, nx.json, tsconfig.base.json |
| Task | Command |
|---|---|
| Run CLI locally | ./packages/cli/core/bin/dev [command] |
| Build all | npm run build |
| Test all | npm run test |
| Lint | npm run lint |
| Format | npm run pre-commit (runs lint-staged) |
| Clean | rm -rf packages/*/lib && npm run build |
- Monorepo: Multiple packages in one repository
- Workspaces: npm's built-in monorepo support
- nx: Build orchestration and caching
- oclif: CLI framework for commands and plugins
- Project References: TypeScript's incremental build system
- Co-location: Tests next to implementation files
- README.md: User-facing documentation and quick start
- CONTRIBUTING.md: Contribution guidelines and project structure
- Instruction files:
.github/instructions/*.instructions.mdfor specific guidance - oclif documentation: https://oclif.io/
- Coveo Platform API: https://docs.coveo.com/en/151/
- Monorepo tools: https://monorepo.tools/
Last Updated: 2026-08-03
Maintained for: AI Coding Agents
Questions: See CONTRIBUTING.md or open an issue