Contributions are welcome! The plugin system makes it straightforward to add support for new agents, runtimes, trackers, and notification channels.
Getting Started
Prerequisites
- Node.js 20+
- pnpm 9.15+
- Git 2.30+
First-Time Setup
Clone the repository
git clone https://github.com/ComposioHQ/agent-orchestrator.git
cd agent-orchestrator
Build all packages
Building is required before running the dev server.
Copy example config
cp agent-orchestrator.yaml.example agent-orchestrator.yaml
Configure your settings
$EDITOR agent-orchestrator.yaml
Running the Dev Server
The web dashboard depends on built packages. Always build before running the dev server.
# Build all packages
pnpm build
# Start dev server
cd packages/web
pnpm dev
# Open http://localhost:3000 (or your configured port)
Project Structure
agent-orchestrator/
├── packages/
│ ├── core/ # Core types, services, config
│ ├── cli/ # CLI tool (ao command)
│ ├── web/ # Next.js dashboard
│ ├── plugins/ # All plugins
│ │ ├── runtime-*/ # Runtime plugins (tmux, docker, k8s)
│ │ ├── agent-*/ # Agent adapters (claude-code, codex, aider)
│ │ ├── workspace-*/ # Workspace providers (worktree, clone)
│ │ ├── tracker-*/ # Issue trackers (github, linear)
│ │ ├── scm-github/ # SCM adapter
│ │ ├── notifier-*/ # Notification channels
│ │ └── terminal-*/ # Terminal UIs
│ └── integration-tests/ # Integration tests
├── agent-orchestrator.yaml.example
├── .gitleaks.toml # Secret scanning config
├── .husky/ # Git hooks
└── docs/ # Documentation
Development Workflow
Making Changes
Create a feature branch
git checkout -b feat/your-feature
Make your changes
- Follow CLAUDE.md conventions
- Add tests for new features
- Update documentation
Build and test
pnpm build
pnpm test
pnpm lint
pnpm typecheck
Commit
git add .
git commit -m "feat: add your feature"
Push and open PR
git push origin feat/your-feature
Code Conventions
TypeScript
- ESM modules -
.js extensions in imports
node: prefix for builtins (node:fs, node:path)
- Strict mode enabled
type imports for type-only imports
- No
any - use unknown + type guards
- Semicolons, double quotes, 2-space indent - enforced by Prettier
// Good
import type { Runtime } from "@composio/ao-core";
import { readFileSync } from "node:fs";
import { foo } from "./bar.js";
// Bad
import { Runtime } from "@composio/ao-core"; // Should be type import
import { readFileSync } from "fs"; // Missing node: prefix
import { foo } from "./bar"; // Missing .js extension
Shell Commands
Security critical: Always follow these rules to prevent shell injection vulnerabilities.
- Always use
execFile (or spawn) - NEVER exec
- Always add timeouts -
{ timeout: 30_000 }
- Never interpolate user input - pass as array args
- Do NOT use
JSON.stringify for shell escaping
// GOOD
import { execFile } from "node:child_process";
import { promisify } from "node:util";
const execFileAsync = promisify(execFile);
const { stdout } = await execFileAsync("git", ["branch", "--show-current"], {
timeout: 30_000
});
// BAD - shell injection risk
exec(`git checkout ${branchName}`); // branchName could contain ; rm -rf /
Plugin Development
Every plugin implements one of the core interfaces defined in packages/core/src/types.ts.
Plugin Pattern
import type { PluginModule, Runtime } from "@composio/ao-core";
export const manifest = {
name: "my-plugin",
slot: "runtime" as const,
description: "My plugin",
version: "0.1.0",
};
export function create(): Runtime {
return {
name: "my-plugin",
async create(config) {
/* ... */
},
// ... implement interface
};
}
export default { manifest, create } satisfies PluginModule<Runtime>;
Adding a New Plugin
Create plugin package
mkdir -p packages/plugins/runtime-myplugin
cd packages/plugins/runtime-myplugin
Set up package.json
{
"name": "@composio/ao-runtime-myplugin",
"version": "0.1.0",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"test": "vitest"
},
"dependencies": {
"@composio/ao-core": "workspace:*"
}
}
Create src/index.ts
Implement the appropriate interface (Runtime, Agent, Workspace, Tracker, etc.).
Register in core
Add to packages/core/src/services/plugin-registry.ts.
Add tests
Create src/index.test.ts with test cases.
Build and test
pnpm --filter @composio/ao-runtime-myplugin build
pnpm --filter @composio/ao-runtime-myplugin test
Plugin Slots
Eight slots available for plugins:
| Slot | Interface | Default | Examples |
|---|
| Runtime | Runtime | tmux | docker, k8s, process |
| Agent | Agent | claude-code | codex, aider, opencode |
| Workspace | Workspace | worktree | clone |
| Tracker | Tracker | github | linear |
| SCM | SCM | github | — |
| Notifier | Notifier | desktop | slack, composio, webhook |
| Terminal | Terminal | iterm2 | web |
| Lifecycle | (core) | core | — |
All interfaces are defined in packages/core/src/types.ts - read this file first!
Testing
# Run all tests
pnpm test
# Run tests for specific package
pnpm --filter @composio/ao-core test
# Run tests in watch mode
pnpm --filter @composio/ao-core test -- --watch
# Run integration tests
pnpm test:integration
Test Coverage
The project has 3,288 test cases ensuring reliability and correctness.
Security
Secret Scanning
A pre-commit hook automatically scans for secrets:
🔒 Scanning staged files for secrets...
✅ No secrets detected
If secrets are detected:
- Remove the secret from the file
- Use environment variables:
${SECRET_NAME}
- Add to
.env.local (in .gitignore)
- Update example configs with placeholders
What Triggers the Scanner
- API keys:
lin_api_*, ghp_*, gho_*, sk-*, AKIA*
- Tokens:
xoxb-*, xoxa-*, etc.
- Webhooks:
https://hooks.slack.com/*, https://discord.com/api/webhooks/*
- Private keys:
-----BEGIN PRIVATE KEY-----
- Database URLs:
postgres://user:pass@host
- Generic patterns:
api_key=..., token=..., password=...
False Positives
If you get a false positive:
Verify it's not a real secret
Double-check the detected pattern is actually safe.
Update allowlist
Edit .gitleaks.toml:[allowlist]
regexes = [
'''your-pattern-here''',
]
Commit the change
git add .gitleaks.toml
git commit -m "chore: update gitleaks allowlist"
Working with Worktrees
If using git worktrees for parallel development:
# Create worktree
git worktree add ../ao-feature-x feat/feature-x
cd ../ao-feature-x
# Install and build
pnpm install
pnpm build
# Copy config
cp ../agent-orchestrator/agent-orchestrator.yaml .
# Start dev server
cd packages/web
pnpm dev
Debugging
Enable Verbose Logging
Attach to tmux Session
tmux attach -t session-name
# Detach: Ctrl-b d
cat ~/.agent-orchestrator/my-app-3
Check Session Status
curl http://localhost:3000/api/sessions/my-app-3
Submission Guidelines
Pull Request Process
Ensure all tests pass
pnpm build && pnpm test && pnpm lint && pnpm typecheck
Write a clear description
- What does this PR do?
- Why is it needed?
- How does it work?
- Any breaking changes?
Link related issues
Use Fixes #123 or Closes #123 in the PR description.
Request review
Tag relevant maintainers or wait for automatic review assignment.
Use Conventional Commits:
feat: add support for Docker runtime
fix: resolve memory leak in session cleanup
chore: update dependencies
docs: improve plugin development guide
test: add integration tests for Linear tracker
Code Review
Expect feedback on:
- Code quality and style
- Test coverage
- Documentation updates
- Security considerations
- Performance implications
Resources
Getting Help
Need help contributing?
- Check existing issues and discussions
- Review the troubleshooting guide
- Ask questions in GitHub Discussions
- Join the community channels
Thank you for contributing to Agent Orchestrator!