Skip to content

Contributing Guide ​

Thank you for your interest in contributing to Helix Agents! This guide covers development setup, testing, and the contribution process.

Development Setup ​

Prerequisites ​

  • Node.js 22+
  • pnpm (the version is pinned in package.json under packageManager; any pnpm 10+ switches to it automatically)
  • Git
  • Docker (for integration tests)

Clone and Install ​

bash
git clone https://github.com/your-org/helix-agents.git
cd helix-agents
pnpm install

Build ​

bash
# Build all packages
pnpm run build

# Watch mode for development
pnpm run dev

Project Structure ​

helix-agents/
├── packages/
│   ├── core/                 # Core types and logic
│   ├── sdk/                  # Umbrella package
│   ├── runtime-js/           # JavaScript runtime
│   ├── runtime-temporal/     # Temporal runtime
│   ├── runtime-cloudflare/   # Cloudflare runtime
│   ├── store-memory/         # In-memory stores
│   ├── store-redis/          # Redis stores
│   ├── store-cloudflare/     # Cloudflare stores
│   ├── llm-vercel/           # Vercel AI SDK adapter
│   ├── ai-sdk/               # Frontend integration
│   ├── agent-server/         # HTTP server for remote agents
│   ├── tracing-langfuse/     # Langfuse tracing integration
│   └── e2e/                  # End-to-end tests
├── examples/
│   ├── research-assistant/
│   ├── research-assistant-temporal/
│   └── research-assistant-cloudflare/
├── docs/                     # Documentation (VitePress)
└── turbo.json               # Turborepo configuration

Commands ​

Building ​

bash
pnpm run build        # Build all packages
pnpm --filter @helix-agents/core run build   # Build one package
pnpm run dev          # Watch mode

Testing ​

bash
pnpm run test                 # Unit tests
pnpm --filter @helix-agents/core exec vitest   # Watch mode (one package)
pnpm run test:integration     # Integration tests (requires services)
pnpm run test:e2e             # End-to-end tests

Code Quality ​

bash
pnpm run typecheck    # TypeScript type checking
pnpm run lint         # ESLint
pnpm --filter @helix-agents/core exec eslint src/ --fix   # Auto-fix lint issues (one package)
pnpm run format       # Prettier formatting

Documentation ​

bash
pnpm run docs:dev     # Start dev server
pnpm run docs:build   # Production build
pnpm run docs:preview # Preview build

Testing ​

Unit Tests ​

