OrcAI.Tool 0.8.0

dotnet tool install --global OrcAI.Tool --version 0.8.0
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local OrcAI.Tool --version 0.8.0
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=OrcAI.Tool&version=0.8.0
                    
nuke :add-package OrcAI.Tool --version 0.8.0
                    

OrcAI CLI

<p align="center"> <img src="assets/orcai_banner.png" alt="OrcAI" /> </p>

A CLI tool for orchestrating bulk GitHub work across many repositories. From a single YAML config, OrcAI creates a GitHub Project, opens templated issues in every target repo, and hands them off to whoever (or whatever) does the work — a human teammate, a bot, or an AI agent like GitHub Copilot or OpenCode.

Features

  • Declarative YAML jobs — one config defines the project, target repos, issue template, assignment behaviour, nudge policy, and notification template.
  • Bulk, idempotent issue creation across any number of repos — a lock file makes re-runs free; glob and brace expansion ("jobs/**/*.{yml,yaml}") for fanning out.
  • GitHub Project auto-management — finds or creates the board and links every issue to it.
  • Assign to anyoneassign.to accepts any GitHub user, bot, or GitHub App handle. Default is @copilot, but humans, OpenCode, and custom App bots all work.
  • Comment-based triggersassign.via: comment posts a slash command (e.g. /opencode) instead of assigning, for agents that listen for mentions. comment-and-assign does both.
  • Tag anyone in templated commentsassign.comment, nudge.comment, and notify all support {assignee}, {job.owner}, and {repo.codeowners} tokens, resolved from YAML and CODEOWNERS files at runtime.
  • orcai nudge — re-trigger stale issues (no linked PR yet) by reassignment, comment, or both.
  • orcai notify — broadcast a templated comment to issues and/or PRs from the lock file; filter by state, dry-run, and inject extra --data key=value template variables.
  • Auto issue-body updates — when the Markdown template changes, existing issues' bodies are updated without re-running the structural work (hash-based detection).
  • Robust at scale — built-in rate limiting (60 writes/min, configurable) with exponential-backoff retry; closed-issue policy (create/reopen/skip/fail); concurrency control; --continue-on-error; JSON output for CI.
  • Multiple auth methods — ambient gh CLI, PAT, or GitHub App (manifest flow supported via orcai auth create-app). A PAT is only required when the assignee is @copilot.

Installation

OrcAI is distributed as a .NET global tool. Requires .NET 10 or later.

dotnet tool install --global OrcAI.Tool

Then run it as orcai.

Prerequisites

  • gh CLI: Install from cli.github.com — must be installed and on PATH
  • Authentication: The easiest option is to ensure gh is authenticated (gh auth login). OrcAI will use it automatically. For other methods see docs/cli-reference.md.

Quick start

1. Authenticate

The simplest option — if you already use the gh CLI, just make sure it's authenticated:

gh auth login

That's it. OrcAI will pick up the token automatically.

For PAT, GitHub App, or environment variable auth see docs/cli-reference.md.

2. Run a job

# Single config file
orcai run jobs/my-upgrade.yml

# All configs in a directory (quote the glob to prevent shell expansion)
orcai run "jobs/*.yml" --continue-on-error --json

# Limit concurrency to avoid rate limits
orcai run "jobs/*.yml" --max-concurrency 2

run finds or creates a GitHub Project, creates issues from your template, adds them to the project, and triggers the configured assignee — whether that's @copilot, another bot, an AI agent like OpenCode, or a human teammate. Triggering can be via assignment, a templated comment (e.g. a slash command), or both. On success a lock file (<basename>.lock.json) is written alongside the YAML for fast idempotent re-runs.

Commands

Command Description
orcai auth pat/app/create-app/switch Store credentials or switch profiles for all other commands
orcai generate Scaffold a YAML job config and stub issue template
orcai run Execute a bulk upgrade job (supports globs, concurrency control, JSON output)
orcai nudge Re-trigger stale issues with no linked PR (reassign, comment, or both)
orcai notify Post a templated comment to issues and/or PRs from the lock file
orcai validate Validate YAML config(s) and verify all repos are accessible
orcai info Display the current state of a job
orcai cleanup Tear down everything created by run

For full flag details, output formats, lock file schema, and advanced usage see docs/cli-reference.md. For config file settings see docs/config.md.

