Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ on:
description: 'Run Linear integration tests'
type: boolean
default: true
run_github:
description: 'Run GitHub Projects integration tests'
type: boolean
default: true
run_git:
description: 'Run Git integration tests'
type: boolean
Expand Down Expand Up @@ -86,6 +90,15 @@ jobs:
OPERATOR_LINEAR_TEST_TEAM: ${{ secrets.OPERATOR_LINEAR_TEST_TEAM }}
run: cargo test --test kanban_integration linear_tests -- --nocapture --test-threads=1

- name: Run GitHub Projects integration tests
if: >-
(github.event_name != 'workflow_dispatch' || inputs.run_github) &&
env.OPERATOR_GITHUB_TOKEN != ''
env:
OPERATOR_GITHUB_TOKEN: ${{ secrets.OPERATOR_GITHUB_TOKEN }}
OPERATOR_GITHUB_TEST_PROJECT: ${{ secrets.OPERATOR_GITHUB_TEST_PROJECT }}
run: cargo test --test kanban_integration github_tests -- --nocapture --test-threads=1

- name: Run cross-provider tests
env:
OPERATOR_JIRA_DOMAIN: ${{ secrets.OPERATOR_JIRA_DOMAIN }}
Expand All @@ -94,6 +107,8 @@ jobs:
OPERATOR_JIRA_TEST_PROJECT: ${{ secrets.OPERATOR_JIRA_TEST_PROJECT }}
OPERATOR_LINEAR_API_KEY: ${{ secrets.OPERATOR_LINEAR_API_KEY }}
OPERATOR_LINEAR_TEST_TEAM: ${{ secrets.OPERATOR_LINEAR_TEST_TEAM }}
OPERATOR_GITHUB_TOKEN: ${{ secrets.OPERATOR_GITHUB_TOKEN }}
OPERATOR_GITHUB_TEST_PROJECT: ${{ secrets.OPERATOR_GITHUB_TEST_PROJECT }}
run: cargo test --test kanban_integration test_provider_interface_consistency -- --nocapture

# Git Integration Tests
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/vscode-extension.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ jobs:
DISPLAY: ':99.0'