Located in src/__tests__/*.test.ts:

typescript
// packages/core/src/__tests__/step-processor.test.ts
import { describe, it, expect } from 'vitest';
import { planStepProcessing } from '../orchestration/step-processor.js';

describe('planStepProcessing', () => {
  it('handles text response', () => {
    const plan = planStepProcessing({
      type: 'text',
      content: 'Hello',
      shouldStop: false,
    });

    expect(plan.isTerminal).toBe(false);
    expect(plan.assistantMessagePlan?.content).toBe('Hello');
  });
});

Run unit tests:

bash
pnpm run test
pnpm --filter @helix-agents/core run test --coverage

Integration Tests ​

Located in src/__tests__/*.integ.test.ts. Require external services:

bash
# Start services
docker-compose up -d

# Run integration tests
pnpm run test:integration

End-to-End Tests ​

Located in packages/e2e/:

bash
pnpm run test:e2e

Adding a New Package ​

1. Create Directory ​

bash
mkdir packages/my-package
cd packages/my-package

2. Initialize Package ​

json
// packages/my-package/package.json
{
  "name": "@helix-agents/my-package",
  "version": "0.0.1",
  "type": "module",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
    }
  },
  "files": ["dist"],
  "scripts": {
    "build": "tsup",
    "dev": "tsup --watch",
    "test": "vitest run",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "@helix-agents/core": "workspace:*"
  },
  "devDependencies": {
    "tsup": "^8.0.0",
    "typescript": "^5.3.0",
    "vitest": "^1.0.0"
  },
  "publishConfig": {
    "access": "public"
  }
}

3. Add TypeScript Config ​

json
// packages/my-package/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"]
}

4. Add Build Config ​

typescript
// packages/my-package/tsup.config.ts
import { defineConfig } from 'tsup';

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['esm'],
  dts: true,
  clean: true,
  sourcemap: true,
});

5. Create Source Files ​

typescript
// packages/my-package/src/index.ts
export function myFunction() {
  return 'hello';
}

6. Update Turborepo ​

Add to turbo.json if special build requirements.

Code Style ​

TypeScript ​

  • Strict mode enabled
  • Explicit return types on public APIs
  • Use readonly for immutable properties
  • Prefer interface over type for objects
typescript
// Good
interface MyConfig {
  readonly name: string;
  count: number;
}

export function processConfig(config: MyConfig): ProcessResult {
  // ...
}

// Avoid
type MyConfig = {
  name: string;
  count: number;
};

export const processConfig = (config) => {
  // ...
};

Imports ​

  • Use explicit .js extensions for local imports
  • Group imports: external, then internal, then relative
typescript
// External
import { z } from 'zod';
import type { Draft } from 'immer';

// Internal workspace
import { defineAgent } from '@helix-agents/core';

// Relative
import { helper } from './utils.js';
import type { MyType } from './types.js';

Exports ​

  • Export types separately with export type
  • Use barrel exports in index.ts
typescript
// types.ts
export interface MyInterface { ... }
export type MyType = { ... };

// index.ts
export type { MyInterface, MyType } from './types.js';
export { myFunction } from './functions.js';

Comments ​

  • JSDoc for public APIs
  • Inline comments for complex logic
  • No comments for self-explanatory code
typescript
/**
 * Process an agent step and determine next actions.
 *
 * @param stepResult - The result from the LLM adapter
 * @param options - Processing options
 * @returns A plan describing what operations to perform
 */
export function planStepProcessing<TOutput>(
  stepResult: StepResult,
  options?: PlanStepProcessingOptions<TOutput>
): StepProcessingPlan<TOutput> {
  // Check for __finish__ tool call (signals completion)
  const finishCall = findFinishToolCall(stepResult);
  // ...
}

Pull Request Process ​

1. Create a Branch ​

bash
git checkout -b feature/my-feature
# or
git checkout -b fix/bug-description

2. Make Changes ​

  • Write code
  • Add tests
  • Update documentation if needed

3. Run Checks ​

bash
pnpm run typecheck
pnpm run lint
pnpm run test
pnpm run build

4. Add Changeset ​

For changes that affect published packages:

bash
pnpm changeset

Select affected packages and describe changes.

5. Commit ​

bash
git add .
git commit -m "feat: add new feature"

Commit message format:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation
  • refactor: Code refactoring
  • test: Test changes
  • chore: Build/tooling changes

6. Push and Create PR ​

bash
git push -u origin feature/my-feature

Create PR with:

  • Clear description
  • Link to related issues
  • Test instructions if applicable

Changesets ​

We use Changesets for versioning.

Adding a Changeset ​

bash
pnpm changeset
  1. Select affected packages
  2. Choose bump type (patch/minor/major)
  3. Write description

Changeset File ​

Creates .changeset/random-name.md:

markdown
---
'@helix-agents/core': minor
'@helix-agents/runtime-js': patch
---

Add new orchestration function for step processing

Release Process ​

Maintainers handle releases:

bash
# Consume changesets and update versions
pnpm changeset version

# Review changes
git diff

# Commit and create release PR
git add .
git commit -m "chore: version packages"
git push

# After merge, build and publish (pnpm publish rewrites workspace:^ deps to real versions)
pnpm run release

Getting Help ​

  • Open an issue for bugs or feature requests
  • Discussions for questions
  • Check existing issues before creating new ones

Code of Conduct ​

  • Be respectful and inclusive
  • Focus on constructive feedback
  • Help others learn and grow

License ​

Contributions are licensed under the project's license (see LICENSE file).

See Also ​

Released under the MIT License.