Contributing ​
We welcome contributions to the @agentsy monorepo! This guide explains how to contribute.
Getting Started ​
- Fork the repository on GitHub
- Clone your fork locally
- Follow the Developer Guide for setup
Development Process ​
Creating a feature branch ​
git checkout -b feat/your-feature-nameBranch naming conventions:
feat/- New featuresfix/- Bug fixesdocs/- Documentationtest/- Test additionsrefactor/- Code refactoring
Making changes ​
- Create focused, atomic commits
- Write clear commit messages
- Add tests alongside code changes
- Update documentation if needed
Code style ​
Our code style is enforced by tools:
# Check formatting and linting
pnpm check-types && pnpm lint && pnpm format
# Auto-fix issues
pnpm lint:fix && pnpm formatTools used:
- Linting/Formatting: Biome (via ultracite preset)
- Type checking: TypeScript
Testing ​
All changes must include tests:
# Run unit tests
pnpm test
# Run with coverage
pnpm test:coverage
# Run CLI E2E terminal tests (if CLI package changed)
pnpm --filter @agentsy/cli test:e2eTest structure:
- Colocate unit tests with source files (
.test.ts) - Test streaming behavior with partial chunks
- Verify safety rails (limits, scrubbing)
- Test error cases and edge cases
CLI E2E tests ​
The @agentsy/cli package uses @microsoft/tui-test for real-PTY E2E tests. These tests run the CLI as a real subprocess, validating terminal output and interactive behavior.
When adding a new CLI command, you must also add a tui-test spec:
- Create
packages/cli/src/e2e/<command>.spec.ts - Import
{ test, expect }from@microsoft/tui-test - Write tests using
terminal.submit(),terminal.write(), andexpect().toBeVisible() - Run
pnpm --filter @agentsy/cli test:e2eto verify - Update the spec table in
packages/cli/README.md
Existing E2E specs in packages/cli/src/e2e/:
| Spec | Covers |
|---|---|
compress.spec.ts | compress --text, --file, invalid level, missing input |
compress-memory.spec.ts | compress-memory --file, --no-backup, missing flag |
memory-sync-dev.spec.ts | memory-sync-dev, --json, custom flags, invalid args |
chat.spec.ts | /exit, message send, /help |
cli-basics.spec.ts | Unknown command, default entry |
Submitting Changes ​
Pull Request Process ​
Before opening: Ensure local checks pass
bashpnpm check-types pnpm lint pnpm testCreate PR with:
- Clear title describing the change
- Description of what and why
- Link any related issues
- Screenshots/examples if applicable
Address feedback: Update PR based on review comments
Merge: Maintainers will merge after approval
PR Title Format ​
Follow conventional commits:
feat: add support for custom tag namesfix: resolve JSON parsing with deep nestingdocs: update API reference examplestest: add coverage for streaming edge cases
Types of Contributions ​
Bug Reports ​
File issues with:
- Clear description of the bug
- Steps to reproduce
- Expected vs actual behavior
- Environment details (Node version, OS)
- Minimal code example
Feature Requests ​
Describe:
- Use case and motivation
- Expected behavior
- Potential implementation approach
- Any concerns or trade-offs
Documentation ​
Improvements to:
- README.md
- docs/ guides
- API reference
- Code comments
- Examples
Parser Improvements ​
- Better error messages
- Performance optimizations
- New parser utilities
- Adapter improvements
Testing Guidelines ​
What to test ​
- Normal operation with various inputs
- Edge cases (empty strings, deeply nested structures)
- Error cases (malformed input, limits exceeded)
- Streaming behavior (partial chunks, boundaries)
- Integration between parsers
Example test structure ​
import { describe, it, expect } from 'vitest';
import { parseJson } from '../index';
describe('parseJson', () => {
it('should parse valid JSON', () => {
const result = parseJson('{"key": "value"}');
expect(result.valid).toBe(true);
expect(result.data).toEqual({ key: 'value' });
});
it('should handle malformed JSON', () => {
const result = parseJson('{invalid}');
expect(result.valid).toBe(false);
expect(result.error).toBeDefined();
});
it('should enforce max depth limit', () => {
const deep = '{"a":' + '{"b":'.repeat(10) + '1' + '}'.repeat(11);
const result = parseJson(deep, { maxDepth: 5 });
expect(result.valid).toBe(false);
});
});Commit Messages ​
Write clear, descriptive commits:
Short summary (50 chars max)
Longer explanation of the change if needed.
Explain the why, not just the what.
Fixes #123
Related to #456Questions? ​
- Check the Developer Guide
- Review existing issues and PRs
- Open a discussion on GitHub
- Ask in the PR review
Thank you for contributing!