- name: Upload coverage to Codecov
if: always()
uses: codecov/codecov-action@v5
with:
files: vscode-extension/coverage/lcov.info
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "operator"
version = "0.1.27"
version = "0.1.28"
edition = "2021"
description = "Multi-agent orchestration dashboard for gbqr.us"
authors = ["gbqr.us"]
Expand Down
49 changes: 24 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@
# Operator!
[![GitHub Tag](https://img.shields.io/github/v/tag/untra/operator)](https://github.com/untra/operator/releases) [![codecov](https://codecov.io/gh/untra/operator/branch/main/graph/badge.svg)](https://codecov.io/gh/untra/operator) [![VS Code Marketplace Installs](https://img.shields.io/visual-studio-marketplace/i/untra.operator-terminals?label=VS%20Code%20Installs)](https://marketplace.visualstudio.com/items?itemName=untra.operator-terminals)

**Session** [![tmux](https://img.shields.io/badge/tmux-1BB91F?logo=tmux&logoColor=white)](https://operator.untra.io/getting-started/sessions/tmux/) [![cmux](https://img.shields.io/badge/cmux-333333)](https://operator.untra.io/getting-started/sessions/cmux/) [![Zellij](https://img.shields.io/badge/Zellij-E8590C)](https://operator.untra.io/getting-started/sessions/zellij/) **|** **LLM Tool** [![Claude](https://img.shields.io/badge/Claude-D97757?logo=claude&logoColor=white)](https://operator.untra.io/getting-started/agents/claude/) [![Codex](https://img.shields.io/badge/Codex-000000?logo=openai&logoColor=white)](https://operator.untra.io/getting-started/agents/codex/) [![Gemini CLI](https://img.shields.io/badge/Gemini_CLI-8E75B2?logo=googlegemini&logoColor=white)](https://operator.untra.io/getting-started/agents/gemini-cli/) **|** **Kanban Provider** [![Jira](https://img.shields.io/badge/Jira-0052CC?logo=jira&logoColor=white)](https://operator.untra.io/getting-started/kanban/jira/) [![Linear](https://img.shields.io/badge/Linear-5E6AD2?logo=linear&logoColor=white)](https://operator.untra.io/getting-started/kanban/linear/) **|** **Git Version Control** [![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://operator.untra.io/getting-started/git/github/)
**|** **Session** [![tmux](https://img.shields.io/badge/tmux-1BB91F?logo=tmux&logoColor=white)](https://operator.untra.io/getting-started/sessions/tmux/) [![cmux](https://img.shields.io/badge/cmux-333333)](https://operator.untra.io/getting-started/sessions/cmux/) [![Zellij](https://img.shields.io/badge/Zellij-E8590C)](https://operator.untra.io/getting-started/sessions/zellij/)
**|** **LLM Tool** [![Claude](https://img.shields.io/badge/Claude-D97757?logo=claude&logoColor=white)](https://operator.untra.io/getting-started/agents/claude/) [![Codex](https://img.shields.io/badge/Codex-000000?logo=openai&logoColor=white)](https://operator.untra.io/getting-started/agents/codex/) [![Gemini CLI](https://img.shields.io/badge/Gemini_CLI-8E75B2?logo=googlegemini&logoColor=white)](https://operator.untra.io/getting-started/agents/gemini-cli/)
**|** **Kanban Provider** [![Jira](https://img.shields.io/badge/Jira-0052CC?logo=jira&logoColor=white)](https://operator.untra.io/getting-started/kanban/jira/) [![Linear](https://img.shields.io/badge/Linear-5E6AD2?logo=linear&logoColor=white)](https://operator.untra.io/getting-started/kanban/linear/) [![GitHub Projects](https://img.shields.io/badge/GitHub_Projects-181717?logo=github&logoColor=white)](https://operator.untra.io/getting-started/kanban/github/)
**|** **Git Version Control** [![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://operator.untra.io/getting-started/git/github/)

An orchestration tool for [**AI-assisted**](https://operator.untra.io/getting-started/agents/) [_kanban-shaped_](https://operator.untra.io/getting-started/kanban/) [git-versioned](https://operator.untra.io/getting-started/git/) software development.

<a href="https://marketplace.visualstudio.com/items?itemName=untra.operator-terminals" target="_blank" class="button">Install <b>Operator! Terminals</b> extension from Visual Studio Code Marketplace</a>

**Operator** is for you if:

- you do work assigned from tickets on a kanban board, such as [_Jira Cloud_](https://operator.untra.io/getting-started/kanban/jira/) or [_Linear_](https://operator.untra.io/getting-started/kanban/linear/)
- you do work assigned from tickets on a kanban board, such as [_Jira Cloud_](https://operator.untra.io/getting-started/kanban/jira/), [_Linear_](https://operator.untra.io/getting-started/kanban/linear/), or [_GitHub Projects_](https://operator.untra.io/getting-started/kanban/github/)
- you use LLM assisted coding agent tools to accomplish work, such as [_Claude Code_](https://operator.untra.io/getting-started/agents/claude/), [_OpenAI Codex_](https://operator.untra.io/getting-started/agents/codex/), or [_Gemini CLI_](https://operator.untra.io/getting-started/agents/gemini-cli/)
- your work is version controlled with a git repository provider like [_GitHub_](https://operator.untra.io/getting-started/git/github/) or [_GitLab_](https://operator.untra.io/getting-started/git/gitlab/)

Expand Down Expand Up @@ -151,29 +154,25 @@ Within each priority level, tickets are processed FIFO by timestamp.
## Dashboard Layout

```
┌─────────────────────────────────────────────────────────────┐
│ operator v0.1.0 ▶ RUNNING 5/7 agents │
├─────────────┬─────────────┬─────────────┬───────────────────┤
│ QUEUE (12) │ RUNNING (5) │ AWAITING (1)│ COMPLETED (8) │
├─────────────┼─────────────┼─────────────┼───────────────────┤
│ INV-003 ‼️ │ backend │ SPIKE-015 │ ✓ FEAT-040 12:30 │
│ FIX-089 │ FEAT-042 │ "what auth │ ✓ FIX-088 12:15 │
│ FIX-090 │ ██████░░ │ pattern?" │ ✓ FEAT-041 11:45 │
│ FEAT-043 │ frontend │ │ ✓ FIX-087 11:30 │
│ FEAT-044 │ FIX-091 │ [R]espond │ │
│ FEAT-045 │ ████░░░░ │ │ │
│ │ api │ │ │
│ │ FEAT-046 │ │ │
│ │ ██░░░░░░ │ │ │
│ │ admin │ │ │
│ │ FEAT-047 │ │ │
│ │ █████████ │ │ │
│ │ infra │ │ │
│ │ FIX-092 │ │ │
│ │ ███░░░░░ │ │ │
├─────────────┴─────────────┴─────────────┴───────────────────┤
│ [Q]ueue [L]aunch [P]ause [R]esume [A]gents [N]otifs [?]Help│
└─────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ operator v0.1.28 ▶ RUNNING 5/7 │
├──────────┬────────────┬──────────────────┬───────────────────┤
│ STATUS │ QUEUE (12) │ IN PROGRESS (5) │ DONE (8) │
├──────────┼────────────┼──────────────────┼───────────────────┤
│ ▾ Config │ INV-003 ‼️ │ A▶ backend │ ✓ FEAT-040 12:30 │
│ ✓ dir │ FIX-089 │ FEAT-042 5m │ ✓ FIX-088 12:15 │
│ ✓ cfg │ FIX-090 │ A▶ frontend │ ✓ FEAT-041 11:45 │
│ ✓ tkts │ FEAT-043 │ FIX-091 3m │ ✓ FIX-087 11:30 │
│ ▾ Conns │ FEAT-044 │ C⏸ api │ │
│ ✓ API │ FEAT-045 │ SPIKE-015 12m │ │
│ ✓ Web │ │ Awaiting input │ │
│ tmux │ │ A▶ admin │ │
│ ▸ Kanban │ │ FEAT-047 1m │ │
│ ▸ LLM │ │ A▶ infra │ │
│ ▸ Git │ │ FIX-092 8m │ │
├──────────┴────────────┴──────────────────┴───────────────────┤
│ [Q]ueue [L]aunch [P]ause [R]esume [A]gents [?]Help [q]uit │
└──────────────────────────────────────────────────────────────┘
```

## Keyboard Shortcuts
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.27
0.1.28
2 changes: 1 addition & 1 deletion backstage-server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "operator-backstage",
"version": "0.1.27",
"version": "0.1.28",
"author": {
"name": "Samuel Volin",
"email": "untra.sam@gmail.com",
Expand Down
4 changes: 4 additions & 0 deletions bindings/BackstageConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ export type BackstageConfig = {
* Whether Backstage integration is enabled
*/
enabled: boolean,
/**
* Whether to show Backstage in the Connections status section
*/
display: boolean,
/**
* Port for the Backstage server
*/
Expand Down
31 changes: 31 additions & 0 deletions bindings/CreateDelegatorFromToolRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { DelegatorLaunchConfigDto } from "./DelegatorLaunchConfigDto";

/**
* Request to create a delegator from a detected LLM tool
*
* Pre-populates delegator fields from the detected tool, requiring minimal input.
* If `name` is omitted, auto-generates as `"{tool_name}-{model}"`.
* If `model` is omitted, uses the tool's first model alias.
*/
export type CreateDelegatorFromToolRequest = {
/**
* Name of the detected tool (e.g., "claude", "codex", "gemini")
*/
tool_name: string,
/**
* Model alias to use (e.g., "opus"). If omitted, uses the tool's first model alias.
*/
model: string | null,
/**
* Custom delegator name. If omitted, auto-generates as `"{tool_name}-{model}"`.
*/
name: string | null,
/**
* Optional display name for UI
*/
display_name: string | null,
/**
* Optional launch configuration
*/
launch_config: DelegatorLaunchConfigDto | null, };
14 changes: 14 additions & 0 deletions bindings/DefaultLlmResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* Response with the current default LLM tool and model
*/
export type DefaultLlmResponse = {
/**
* Default tool name (empty string if not set)
*/
tool: string,
/**
* Default model alias (empty string if not set)
*/
model: string, };
25 changes: 24 additions & 1 deletion bindings/DelegatorLaunchConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

/**
* Launch configuration for a delegator
*
* Controls how the delegator launches agents. Optional fields use tri-state
* semantics: `None` = inherit from global config, `Some(true/false)` = override.
*/
export type DelegatorLaunchConfig = {
/**
Expand All @@ -15,4 +18,24 @@ permission_mode: string | null,
/**
* Additional CLI flags
*/
flags: Array<string>, };
flags: Array<string>,
/**
* Override global `git.use_worktrees` per-delegator (None = use global setting)
*/
use_worktrees: boolean | null,
/**
* Whether to create a git branch for the ticket (None = default behavior)
*/
create_branch: boolean | null,
/**
* Run in docker container (None = use global `launch.docker.enabled`)
*/
docker: boolean | null,
/**
* Prompt text to prepend before the generated step prompt
*/
prompt_prefix: string | null,
/**
* Prompt text to append after the generated step prompt
*/
prompt_suffix: string | null, };
25 changes: 24 additions & 1 deletion bindings/DelegatorLaunchConfigDto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

/**
* Launch configuration DTO for delegators
*
* Optional fields use tri-state semantics: `None` = inherit global config,
* `Some(true/false)` = explicit override per-delegator.
*/
export type DelegatorLaunchConfigDto = {
/**
Expand All @@ -15,4 +18,24 @@ permission_mode: string | null,
/**
* Additional CLI flags
*/
flags: Array<string>, };
flags: Array<string>,
/**
* Override global `git.use_worktrees` (None = use global setting)
*/
use_worktrees: boolean | null,
/**
* Whether to create a git branch for the ticket (None = default behavior)
*/
create_branch: boolean | null,
/**
* Run in docker container (None = use global `launch.docker.enabled`)
*/
docker: boolean | null,
/**
* Prompt text to prepend before the generated step prompt
*/
prompt_prefix: string | null,
/**
* Prompt text to append after the generated step prompt
*/
prompt_suffix: string | null, };
14 changes: 14 additions & 0 deletions bindings/GithubCredentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* Ephemeral GitHub Projects credentials supplied by a client during onboarding.
*
* The token must have `project` (or `read:project`) scope. A repo-only token
* (the kind used for `GITHUB_TOKEN` and operator's git provider) will be
* rejected at validation time with a friendly "lacks `project` scope" error.
*/
export type GithubCredentials = {
/**
* GitHub PAT, fine-grained PAT, or app installation token
*/
token: string, };
26 changes: 26 additions & 0 deletions bindings/GithubProjectInfoDto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* A GitHub Project v2 surfaced during onboarding for project picker UIs.
*/
export type GithubProjectInfoDto = {
/**
* `GraphQL` node ID (e.g., `PVT_kwDOABcdefg`) — used as the project key
*/
node_id: string,
/**
* Project number (e.g., 42) within the owner
*/
number: number,
/**
* Human-readable project title
*/
title: string,
/**
* Owner login (org or user name)
*/
owner_login: string,
/**
* "Organization" or "User"
*/
owner_kind: string, };
33 changes: 33 additions & 0 deletions bindings/GithubProjectsConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ProjectSyncConfig } from "./ProjectSyncConfig";

/**
* GitHub Projects v2 (kanban) provider configuration
*
* The owner login (user or org) is specified as the `HashMap` key in
* `KanbanConfig.github`. Project keys inside `projects` are `GraphQL` node
* IDs (e.g., `PVT_kwDOABcdefg`) — opaque, stable identifiers used directly
* by every GitHub Projects v2 mutation without needing a lookup.
*
* **Distinct from `GitHubConfig`** (the git provider used for PR/branch
* operations). They live in different parts of the config tree, use
* different env vars (`OPERATOR_GITHUB_TOKEN` vs `GITHUB_TOKEN`), and
* require different OAuth scopes (`project` vs `repo`). See
* `docs/getting-started/kanban/github.md` for the full rationale.
*/
export type GithubProjectsConfig = {
/**
* Whether this provider is enabled
*/
enabled: boolean,
/**
* Environment variable name containing the GitHub token (default:
* `OPERATOR_GITHUB_TOKEN`). The token must have `project` (or
* `read:project`) scope, NOT just `repo` — see the disambiguation
* guide in the kanban github docs.
*/
api_key_env: string,
/**
* Per-project sync configuration. Keys are `GraphQL` project node IDs.
*/
projects: { [key in string]?: ProjectSyncConfig }, };
6 changes: 6 additions & 0 deletions bindings/GithubSessionEnv.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* GitHub Projects session env body — includes the actual secret to set in env.
*/
export type GithubSessionEnv = { token: string, api_key_env: string, };
25 changes: 25 additions & 0 deletions bindings/GithubValidationDetailsDto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { GithubProjectInfoDto } from "./GithubProjectInfoDto";

/**
* GitHub-specific validation details (returned on success).
*/
export type GithubValidationDetailsDto = {
/**
* Authenticated user's login (e.g., "octocat")
*/
user_login: string,
/**
* Authenticated user's numeric `databaseId` as a string (used as `sync_user_id`)
*/
user_id: string,
/**
* All Projects v2 visible to the token (across viewer + organizations)
*/
projects: Array<GithubProjectInfoDto>,
/**
* The env var name the validated token came from. Used by clients to
* display "Connected via `OPERATOR_GITHUB_TOKEN`" so users can rotate the
* right token. See Token Disambiguation in the kanban github docs.
*/
resolved_env_var: string, };
Loading
Loading