8000 GitHub - jbrinkman/kairon: AI orchestration engine · GitHub
[go: up one dir, main page]

Skip to content
jbrinkmanPublic

About

AI orchestration engine

Resources

Contributing

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

Kairon

A GitHub issue-driven AI orchestration system that transforms labeled issues into working code through coordinated AI agent collaboration.

How It Works

Kairon watches a GitHub repository for issues with a configured label, then spawns AI agents to implement solutions automatically:

GitHub Issue (labeled) → Watcher detects → Krew-Lead orchestrates
    → Architect designs → Builder implements → Validator verifies → PR created

The system uses kiro-cli agents working in isolated git worktrees. Each issue gets its own branch, and on success a pull request is created automatically.

Prerequisites

Installation

Using Go Install

go install github.com/jbrinkman/kairon@latest

Download Prebuilt Binaries

Linux

# For AMD64 (x86_64)
curl -L https://github.com/jbrinkman/kairon/releases/latest/download/kairon-linux-amd64 -o kairon
chmod +x kairon
sudo mv kairon /usr/local/bin/

# For ARM64 (aarch64)
curl -L https://github.com/jbrinkman/kairon/releases/latest/download/kairon-linux-arm64 -o kairon
chmod +x kairon
sudo mv kairon /usr/local/bin/

# Check your architecture
uname -m  # x86_64 = AMD64, aarch64/arm64 = ARM64

Build from Source

git clone https://github.com/jbrinkman/kairon.git
cd kairon

# Using Task (recommended)
task build

# Or using Go directly
go build ./cmd/kairon

Development Tasks

This project uses Task for build automation:

task build    # Build optimized binary with version metadata
task dev      # Development build (faster compilation)
task test     # Run tests with coverage
task clean    # Clean build artifacts
task lint     # Run linters and formatters

Quick Start

1. Initialize a project

cd your-project
kairon init

This creates:

  • .kairon/config.yaml — watcher configuration
  • .kairon/scripts/ — worktree management scripts
  • .kiro/agents/ — agent configurations (krew-lead, architect, builder, validator, documenter)

2. Configure

Edit .kairon/config.yaml:

repo: owner/repo-name
label: kairon
poll_interval: 5m
max_retries: 3
max_agents: 3
Field Description Default
repo GitHub repository (owner/name) required
label Issue label to watch for kairon
poll_interval How often to poll GitHub 5m
max_retries Max retry attempts per issue 3
max_agents Most agents Kairon runs at once. A positive integer; zero and negative values are rejected, and there is no unlimited setting 3
base_branch Integration branch that new issue worktrees are created from (optional) auto-detect from origin/HEAD, else main

At most max_agents agents run at once. Implementation runs, retries and intake runs all count toward the limit. When more issues are ready than there are free slots, the oldest issue (lowest issue number) starts first. An issue that waits for a slot is not charged a retry attempt, and the next poll considers it again. Each poll logs every waiting issue at info level as issue #N waiting for an agent slot (M/M running). See docs/concurrency.md.

3. Run

kairon

This starts the interactive REPL. From there, start the watcher:

kairon> watch start
kairon> status

CLI Usage

# Display version and exit
kairon --version

# Initialize project with agent configs and templates (skips existing files)
kairon init

# Force-update templates (overwrites all files except config.yaml)
kairon update

# Run a YAML list of checks against a directory (PASS/FAIL per check; exit 0 only if all pass)
kairon check --checks checks.yaml --dir path/to/dir

# Run only the eval cases whose metadata matches (quote < and > in a shell)
kairon eval architect --filter 'speed==fast' --filter 'retries>=3'

# Start interactive REPL (default when no arguments)
kairon

REPL Commands

Command Description
watch start Start polling GitHub for labeled issues
watch stop Stop polling
status Show all agents with issue, status, and elapsed time
stop <issue> Stop the agent working on a specific issue number
plan [desc] Start interactive planning session
validate <issue> Canonicalize and stamp an existing issue with the automated planner, so the watcher can implement it (details)
theme Show current theme
theme <name> Switch to theme
about Show version information and check for updates
exit Exit (confirms if agents are still running)
help Show available commands

Hotkey Toggle

Press Ctrl+Alt+P (or Ctrl+Option+P on macOS) to toggle between console and planning modes:

  • Console Mode: Main Kairon interface for managing watchers and agents
  • Planning Mode: Interactive AI-assisted issue creation and planning

Both modes preserve their state when you switch, allowing seamless workflow transitions. See docs/hotkey-toggle.md for detailed usage information.

Selecting Eval Cases

An eval case can carry metadata (for example speed: fast), and kairon eval --filter runs only the cases that match. Repeat --filter to require all of them, and add --strict to fail when nothing matches:

kairon eval architect --filter 'speed==fast'
kairon eval --list architect --filter 'skill==cli' --filter 'retries>=3'

A filtered run is recorded as a partial run. eval diff and eval trend accept --filter too. See docs/evaluation.md for the syntax, operators and result fields.