The original Nushell scripts (orca.nu, cleanup.nu) are documented in docs/nushell-scripts.md.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
0.8.0 0 6/9/2026
0.7.5-beta6 0 6/9/2026
0.7.4-beta5 90 5/21/2026
0.7.3-beta4 102 5/19/2026
0.7.2-beta3 96 5/18/2026
0.7.1-beta2 107 5/18/2026
0.7.0-beta1 94 5/13/2026
0.6.0 111 5/7/2026
0.5.1 253 3/17/2026
0.5.0 127 3/16/2026
0.4.4 127 3/16/2026
0.4.3 117 3/16/2026
0.4.2 126 3/16/2026
0.4.1 119 3/15/2026
0.4.0 115 3/13/2026
0.3.0 120 3/11/2026

`orcai run --dryrun` — preview what would be created, reopened, or updated without making any GitHub API calls or writing the lock file. Read-only lookups still run so the preview reflects current state. Outcomes are reported per repo as `would create`, `would reopen`, or `would update`, with a summary line and `dryRunWouldCreate` / `dryRunWouldReopen` / `dryRunWouldUpdate` counts in `--json`.
`orcai notify` command — posts a templated comment to issues and/or PRs recorded in the lock file. Supports the same `{assignee}`, `{job.owner}`, and `{repo.codeowners}` template tokens as `nudge.comment`.
`--target issues|prs|both` — which lock file items to notify (default: `issues`).
`--state open|closed|all` — filter by current GitHub state before commenting (default: `open`); `closed` matches both closed and merged PRs; `all` skips the live state check entirely.
`--dryrun` — preview which items would be notified without posting any comments.
`--verbose` — print per-item progress to stderr.
`--template <string>` — inline comment template supplied directly on the CLI; overrides `notify.comment` from YAML/config.
`--data key=value` — inject an extra template variable (repeatable). E.g. `--data sprint=42`.
`--json-data <json>` — inject extra template variables as a JSON object string. Merged with `--data`; `--data` takes precedence on key conflicts. User-supplied values override built-in tokens (`{assignee}` etc.) when the same key is used.
`notify` block in YAML job config and global/local JSON config — configures the comment template for `orcai notify`.
`notify.comment` — comment body template. Supports the same `{assignee}`, `{job.owner}`, and `{repo.codeowners}` tokens as `nudge.comment`.
`orcai run` records repos that were skipped because they are archived in a new `skippedRepos` field in the lock file. The run summary and `--json` output include a `skippedArchived` count and status.
`orcai run` detects when the lock file points to a deleted or transferred issue and recreates the issue in place instead of failing. New `staleIssueRecreated` count/status in the summary and `--json` output; the lock file is rewritten with the new issue numbers.
`orcai run` now persists error information in the lock file when a repo fails to process, allowing errors to be surfaced in subsequent runs instead of being silently ignored as "not created". New `failures` field in the lock file maps repo, attempts, and action that failed.
`orcai nudge` and `orcai notify` rename `--dry-run` to `--dryrun` for consistency with `cleanup` (and the new `run --dryrun`). The old spelling is no longer accepted.
Comment-building logic (template variable resolution + `PostComment`) extracted from `RunCommand` and `NudgeCommand` into a shared internal `Comments` module, used by all three comment-posting paths.
`orcai run` now automatically updates issue bodies when the Markdown template changes. A `templateHash` field is stored in the lock file alongside the existing `yamlHash`, allowing the tool to detect which changed:
Either `.yml` or `.md` changed → structural re-run via `runFull`, honouring `onClosedIssue` policy. If the template hash changed, issue bodies are refreshed for any repos reconciled as `AlreadyExisted` or `Reopened`.
Neither changed → fast path, zero network calls (unchanged from before).
`--skip-lock` → structural re-run plus unconditional body refresh for `AlreadyExisted` / `Reopened`.
Old lock files without `templateHash` are treated as changed, triggering a one-time body sync on next run.
`assign` block in YAML job config and global/local JSON config — configures who receives the issue and how they are triggered. Applies to both `orcai run` and `orcai nudge`.
`assign.to` — assignee handle (default: `@copilot`). Accepts any GitHub user, bot, or GitHub App bot handle. Note: assigning `@copilot` requires a PAT (`ORCAI_PAT`) regardless of primary auth method, as GitHub Copilot can only be assigned via a user-level token.
`assign.via` — trigger method: `assign` (default), `comment`, or `comment-and-assign`. Use `comment` for agents triggered by slash commands (e.g. OpenCode's `/opencode`).
`assign.comment` — comment body posted when `via` includes `comment`. Supports template tokens (see below).
`nudge` block in YAML job config and global/local JSON config — configures how `orcai nudge` re-triggers the assignee on stale issues.
`nudge.mode` — `reassign` (default), `comment-only`, or `comment-and-reassign`.
`nudge.comment` — comment body posted on nudge. Supports template tokens (see below).
Dynamic template tokens in `assign.comment` and `nudge.comment` — placeholders resolved at runtime:
`{assignee}` — the configured `assign.to` handle.
`{job.owner}` — who owns the orcai job. Resolved from `job.owner` in the YAML (highest priority), then the catch-all `*` owner from a `CODEOWNERS` file in the current repository (checked at `CODEOWNERS`, `.github/CODEOWNERS`, `docs/CODEOWNERS`). Left unreplaced if neither is found.
`{repo.codeowners}` — the catch-all `*` owner from the target repository's `CODEOWNERS` file (fetched from GitHub). Left unreplaced if no `CODEOWNERS` is present or it has no `*` rule.
`job.owner` field in the YAML `job` block — statically sets the job owner for use in comment templates via `{job.owner}`. Overrides any CODEOWNERS-based discovery.
`orcai nudge` command now documented in the CLI reference.
Generated YAML scaffold now includes commented-out `assign:` and `nudge:` example blocks instead of the unused `copilot:` block.
The `copilot:` block previously scaffolded by `orcai generate` has been removed. It was never parsed and is superseded by the `assign:` block.
`--skip-copilot` is superseded by `assign.via: comment` (skips assignment while still allowing a trigger comment). The flag remains supported for backwards compatibility.
`ORCAI_LOG_LEVEL` environment variable — controls log verbosity. Accepts any `Microsoft.Extensions.Logging.LogLevel` name (`Trace`, `Debug`, `Information`, `Warning`, `Error`, `Critical`, `None`). Defaults to `Warning`.
Lock file schema: new `skippedRepos: string[]` field. Old lock files without this field still load (treated as empty); the field is populated on the next run.
Template bumps now go through `runFull`, honouring `onClosedIssue` policy and refreshing the body of reopened issues. Previously, editing only the MD template could silently rewrite the body of a closed issue and skip the body refresh for reopened issues.
`orcai run` no longer creates a duplicate issue when the GitHub API lookup itself fails. Transient `gh` errors during open- or closed-issue lookup (rate limits, network resets, exhausted retries) are now surfaced as a per-repo error instead of being silently treated as "no matching issue". This also restores `--on-closed-issue` semantics on lookup failures — the configured action (`reopen` / `skip` / `fail`) is no longer bypassed when the closed-issue query errors.
Assignment via GitHub App auth now only requires a PAT (`ORCAI_PAT`) when the assignee is `@copilot`. Assigning human users or other bots with a GitHub App (which has `issues: write` permission) no longer warns or skips — the PAT constraint was previously applied to all assignees, not just Copilot.
`orcai cleanup` no longer fails when a project, issue, or PR has already been deleted — the operation is treated as success and a warning is emitted instead.
Issue lookup now uses GitHub's title search (`in:title`) with a 100-result limit, preventing missed matches on repos with more than 30 open or closed issues.
PR lookup for an issue now queries GitHub's GraphQL API (`Issue.closingPullRequests`) instead of listing all PRs in the repo and filtering in memory — fixes silent data loss on repos with more than 30 PRs.
`orcai run` no longer errors out on archived repositories. Each repo is pre-checked with `gh repo view --json isArchived`; archived repos are skipped with a single informational line instead of cascading `Repository was archived so is read-only` errors from label and issue writes.
`orcai run --auto-create-labels` no longer produces spurious errors when a label already exists. Two fixes: (1) `gh label list` now uses `--limit 1000` so labels past page 1 are detected by the pre-check, and (2) `CreateLabel` is idempotent — a GitHub "already exists" / "already been taken" response is downgraded to success with a warning log.