README
¶
vigilante
vigilante is a GitHub-native control plane for autonomous software delivery. It watches repositories, selects executable issues, prepares isolated implementation environments, dispatches headless coding agents, keeps GitHub updated with progress, and maintains the delivery loop around pull requests.
It is a Go CLI and background service that runs locally on top of the tools teams already use: git, gh, and a supported coding-agent CLI such as codex, claude, or gemini. The current target platforms are macOS and Ubuntu.
What Vigilante Is
vigilante is the orchestration layer around coding agents. It is responsible for:
- treating GitHub issues as the work queue
- selecting eligible work based on labels, assignees, and repository limits
- creating dedicated git worktrees and issue branches for each session
- choosing the right execution playbook from repository classification
- launching supported coding-agent CLIs under a consistent lifecycle
- posting execution state back to GitHub through issue comments and PR tracking
- recovering, resuming, redispatching, and cleaning up local sessions safely
What Vigilante Is Not
vigilante is not the code-generating model itself. Tools such as Codex, Claude Code, and Gemini are the execution engines that read prompts, edit code, run validation, and prepare pull requests. Keeping orchestration separate from code generation lets Vigilante stay provider-neutral while owning scheduling, worktree isolation, GitHub coordination, and PR maintenance.
Why Use Vigilante
Vigilante turns a repository checkout into a controlled autonomous worker instead of a loose collection of scripts.
- GitHub stays the operator surface for issue intake, progress, resume commands, cleanup, and PR visibility.
- Each issue runs in an isolated worktree, which keeps the main checkout stable and makes unattended execution safer.
- Repository-aware skills let the same control plane adapt to standard repositories, monorepos, and supported build systems.
- Session state persists locally, so Vigilante can recover from failures, clean up stalled work, and avoid duplicate dispatch.
- Provider support is pluggable, so the orchestration layer remains stable even when teams change coding-agent runtimes.
Quickstart
Install with Homebrew:
brew tap aliengiraffe/spaceship
brew install --cask vigilante
Prepare the local machine with your preferred coding-agent provider:
vigilante setup --provider codex
Register a repository and install the background service:
vigilante watch -d ~/path/to/repo
Useful follow-up commands:
vigilante list
vigilante list --running
vigilante status
vigilante service restart
vigilante daemon run --once
Quickstart requirements:
gitghauthenticated against the GitHub account you want Vigilante to operate with- one supported coding-agent CLI installed locally:
codex,claude, orgemini
Product Goal
Turn a local checkout into an autonomous coding-agent worker:
vigilante watch ~/hello-world-app
Once a folder is registered, vigilante should:
- Resolve the repository path and detect the GitHub remote.
- Poll or subscribe for open GitHub issues through
gh. - Select issues that are ready to work and not already being handled.
- Launch a headless coding agent session in YOLO mode against a dedicated git worktree.
- Classify the watched repository and use the matching issue implementation skill from the repo
skills/folder as part of the execution prompt. - Post progress comments back to the GitHub issue, including session start and failures.
- Track watched repositories locally and optionally run as a daemon.
In the current implementation, that worker loop already covers repository onboarding, issue intake, isolated worktrees, provider orchestration, repo-aware execution skills, local session recovery, and part of the pull request maintenance path. CI/CD promotion and richer deployment control are planned next-stage capabilities.
Telemetry
Vigilante emits anonymous telemetry with two different purposes:
- PostHog analytics events track product usage, such as command starts and completions, using bounded properties like command name, feature area, result, platform, and distro.
- OTLP logs remain the operational debugging stream when log export is configured.
Analytics events intentionally avoid raw repository contents, issue text, file paths, and other free-form command arguments. Operators can disable both streams with DO_NOT_TRACK=1 or MYTOOL_NO_ANALYTICS=1.
Core Workflow
For each watched repository:
- Validate that the folder is a git repository.
- Inspect
originand infer the GitHub repository slug. - Ensure required tools are available:
gitgh- the configured coding-agent provider CLI (
codex,claude, orgemini)
- Ensure the bundled issue implementation skills from the repo
skills/folder are installed during setup, including companion agent metadata. - Query GitHub for open issues.
- Determine which issues are eligible for execution.
- Create a git worktree for the selected issue.
- Launch a supported coding agent headlessly in the worktree with a prompt that:
- uses the repo-aware issue implementation skill selected from repository classification
- passes the detected repo/process context into the prompt
- instructs the agent to comment on the issue when work starts
- instructs the agent to keep commenting as progress is made
- instructs the agent to report errors back to the issue
- Track the session state locally so the daemon does not duplicate work.
- Clean up or mark terminal states when the session exits.
Commands
vigilante --help and vigilante -h print top-level usage. Each command also supports command-specific help, for example:
vigilante watch --help
vigilante daemon run --help
Shell completion
Generate a completion script for a supported shell and source or install it in your shell startup files:
vigilante completion bash
vigilante completion zsh
vigilante completion fish
Examples:
vigilante completion zsh > "${fpath[1]}/_vigilante"
autoload -Uz compinit && compinit
vigilante completion bash > ~/.local/share/bash-completion/completions/vigilante
vigilante completion fish > ~/.config/fish/completions/vigilante.fish
Installation
Install vigilante from the Homebrew tap:
brew tap aliengiraffe/spaceship
brew install --cask vigilante
Upgrade later with:
brew upgrade --cask vigilante
vigilante watch [--assignee <value>] [--max-parallel <value>] [--provider <codex|claude|gemini>] <path>
Register a local repository for issue monitoring.
Expected behavior:
- expands
~and resolves the absolute path - validates the folder is a git repository
- discovers the GitHub remote from git config
- defaults the assignee filter to
meunless overridden - defaults
--max-parallelto0when not configured, where0means unlimited - defaults
--providertocodexunless overridden - resolves
meto the authenticated GitHub login at runtime before issue queries - stores the target in
~/.vigilante/watchlist.json
Example:
vigilante watch ~/hello-world-app
vigilante watch --assignee nicobistolfi ~/hello-world-app
vigilante watch --max-parallel 3 ~/hello-world-app
vigilante watch --max-parallel 0 ~/hello-world-app
vigilante watch --provider claude ~/hello-world-app
vigilante watch --provider gemini ~/hello-world-app
vigilante watch -d <path>
Register a repository and ensure the daemon/service is installed and started.
Expected behavior:
- adds the target to the watchlist
- installs the
vigilantedaemon on the current operating system - starts or reloads the service
vigilante list
Show the currently watched repositories and their metadata.
Expected fields:
- local path
- GitHub repository slug
- max parallel issue sessions
- daemon status
- last scan time
- active issue/session, if any
vigilante list --running
Show currently running sessions with their repository, issue number, branch, and worktree path.
vigilante status
Show whether the Vigilante OS-managed user service is installed and currently running.
Expected behavior:
- reports a stable
statevalue ofrunning,stopped, ornot-installed - includes the service manager, service identifier, and installed service file path
- exits successfully when the service is not installed so operators and scripts can inspect the reported state
- fails with a clear error on unsupported operating systems or when the underlying service manager cannot be queried
vigilante service restart
Restart the installed Vigilante user service through the operating system service manager.
Expected behavior:
- uses
launchctlon macOS andsystemctl --useron Linux - restarts the installed managed service instead of launching an unmanaged background process
- fails clearly when the service is not installed or the platform is unsupported
vigilante cleanup --repo <owner/name> [--issue <n>]
Clean up running sessions without touching unrelated historical session records.
Expected behavior:
--repo <owner/name> --issue <n>cleans up one running session for a single issue--repo <owner/name>cleans up all running sessions for one repository- removes the running-session blockage from local state
- removes the local worktree and issue branch when those artifacts are present and safe to delete
vigilante cleanup --all
Clean up all running sessions across all watched repositories.
vigilante redispatch --repo <owner/name> --issue <n>
Force a fresh local restart for one watched issue.
Expected behavior:
- fails clearly when the target repository is not currently watched
- stops any active local session for the target issue before redispatching
- removes the target issue worktree and local issue branch artifacts when safe to do so
- clears stale local session state for the target issue only
- immediately launches a brand-new implementation session using the current watched-repo configuration
- does not delete remote pull requests or remote branches
vigilante unwatch <path>
Remove a repository from the watchlist without deleting the repository itself.
vigilante daemon run
Run the long-lived watcher loop in the foreground. This is the process the OS service should execute.
By default it scans watched repositories every 1 minute. Use --interval to override that cadence for manual runs.
vigilante setup [--provider <codex|claude|gemini>]
Prepare the machine for autonomous execution.
Expected behavior:
- creates
~/.vigilante/ - initializes
watchlist.json - verifies
git,gh, and the selected coding-agent provider CLI - verifies the selected provider CLI reports a compatible build-supported version range, currently
>=0.114.0, <2.0.0forcodex,>=2.0.0, <3.0.0forclaude, and>=1.0.0, <2.0.0forgemini - installs the bundled coding-agent skills for regular runtime use, including any companion files under each skill directory
vigilante-issue-implementationvigilante-issue-implementation-on-monorepovigilante-issue-implementation-on-turborepovigilante-issue-implementation-on-nxvigilante-issue-implementation-on-rushvigilante-issue-implementation-on-rush-monorepovigilante-issue-implementation-on-bazelvigilante-issue-implementation-on-gradlevigilante-issue-implementation-on-bazel-monorepovigilante-conflict-resolutionvigilante-create-issuevigilante-local-service-dependenciesdocker-compose-launch
- installs or updates the daemon definition when requested
On macOS, vigilante setup -d resolves Homebrew-style symlinks before it prepares the daemon binary. The launchd plist still uses the invoked path, but Vigilante removes com.apple.provenance and com.apple.quarantine from the resolved binary when present, ad-hoc signs that binary, and runs spctl --assess --type execute -vv against the resolved path before loading the service.
If Gatekeeper still rejects the binary, the error now reports both the assessed path and the invoked path when they differ. A useful manual recovery sequence is:
realbin="$(python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' /opt/homebrew/bin/vigilante)"
xattr "$realbin"
xattr -d com.apple.provenance "$realbin" 2>/dev/null || true
xattr -d com.apple.quarantine "$realbin" 2>/dev/null || true
codesign --force --sign - "$realbin"
spctl --assess --type execute -vv "$realbin"
Development Mode
For fast local iteration, prefer running vigilante in the foreground instead of going through the installed OS service on every change.
If you use go-task, the repository includes a root Taskfile.yml for the main local workflows. Install task with either:
brew install go-task/tap/go-task
or:
go install github.com/go-task/task/v3/cmd/task@latest
Primary tasks:
task testrunsgo test ./...task buildbuilds./vigilantetask installcopies the built binary to~/.local/bin/vigilantetask setupruns./vigilante setuptask install-setupruns~/.local/bin/vigilante setuptask setup-daemonruns a small wrapper around~/.local/bin/vigilante setup -dthat retries once on macOS after cleaning up an existinglaunchdagent
Recommended loop:
task test
task build
task setup
./vigilante watch /path/to/repo
./vigilante daemon run --once
Useful development commands:
- run a single scan without installing the daemon:
go run ./cmd/vigilante daemon run --once
- run the foreground daemon loop directly from source:
go run ./cmd/vigilante daemon run --interval 30s
- rebuild the installed binary and refresh the installed provider skills:
task install
task install-setup
- reinstall the OS service after changing daemon or service behavior:
task setup-daemon
On macOS, task setup-daemon now performs one explicit recovery attempt when an existing com.vigilante.agent launch agent is already present. If the first refresh fails, the task cleans up the existing launch agent, retries once, and prints a short manual launchctl bootout ... hint if recovery still fails.
On macOS, vigilante setup -d also prepares the installed daemon binary before reloading the LaunchAgent by clearing an observed com.apple.provenance xattr, applying ad-hoc signing, and validating the binary with spctl. If macOS still rejects the binary, setup exits with a code-signing error instead of leaving the agent stuck in OS_REASON_CODESIGNING.
Notes:
- foreground runs are the quickest way to iterate on scheduler, worktree, and coding-agent execution behavior
- when
vigilanteruns from a repository checkout,setuprefreshes installed skills from the local reposkills/folder so skill edits are picked up immediately - when
vigilanteruns as an installed binary outside the repo checkout,setupuses skills embedded in the binary so it works from any directory without depending on the source tree - after changing service installation logic on macOS, rerun
setup -dso thelaunchdplist is regenerated with the current shell-derived PATH - the CLI entrypoint lives in
cmd/vigilante/, while non-exported implementation packages live underinternal/
CI and Releases
Pull requests are validated in GitHub Actions with native Go commands:
gofmt -l .go vet ./...go test ./...go build ./...goreleaser check
Tagged releases are built and published with GoReleaser. Pushing a version tag that matches {x}.{y}.{z} and points to a commit already reachable from main creates a GitHub Release with:
darwin/amd64darwin/arm64linux/amd64- a
checksums.txtfile for the published archives - an updated Homebrew cask in
aliengiraffe/homebrew-spaceshipsobrew install --cask vigilanteinstalls the tagged release fromaliengiraffe/spaceship
The release workflow requires a GitHub App that can write to the tap repository:
APP_ID: the GitHub App IDAPP_PRIVATE_KEY: the GitHub App private key
During a tagged release, GitHub Actions exchanges those secrets for a short-lived token scoped to aliengiraffe/homebrew-spaceship and passes it to GoReleaser as HOMEBREW_GITHUB_API_TOKEN.
Recommended release flow:
git checkout main
git pull --ff-only
git tag 1.2.3
git push origin 1.2.3
Tags that do not match the required version format, such as v1.2.3 or release-1.2.3, may start the release workflow but are rejected by the tag validation step before GoReleaser publishes artifacts. The release workflow also validates that the tagged commit is already merged into main before publishing to GitHub Releases.
Before cutting a release, validate the packaging config locally with:
goreleaser check
You can also confirm the Homebrew cask will target the published release archive names by checking the GoReleaser archive template:
vigilante_<version>_macOS_amd64.tar.gzvigilante_<version>_macOS_arm64.tar.gzvigilante_<version>_Linux_amd64.tar.gz
Local State
vigilante should maintain its local state under:
~/.vigilante/
Initial files:
config.json: service-level daemon configurationwatchlist.json: configured repositories being monitoredsessions.json: active or recent issue execution sessionslogs/: daemon and run logs
Suggested config.json shape:
{
"blocked_session_inactivity_timeout": "20m"
}
Notes:
blocked_session_inactivity_timeoutis a service-level setting shared across all watched repositories.- The default is
20m. - A blocked session is eligible for automatic local cleanup only after there have been no qualifying user comments on the issue, no session updates, and no worktree updates for longer than the configured timeout.
- This inactivity cleanup is conservative: it clears local blocked-session artifacts so the issue can be redispatched later, but it does not delete remote pull requests or remote branches automatically.
Suggested watchlist.json shape:
[
{
"path": "/Users/example/hello-world-app",
"repo": "owner/hello-world-app",
"branch": "main",
"assignee": "me",
"max_parallel_sessions": 0,
"daemon_enabled": true,
"last_scan_at": "2026-03-10T12:00:00Z"
}
]
Issue Selection Rules
The scheduler should stay conservative in the first version.
Initial rules:
- only consider open issues
- ignore pull requests
- enforce positive
max_parallel_sessionsindependently for each watched repository - treat
max_parallel_sessions: 0as unlimited parallel issue dispatch for that repository - count both running implementation sessions and open-PR maintenance sessions against that repository limit
- avoid duplicate work across multiple daemon scans
- allow an issue label that exactly matches a registered provider id, such as
codex,claude, orgemini, to override the watch target provider for that issue only - if more than one provider-id label is present on the same issue, skip dispatch instead of choosing a provider arbitrarily
- prefer oldest eligible open issue first unless later prioritization rules are added
Future policy can expand to richer label filters, assignment rules, and priority queues.
Pull Request Maintenance
For pull requests tied to an active Vigilante session:
- keep the branch updated against
origin/mainthrough the existing maintenance loop - if either the source issue or the PR has
vigilante:automerge, attempt a GitHub squash merge only after required checks pass and GitHub reports the PR is mergeable - keep the legacy plain
automergePR label working as a compatibility alias during migration to the namespaced label - never force through branch protection, required reviews, or failing checks
Issue Labeling System
Vigilante should use a small issue-label taxonomy that complements issue comments instead of replacing them. The repository-owned proposal lives in .github/labels.json.
Label ownership rules:
- Work-classification labels such as
bug,feature, andgood first issueremain repository-managed and should not be changed by Vigilante. vigilante:*lifecycle and intervention labels are primarily informational and should be set or cleared by Vigilante as the issue moves through execution.- Provider-routing labels
codex,claude, andgeminikeep their existing control semantics and remain human-managed overrides. vigilante:resumeis the preferred control label for unblocking a paused session;resumeremains a legacy-compatible alias.
Proposed groups:
- Execution state:
vigilante:queued,vigilante:running,vigilante:blocked,vigilante:ready-for-review,vigilante:awaiting-user-validation,vigilante:done - Human-intervention state:
vigilante:needs-human-input,vigilante:needs-provider-fix,vigilante:needs-git-fix - Provider routing controls:
codex,claude,gemini - Explicit control labels:
vigilante:resumeand legacyresume
Recommended lifecycle:
- When an issue becomes eligible but has not started, add
vigilante:queued. - When execution starts, replace
vigilante:queuedwithvigilante:running. - If execution stalls on a known blocker, replace
vigilante:runningwithvigilante:blockedand add exactly one matchingvigilante:needs-*label when possible. - When implementation is ready for a human to inspect, replace blocked or running state with
vigilante:ready-for-reviewas the single review-handoff label. - When code review is complete but a product or operator check is still required, use
vigilante:awaiting-user-validation. - When the issue reaches a terminal successful state, clear transient labels and leave
vigilante:done.
This keeps control semantics narrow while making the issue list readable at a glance. Existing label-based behaviors stay compatible: watch-target allowlists still match repository-managed labels, provider overrides still use provider ids, and blocked-session recovery still honors both resume and vigilante:resume.
Headless Agent Execution Contract
When vigilante launches a coding agent for an issue, it should:
- create a dedicated git worktree for that issue
- pass a prompt that includes the repository, issue number, and local working directory
- ensure the issue implementation skill is available
- instruct the agent to post a GitHub comment when the session starts
- instruct the agent to post progress comments during execution
- instruct the agent to report failures on the issue if execution aborts
The agent invocation remains a subprocess wrapper around an installed coding CLI such as codex, claude, or gemini, while keeping the orchestration behavior provider-neutral.
GitHub Integration
GitHub access should use gh rather than direct API client dependencies.
Expected gh responsibilities:
- detect authentication state
- list open issues for a repository
- post start/progress/error comments
- optionally inspect issue metadata needed for scheduling
This keeps the Go code smaller and delegates auth/session handling to the installed GitHub CLI.
Worktree Strategy
Each issue run should get an isolated worktree to prevent branch collisions and dirty working trees.
Suggested naming:
- branch:
vigilante/issue-<number>-<title-slug>with fallback compatibility for legacyvigilante/issue-<number>branches - worktree path: a repo-local path such as
<repo>/.worktrees/vigilante/issue-<number>
The daemon must track which worktrees are active so duplicate launches do not happen.
Daemon and Service Installation
Initial supported operating systems:
- macOS via
launchd - Ubuntu via
systemd --user
Service responsibilities:
- start
vigilante daemon run - restart on failure
- read the persisted watchlist
- write logs to
~/.vigilante/logs/
Error Handling
Failures should be visible both locally and on GitHub.
Minimum error reporting behavior:
- write structured local logs
- mark the local session as failed
- comment on the GitHub issue when the coding-agent session fails to start
- comment on the GitHub issue when a running session exits with error
Development Plan
The initial implementation should be split into issues covering:
- CLI scaffolding and config/state management
- Git repository and GitHub remote discovery
- GitHub issue polling through
gh - Coding-agent skill installation and prompt assembly
- Worktree lifecycle management
- Headless coding-agent session runner with GitHub progress comments
- Daemon loop and scheduler
- macOS and Ubuntu service installation
Current Status
The repository currently contains the initial Go module and a placeholder CLI. The feature set described above is the target specification that should now be implemented incrementally through GitHub issues.
Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
var LabelsManifest embed.FS
LabelsManifest contains the canonical Vigilante repository label definitions.
var Skills embed.FS
Skills contains built-in runtime skill files for installed binaries.
Functions ¶
This section is empty.
Types ¶
This section is empty.