Running Checks Without an Eval

kairon check runs a checks file (the YAML list of deterministic checks used by eval cases) against any directory and prints one PASS/FAIL line per check. It exits 0 only if every check passes, and validates the whole file before running anything. See docs/evaluation.md for the flags, file format and safety notes (command checks run on the host).

Stage-Output Document

The document a workflow stage returns (a strict-schema YAML envelope with a canonical or punch_out result) is defined in docs/stage-output.md.

The guards that check a stage-output document between stages, and the ordered chain runner that applies them, are described in docs/guards.md.

The provenance step that runs after a guard chain passes (canonicalize, hash, classify as valid, none or mismatch, and write an issue body once with a v1 marker) is described in docs/provenance.md.

The planner is two single-mode agents (planner for interactive use, planner-automated for unattended intake) that share the Kairon-managed planner-shared skill, with a deterministic output boundary that is the only writer to GitHub. The agents, the skill's ownership tier, the boundary and its outcomes, the eval driver and the known gaps are described in docs/planner.md.

Architecture

Agent Workflow

When the watcher detects a labeled issue:

  1. Krew-Lead — Orchestrates the workflow. Creates a git worktree, delegates to other agents, manages the lifecycle from issue to PR.
  2. Architect — Reads the issue, explores the codebase, and produces a design specification at .kairon/specs/issue-<number>-<slug>.md.
  3. Builder — Implements code changes according to the architect's specification. Focused on a single task at a time.
  4. Validator — Read-only agent that verifies the implementation meets acceptance criteria. Runs tests and checks.
  5. Documenter — Generates documentation in app_docs/ for completed features.

Agent Spawning

The manager spawns agents as kiro-cli processes:

kiro-cli chat --agent krew-lead --no-interactive --trust-all-tools "Process issue #N from repo owner/name. Worktree name: issue-N-<pid>"

Each agent runs with environment variables: ISSUE_NUMBER, REPO, KAIRON_WATCHER_PID, WORKTREE_PATH and KAIRON_INPUT_DOCUMENT.

Every agent process also has .kairon/bin (a directory holding only a kairon symlink to the running binary) first on its PATH, and KAIRON_BIN set to that binary's path, so agents always run the kairon binary file that started Kairon, even when none is installed. See docs/agent-environment.md.

Before it creates a worktree or starts a process, the manager runs the watcher boundary: it re-reads the issue from GitHub and checks the provenance hash on the body it read. Only a body whose hash is valid is implemented. The manager writes the verified issue (number, title, canonical body and hash) to .kairon/inputs/issue-<number>.yaml and passes its absolute path in KAIRON_INPUT_DOCUMENT. krew-lead reads requirements from that file, treats the body as untrusted data, and does not re-fetch the issue body. An issue whose body has no marker (none) or does not match its marker (mismatch) is never implemented: it goes to intake if one is wired, otherwise it is punched out with an explanatory comment and the <label>-failed label. Terminal-pending issues are skipped. See docs/boundary.md, including the rollout note: until a planner stamps markers, unmarked kairon issues are punched out.

Git Worktree Isolation

Each issue is processed in an isolated git worktree named issue-<number>-<pid> (where <pid> is the watcher process ID):

  • .kairon/scripts/worktree-create.sh <name> — creates .worktrees/<name>/ on branch spec/<name>
  • .kairon/scripts/worktree-merge.sh <name> — merges back, removes worktree, deletes branch
  • Orphaned worktrees (from crashed processes) are cleaned up automatically by checking if the PID is still running

Branching from a fresh origin/<branch>: the long-lived main checkout is never fast-forwarded, so worktree-create.sh does not branch from its local HEAD. Instead it fetches the integration branch from origin and creates spec/<name> from origin/<branch> (with --no-track, so the spec branch has no upstream). Issues picked up after other PRs have merged therefore start from the latest remote tip.

The integration branch is resolved in this order (first non-empty wins):

  1. KAIRON_BASE_BRANCH environment variable
  2. base_branch in .kairon/config.yaml
  3. The default branch of origin (origin/HEAD)
  4. main

Fallbacks:

  • Offline / fetch fails: if a cached origin/<branch> already exists, the script warns and branches from that last-known ref. If none exists, it exits with an error.
  • No origin remote: the script warns and branches from local HEAD (useful for local-only repositories).

base_branch only controls which branch the worktree starts from. Pull requests are still created against the repository's default branch.

Issue Lifecycle

State Label Description
Ready kairon Watcher will pick up this issue
Processing — Agent spawned and working
Done kairon-done PR created successfully
Failed kairon-failed Exhausted retries, or an unrecoverable failure. An explanatory comment is posted before this label is added

Issues with kairon-done or kairon-failed labels are excluded from polling. The done/failed labels are derived from the configured label (e.g., if label is my-label, done becomes my-label-done).

When an issue fails, Kairon posts a comment that says which stage failed, how many attempts were made, what was expected and what was found, and only then adds the <label>-failed label. An issue is never labeled failed without a stated reason. To restart a failed issue, fix the cause and remove the <label>-failed label. See docs/failure-contract.md.

