BoxCI
GitHub Actions runners on your own InstaBox VMs.
They wake up for CI and pause again when idle.
Quick start · Use your agent · How it works · Commands · Migrate · Limits · Docs
BoxCI turns InstaBox VMs into dedicated GitHub Actions runners for your repository. Set up, migrate your existing CI, then run and monitor it, all from one CLI. No keepalive, no webhook server, no BoxCI account.
- Reviewable.
--dry-runshows the plan. Workflow changes stay local for you to review, commit and push. - Migrates existing CI.
boxci migrateretargets jobs (Blacksmith,ubuntu-latest) as a local diff. - Agent-ready. Paste one prompt, or use the bundled migration skill.
- Safe fallback. Fork PRs, or a pool that isn't ready, run on hosted
ubuntu-24.04. Fork code never sees your provider key. - Read-only dashboard.
boxci dashboardis local and authenticated, and never wakes a VM.
Quick start
Needs Node.js ^22.23.4 || >=24.22.1, Git, admin on a GitHub repo, and an InstaBox account with room for one more VM.
npm install -g @balasivagn/boxci
cd /path/to/your-app # the repo whose CI you want to change
boxci init --dry-run # preview, creates nothing
boxci init # approve the plan; writes .github/workflows/boxci-wake.yml
boxci migrate # pick existing jobs to move onto the pool
init and migrate only edit files locally. They never create a branch, commit, push or PR. Review git diff -- .github/workflows, commit and push it your usual way, merge to the default branch, then:
boxci ci run --workflow ci.yml
boxci status
Install tips
-
Older Node: npm only warns (
EBADENGINE).--versionand--helpwork, but setup stops with a certificate-trust error. Checknode --versionfirst. -
boxci: command not found: put npm's global bin onPATH, or install to a user prefix:npm install -g --prefix "$HOME/.local" @balasivagn/boxci export PATH="$HOME/.local/bin:$PATH" -
Update: rerun the install command.
-
Unreleased
main:npm install -g https://github.com/balasivagn/boxci/archive/refs/heads/main.tar.gz(swaprefs/heads/mainfor a commit SHA to pin). -
Pick the repo:
--repo owner/repository.initandmigratestill need a checkout with a matching GitHub remote. -
Test commands and toolchains live in your own workflows. Init generates no test job.
-
Interrupted? Rerun
boxci init; it resumes. On an already-configured repo it reports "Already configured" and changes nothing. -
HTTPS certificates: system certificates are used automatically. See certificate trust.
-
Existing pool? Dry run first, and read pool discovery and recovery.
Set up with a coding agent
Open your app's checkout in any agent with terminal access and paste:
Set up BoxCI for this application's repository; use https://github.com/balasivagn/boxci as the documentation reference. Install `npm install -g @balasivagn/boxci`, check `boxci --version`, and run all setup and migration commands from this application's checkout. Reuse my current GitHub/InstaBox sign-ins and show me `boxci init --dry-run` with the target repository for approval before applying. Then complete setup, migrate compatible existing Linux x64 CI jobs with `boxci migrate`, preserve existing pools, verify with `boxci doctor` and `boxci status`, and leave all workflow changes locally for my review. Do not commit, push, or open a PR.
You complete the browser sign-ins and approve the plan.
How it works
- Wake. A hosted Ubuntu job wakes every pool VM for trusted events and checks their runner services. It never checks out PR code.
- Route. Pool ready: the build targets your dedicated self-hosted label. Otherwise, and always for fork PRs, it uses hosted
ubuntu-24.04. - Run. GitHub assigns the build to an idle runner. Afterwards the VMs follow InstaBox's normal idle suspension.
More: architecture and source map · interactive diagram (download and open locally)
Commands
| Command | What it does |
|---|---|
boxci init | Set up runner, secret and pool variable; write the wake helper |
boxci migrate | Move existing workflow jobs onto the pool |
boxci ci run | Dispatch a connected workflow (--workflow file.yml, --ref) |
boxci status | VM and runner states, recent jobs (passive) |
boxci doctor | Check account, quota, mapping, merge state, key expiry |
boxci dashboard | Start or reopen the background read-only dashboard |
boxci dashboard status/stop | Check or stop the dashboard; runners are unaffected |
boxci wake | Explicitly wake the pool |
boxci pool add --count 1 | Add a VM, within your quota |
boxci auth renew | Rotate the 30-day CI credential |
boxci help [command] | Help for boxci or one command (also --help, -h, --version) |
Flags: --dry-run previews any change, --yes skips the prompt, --json gives structured output, --repo selects the repository. status, doctor and dashboard never run guest commands or wake VMs.
The dashboard keeps running after you close the terminal and doesn't restart on reboot. --no-open skips the browser, --foreground is for debugging, --port N chooses the local port (0-65535; the default, 0, picks a free port; stop a running dashboard first to change it). See dashboard operations.
Migrate existing jobs
boxci migrate --match blacksmith --dry-run
boxci migrate --match blacksmith
No flags picks jobs interactively; --jobs file.yml:job,... names them; boxci init --migrate-workflows migrates right after setup. Rerunning reuses the existing pool and helper.
The wake logic lives in .github/workflows/boxci-wake.yml. Your workflow calls it, and chosen jobs consume its output:
jobs:
boxci-wake:
uses: ./.github/workflows/boxci-wake.yml
with:
pool: ${{ vars.BOXCI_POOL }}
runner-label: your-boxci-label
secrets:
api-key: ${{ secrets.BOXCI_API_KEY }}
test:
needs: boxci-wake
runs-on: ${{ fromJSON(needs.boxci-wake.outputs.runner) }}
Commit the helper and its callers together. To have your agent do it, point it at skills/boxci-migrate/SKILL.md and ask, e.g. "move our Blacksmith test jobs onto BoxCI".
--matchis a case-insensitive regular expression tested against each job's staticruns-on.--jobswins over--match. Dynamic expressions are skipped.- Pick Linux x64 jobs that also work on the hosted fallback. Check matrix jobs and complex
needsby hand. - Only scheduling changes. Toolchains, services and caches stay as they are.
- Generated inline wake blocks can be extracted. Customized ones and conflicting helper files need manual review.
- A starter workflow left by an older release is kept as a legacy file. Remove it yourself if redundant.
Limits
- Requirements: GitHub.com repo with admin access and Actions enabled. Paused VMs still count toward InstaBox quota. Existing GitHub and InstaBox sign-ins are reused; BoxCI bundles the InstaBox CLI and can install a checksum-verified GitHub CLI privately.
- Use a dedicated InstaBox account for CI. The CI key can run commands on every VM in its account.
- Capacity: one job per runner. Up to five VMs, within quota. More VMs help only with multiple jobs or a matrix. BoxCI never deletes another VM to free quota.
- Cost and speed: no promises. BoxCI charges nothing, but InstaBox usage and hosted wake/fallback jobs bill as usual, and there is no spending cap. See InstaBox limits.
- Credential expires every 30 days with no automatic renewal.
boxci doctorwarns within seven days; runboxci auth renew. If it lapses, jobs fall back to hosted Ubuntu. See renewing. - Queued job after wake: runner readiness doesn't prove GitHub connectivity, and fallback is chosen before assignment, so it can't rescue a job already queued. See troubleshooting.
- Status: v0.4.1, early. POSIX shell commands only; native Linux/Windows bootstrap is unverified (validation). No automatic uninstall; see stop using BoxCI.
- Affiliation: independent open source. Not built or endorsed by InstaBox, and not affiliated with boxci.dev.
Docs
| Guide | Covers |
|---|---|
| Configuration | Sign-in, local records, repo settings, pool discovery |
| Operations | Renewal, adding capacity, recovery, troubleshooting |
| Architecture | Setup, CI and monitoring paths |
| Validation | What is tested and what isn't |
| Releasing | npm trusted publishing, GitHub releases |
| Security | Credential scope and isolation limits |
Contributing
Ideas, feature requests and collaboration are welcome: open an issue. Tests need no live credentials.
git clone https://github.com/balasivagn/boxci.git
cd boxci && npm ci
npm test
python3 -m unittest discover -s ci/tests
npm run check
npm pack --dry-run
ci/wake.py and vendor/install.sh are security-sensitive; changes need matching Python tests (see AGENTS.md). Keep scratch files in the ignored .orca-scratch/. More: developer experience · design tokens · project site.
License
Apache-2.0. Third-party notices in NOTICE and vendor/. Provider tools and vendored fonts keep their own licenses.