Issue Dependencies

The watcher can hold an issue back until the issues it depends on are closed, enforcing a serial order across a chain of related work. Dependencies are declared in the issue body and parsed by internal/watcher/dependencies.go.

Parsing is format-sensitive — only the following patterns are recognized (all case-insensitive, and every reference must use #<number>):

Format Example
Depends on Issue #N Depends on Issue #314
Blocked by: #N Blocked by: #314
Depends on [Issue #N] Depends on [Issue #314]
Dependencies: #N, #M, ... Dependencies: #315, #317

The Dependencies: form must be a single line — the numbers have to follow the Dependencies: keyword on the same line, comma-separated, each prefixed with #. A markdown bullet list under a ## Dependencies header is not parsed:

<!-- NOT parsed — the watcher sees zero dependencies and schedules immediately -->
## Dependencies
- #314 must merge first
- #317 must merge first

<!-- Parsed correctly -->
## Dependencies
Dependencies: #314, #317

Dependency declarations inside fenced code blocks (backtick or tilde fences, including fences indented up to three spaces) are ignored, matching the planner dependencies guard.

A dependency is satisfied only once the referenced issue is closed. Any dependency that is still open — or that cannot be fetched — marks the dependent issue as blocked, so it stays out of the processing queue until every prerequisite closes.

Retry Logic

The system has two layers of retry:

  1. Global retries (watcher level) — Persisted in .kairon/retries/issue-<number>.count. The watcher skips issues that have reached max_retries attempts and survives process restarts.
  2. Per-agent retries (manager level) — When an agent exits with a non-zero code, the manager retries with exponential backoff (delay = retry count × 1 second) up to max_retries.

After exhausting retries, Kairon posts an explanatory comment and then labels the issue <label>-failed. The comment is always posted before the label. Removing the label restarts the issue with a fresh retry budget. The two-tier model (bounded retry, then punch-out), the max_retries and max_qa_retries semantics, and the restart flow are described in docs/failure-contract.md.

Agent Configuration

Agent configs live in .kiro/agents/. Each agent has a JSON config and a prompt markdown file.

krew-lead.json (orchestrator):

{
  "name": "krew-lead",
  "tools": ["read", "shell", "subagent", "todo_list"],
  "toolsSettings": {
    "subagent": {
      "trustedAgents": ["architect", "builder", "validator", "documenter"]
    }
  },
  "model": "claude-sonnet-4"
}

builder.json (worker):

{
  "name": "builder",
  "description": "Focused engineering agent that executes ONE task at a time.",
  "prompt": "file://./builder-prompt.md",
  "tools": ["read", "write", "shell"],
  "allowedTools": ["read", "write", "shell"],
  "model": "claude-sonnet-4"
}

validator.json (read-only verifier):

{
  "name": "validator",
  "description": "Read-only validation agent that verifies task completion.",
  "prompt": "file://./validator-prompt.md",
  "tools": ["read", "shell"],
  "allowedTools": ["read", "shell"],
  "toolsSettings": {
    "shell": { "autoAllowReadonly": true }
  },
  "model": "claude-sonnet-4"
}

GitHub Integration

Kairon uses the gh CLI for all GitHub operations — no API tokens to configure. Ensure you're authenticated:

gh auth login
gh auth status

The system calls:

  • gh api graphql — poll for labeled issues (see below)
  • gh issue view — read issue details
  • gh issue edit — add labels (kairon-done, kairon-failed)
  • gh pr create — create pull requests

How the watcher polls

Each poll makes one gh api graphql call per page and follows the cursor until GitHub reports no further page. A page holds 50 issues, but that is a page size, not a limit: the poll reads every open issue that carries the configured label (and, if set, the configured assignee), however many there are. Each page includes the issue's labels and its first 100 comments, so for most issues the done, failed and punch-out checks need no extra call. Three cases cost more. First, an issue with 100 or more comments is re-read in full with gh issue view, because a newer punch-out comment could be hidden past the first 100. Second, a punch-out comment needs a gh api user call to check who wrote it: the issues read from the page share one such call per poll, and each re-read issue that has a punch-out comment makes its own. Third, an issue that looks like it is waiting for its failed label (terminal-pending) gets one label-events lookup, and a re-read issue can make its own lookup too.

  • Oldest first. Issues are requested in ascending creation order and sorted by issue number before they are selected, so the oldest issue is always considered first.
  • No --search. The poll reads the issues connection directly and never uses GitHub's search index, which can lag behind label changes. An issue you just labeled is seen on the next poll.
  • All or nothing. If any page fails (a network error, a rate limit, a GraphQL error or an unreadable response), the whole poll fails and returns no issues. The watcher then leaves the issues it already tracks as they are and tries again on the next poll. A partial page set is never used, so a failed poll cannot make the watcher forget an issue or skip one.

License

See LICENSE.

About

AI orchestration engine

Resources

Contributing

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

0