Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
51df415
refactor(adapters): iso_to_epoch dedupes BSD/GNU date split (Windows …
joelteply Apr 27, 2026
74cebe2
fix(prereqs): strict python3 probe — Windows Store alias defeats comm…
joelteply Apr 27, 2026
506a911
fix(sidecar): inherit --no-gist flag so tests stop leaking live #gene…
joelteply Apr 27, 2026
3606845
fix(gist): git-clone fallback + |\| true guards under rate-limit (thi…
joelteply Apr 27, 2026
5f5302e
feat(doctor,install): probe sshd readiness + scope strict-probe to py…
joelteply Apr 27, 2026
db48e7a
feat(install): auto-install + start sshd during install (close "this …
joelteply Apr 27, 2026
4576c18
fix(sshd-probe): macOS launchctl print system + osascript admin dialo…
joelteply Apr 27, 2026
e26913d
fix(doctor): tailscale probe uses resolve_tailscale_bin (catch GUI in…
joelteply Apr 27, 2026
2ea742d
fix(install,doctor): Windows HNS port-22 reservation (continuum's dia…
joelteply Apr 27, 2026
4a81484
fix(parser,prereq): jq is required — fallback parser corrupts gist en…
joelteply Apr 27, 2026
99e3e20
fix(python): AIRC_PYTHON env var replaces broken export -f shim (THE …
joelteply Apr 27, 2026
caa0b5e
fix(airc): two PR #164 followups — sed missed line 1372 + harden host…
joelteply Apr 27, 2026
7a14984
feat(airc_core): Python truth-layer foundation + first migration (#15…
joelteply Apr 27, 2026
74560f2
feat(airc_core): migrate config CRUD to airc_core.config (#152 Phase …
joelteply Apr 27, 2026
db89174
feat(airc_core): handshake response parser → airc_core.handshake (#15…
joelteply Apr 27, 2026
1536d8f
feat(airc_core): collapse _whois_in_scope + resolve_name + cmd_rename…
joelteply Apr 27, 2026
100dd00
feat(airc_core): joiner handshake send → airc_core.handshake.send (#1…
joelteply Apr 27, 2026
0354658
feat(airc_core): monitor_formatter → airc_core.monitor_formatter (250…
joelteply Apr 27, 2026
ee02754
feat(airc_core): host pair-handshake accept_one → airc_core.handshake…
joelteply Apr 27, 2026
088adbc
feat(airc-bash): split — extract platform_adapters.sh as Phase 3 feas…
joelteply Apr 27, 2026
4a38885
fix(airc_core): use argparse --flags for all paths, not env vars (con…
joelteply Apr 27, 2026
27cbd01
feat(airc-bash): extract cmd_doctor — airc under 5000 lines (Phase 3)…
joelteply Apr 27, 2026
1c172f4
fix(airc_core): config set_host_block — close last env-var-pass site …
joelteply Apr 27, 2026
8b55aed
fix(msys): MSYS2_ARG_CONV_EXCL — last layer; cross-machine VERIFIED e…
joelteply Apr 27, 2026
dee3b6c
fix(encoding): PYTHONIOENCODING=utf-8 at airc startup (continuum's si…
joelteply Apr 27, 2026
9c08ce4
fix(airc): rename propagates to sibling scopes; cmd_send --internal f…
joelteply Apr 28, 2026
e9f3f05
fix(airc): pair-listener parent-watch — orphan-process port-hold (#13…
joelteply Apr 28, 2026
b1092fb
ci: clean-install matrix (linux + macos + windows + windows-ps5) (#186)
joelteply Apr 28, 2026
b8ce896
fix(windows-install-e2e): real CI prereq path + Tailscale typo + Defa…
joelteply Apr 28, 2026
f23c9e2
fix(airc): surface monitor-escalation to stdout + daemon-aware (#184)…
joelteply Apr 28, 2026
dbc295b
fix(airc list): hide stale entries by default; --all to show; --prune…
joelteply Apr 28, 2026
116bdef
fix(install.sh): Windows-from-bash works end-to-end (#94 Tailscale, #…
joelteply Apr 28, 2026
6a9c447
fix(install.sh): elevated PS transcript + step-by-step output (Joel: …
joelteply Apr 28, 2026
b4699ac
fix(install.sh): ssh-keygen probe — drop --version, bin has no such f…
joelteply Apr 28, 2026
c6ddb86
fix(install/airc): elevated transcript path; Tailscale Windows GUI fa…
joelteply Apr 28, 2026
615b57a
fix(install.sh): stage payload as .ps1 file + ssh-keygen -A for hostk…
joelteply Apr 28, 2026
3b0b379
fix(install.sh): auto-run 'gh auth setup-git' so gist ops stop prompt…
joelteply Apr 28, 2026
132b67c
feat(airc daemon): Windows support via HKCU Run-key autostart (no adm…
joelteply Apr 28, 2026
34f354e
fix(airc daemon): scope tracks cwd, not always $HOME/.airc (#201)
joelteply Apr 28, 2026
d4c5e60
fix(airc daemon): launcher cd's to cwd, skip AIRC_HOME (kills crashlo…
joelteply Apr 28, 2026
8e9c66d
fix(airc daemon): sentinel-marker for intentional re-exec on Windows …
joelteply Apr 28, 2026
7828437
refactor(airc): _reexec_into helper consolidates 5 exec sites (#205 t…
joelteply Apr 28, 2026
c2ab471
refactor: _to_win_path / _to_bash_path helpers (#205 Target #3) (#207)
joelteply Apr 28, 2026
1f6e8d7
refactor(airc): _self_heal_stale_host helper (#205 target 4) — net -2…
joelteply Apr 28, 2026
678d7a5
refactor(airc): _daemon_install_done helper + trim daemon comments (#…
joelteply Apr 28, 2026
264fe06
refactor: set_config_val + parted_rooms unification (#205 target 6, n…
joelteply Apr 28, 2026
19ca947
refactor: unify _daemon_os into detect_platform (#205, net -26) (#211)
joelteply Apr 28, 2026
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
221 changes: 221 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
name: ci

# Three jobs on every PR + every push to canary/main:
#
# clean-install-linux ubuntu install.sh + airc doctor + smoke test
# clean-install-macos macos install.sh + airc doctor + smoke test
# clean-install-windows windows install.ps1 + airc doctor (PS-side)
Comment on lines +3 to +7
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Workflow header comment says “Three jobs on every PR + every push”, but the workflow now defines four clean-install jobs (linux/macos/windows/windows-ps5) plus integration-suite on push. Update the comment block to match the actual job set so future edits don’t drift based on incorrect docs.

Suggested change
# Three jobs on every PR + every push to canary/main:
#
# clean-install-linux ubuntu install.sh + airc doctor + smoke test
# clean-install-macos macos install.sh + airc doctor + smoke test
# clean-install-windows windows install.ps1 + airc doctor (PS-side)
# Four clean-install jobs on every PR + every push to canary/main:
#
# clean-install-linux ubuntu install.sh + airc doctor + smoke test
# clean-install-macos macos install.sh + airc doctor + smoke test
# clean-install-windows windows install.ps1 + airc doctor (PS-side)
# clean-install-windows-ps5 windows install.ps1 + airc doctor (PS 5.1)

Copilot uses AI. Check for mistakes.
#
# Plus on canary/main only (skipped on PR): integration-suite runs the
# full test/integration.sh on ubuntu — the most thorough gate, but
# expensive (real gh-gist scenarios + ~5min runtime).
#
# The clean-install jobs are the "guarantee installs work from zero"
# gate Joel asked for (2026-04-28). They run on a stock runner image
# with no airc preinstalled, exercise install.{sh,ps1} the way a real
# first-time user would, and validate the binary lands + doctor reports
# clean. Without these, every Windows install bug (#94, #96, #98, #99)
# slipped past every PR review and only surfaced when a user hit them.

on:
pull_request:
branches: [canary, main]
push:
branches: [canary, main]

# A previous push's CI gets cancelled if the same branch / PR pushes
# again. Prevents queue pileup when several PRs land in quick succession.
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
clean-install-linux:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Stage install.sh in a temp dir (simulate first-time user)
# The shipped install.sh clones from the canonical github URL.
# In CI we want it to install FROM THIS COMMIT, not from main —
# otherwise we'd be testing the published install.sh against
# whatever's already on the canonical branch, not the PR.
# Override AIRC_DIR + skip the clone step by pre-populating
# the source tree, then run install.sh's PATH/skills wiring.
run: |
mkdir -p $HOME/.airc-src
cp -r . $HOME/.airc-src/
# Real install — no AIRC_SKIP_PREREQS. install.sh must
# detect the package manager and install everything missing.
AIRC_DIR=$HOME/.airc-src bash install.sh

- name: airc doctor (must report environment-clean)
run: |
export PATH="$HOME/.local/bin:$PATH"
which airc
airc doctor

- name: Smoke — connect --no-room --no-gist + teardown
run: |
export PATH="$HOME/.local/bin:$PATH"
export AIRC_HOME=/tmp/ci-airc/state
export AIRC_NO_DISCOVERY=1 AIRC_NO_GENERAL=1 AIRC_NO_IDENTITY_PROMPT=1
mkdir -p /tmp/ci-airc/state
# Spawn host in background. --no-gist keeps it offline.
airc connect --no-room --no-gist > /tmp/ci-airc/host.log 2>&1 &
# Wait up to 10s for airc.pid to appear (airc writes it once
# the host loop is up). Don't pgrep on argv — airc's actual
# process line is `bash /path/to/airc connect ...` and pgrep
# patterns are brittle across distros.
for i in 1 2 3 4 5 6 7 8 9 10; do
[ -f /tmp/ci-airc/state/airc.pid ] && break
sleep 1
done
if [ ! -f /tmp/ci-airc/state/airc.pid ]; then
echo "FAIL: airc.pid never appeared — connect didn't reach host loop"
cat /tmp/ci-airc/host.log || true
exit 1
fi
# Verify all PIDs in airc.pid are alive.
for p in $(cat /tmp/ci-airc/state/airc.pid); do
if ! kill -0 "$p" 2>/dev/null; then
echo "FAIL: PID $p in airc.pid is not alive"
cat /tmp/ci-airc/host.log || true
exit 1
fi
done
echo "✓ airc connect stayed up (pids: $(cat /tmp/ci-airc/state/airc.pid))"
airc teardown
sleep 1
# After teardown, airc.pid is removed AND no PID from it should
# still be alive. We saved the pids before teardown for the
# post-check.
if [ -f /tmp/ci-airc/state/airc.pid ]; then
echo "FAIL: airc teardown left airc.pid behind"
exit 1
fi
echo "✓ airc teardown clean"

clean-install-macos:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Stage install.sh + run (no skip-prereqs — real install path)
run: |
mkdir -p $HOME/.airc-src
cp -r . $HOME/.airc-src/
AIRC_DIR=$HOME/.airc-src bash install.sh

- name: airc doctor (must report environment-clean)
run: |
export PATH="$HOME/.local/bin:$PATH"
which airc
airc doctor

- name: Smoke — same as linux (airc.pid based)
run: |
export PATH="$HOME/.local/bin:$PATH"
export AIRC_HOME=/tmp/ci-airc/state
export AIRC_NO_DISCOVERY=1 AIRC_NO_GENERAL=1 AIRC_NO_IDENTITY_PROMPT=1
mkdir -p /tmp/ci-airc/state
airc connect --no-room --no-gist > /tmp/ci-airc/host.log 2>&1 &
for i in 1 2 3 4 5 6 7 8 9 10; do
[ -f /tmp/ci-airc/state/airc.pid ] && break
sleep 1
done
if [ ! -f /tmp/ci-airc/state/airc.pid ]; then
echo "FAIL: airc.pid never appeared — connect didn't reach host loop"
cat /tmp/ci-airc/host.log || true
exit 1
fi
for p in $(cat /tmp/ci-airc/state/airc.pid); do
if ! kill -0 "$p" 2>/dev/null; then
echo "FAIL: PID $p in airc.pid is not alive"
cat /tmp/ci-airc/host.log || true
exit 1
fi
done
echo "✓ airc connect stayed up (pids: $(cat /tmp/ci-airc/state/airc.pid))"
airc teardown
sleep 1
if [ -f /tmp/ci-airc/state/airc.pid ]; then
echo "FAIL: airc teardown left airc.pid behind"
exit 1
fi
echo "✓ airc teardown clean"

clean-install-windows:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Run install.ps1 (no skip — real install path via winget)
shell: pwsh
run: |
$env:AIRC_DIR = "$env:USERPROFILE\.airc-src"
New-Item -ItemType Directory -Force -Path $env:AIRC_DIR | Out-Null
Copy-Item -Recurse -Force * $env:AIRC_DIR
# install.ps1 must work from default Windows PowerShell 5.1
# too; we test 5.1 path in a separate job below.
& "$env:AIRC_DIR\install.ps1"

- name: airc doctor (must report environment-clean)
shell: pwsh
run: |
$env:PATH = "$env:USERPROFILE\AppData\Local\Programs\airc;$env:PATH"
(Get-Command airc -ErrorAction SilentlyContinue) | Out-String
airc doctor
if ($LASTEXITCODE -ne 0) {
Write-Error "airc doctor failed with exit $LASTEXITCODE"
exit $LASTEXITCODE
}

clean-install-windows-ps5:
# Validates the bootstrap path under Windows PowerShell 5.1 — the
# default that ships with Windows. install.ps1 must work from 5.1
# to bootstrap pwsh itself (#91 — bootstrap-airc.ps1 fails under
# PS 5.1 because airc.ps1 has #Requires -Version 7.0). Splitting
# this into its own job means a 5.1 regression fails loudly without
# also failing the pwsh-based smoke.
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Run install.ps1 under Windows PowerShell 5.1 (real install)
shell: powershell
run: |
$env:AIRC_DIR = "$env:USERPROFILE\.airc-src-ps5"
New-Item -ItemType Directory -Force -Path $env:AIRC_DIR | Out-Null
Copy-Item -Recurse -Force * $env:AIRC_DIR
& "$env:AIRC_DIR\install.ps1"

integration-suite:
# Heavy gate: the full test/integration.sh, including scenarios that
# hit real gh-gists. Runs on canary/main pushes, NOT on PRs (rate
# limits + flaky network). When canary→main bundle PRs come up, this
# already-green status on the canary tip is the signal that cross-
# branch validation passed.
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Stage + install (real install path)
run: |
mkdir -p $HOME/.airc-src
cp -r . $HOME/.airc-src/
AIRC_DIR=$HOME/.airc-src bash install.sh

- name: Run integration suite
run: |
export PATH="$HOME/.local/bin:$PATH"
# Tests that need real gists self-skip without gh auth. The
# remaining ~85% of the suite covers the local-only scenarios
# that catch the lion's share of regressions.
bash test/integration.sh
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
.airc/
__pycache__/
*.pyc
18 changes: 6 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,15 @@

## Install

**macOS / Linux / WSL** (bash):
**Any platform** (bash — works from macOS / Linux / WSL / Windows Git Bash):

```bash
curl -fsSL https://raw.githubusercontent.com/CambrianTech/airc/main/install.sh | bash
```

**Windows** (PowerShell — works from the default Windows PowerShell 5.1; bootstraps pwsh 7 + every other prereq via winget):
This is the install command for everyone running Claude Code, Codex, Cursor, opencode, Windsurf, or openclaw — all of which use bash on every platform including Windows. On Windows, install.sh detects Git Bash, installs prereqs via winget, and self-elevates once for OpenSSH server + DefaultShell setup. You stay in your terminal — no PowerShell switch.

```powershell
iwr https://raw.githubusercontent.com/CambrianTech/airc/main/install.ps1 | iex
```
> **Native-PowerShell users (rare):** if you specifically want `airc.ps1` (the PowerShell port, not the bash one), use `iwr https://raw.githubusercontent.com/CambrianTech/airc/main/install.ps1 | iex` instead. Most users don't need this — Claude Code / Codex / etc. on Windows run in Git Bash, where `install.sh` is the right entry.

One command. Puts `airc` on your `PATH` and installs the Claude Code skills automatically. Other agents (Codex, Cursor, opencode, Windsurf, openclaw) get their integration files at [`integrations/`](integrations/).

Expand Down Expand Up @@ -120,19 +118,15 @@ This isn't a knock on the federation protocols — they solve real enterprise fe

## Install

**macOS / Linux / WSL**:
**Every platform** (macOS / Linux / WSL / Windows Git Bash):

```bash
curl -fsSL https://raw.githubusercontent.com/CambrianTech/airc/main/install.sh | bash
```

**Windows** (PowerShell):

```powershell
iwr https://raw.githubusercontent.com/CambrianTech/airc/main/install.ps1 | iex
```
Puts `airc` on your `PATH` and installs Claude Code skills automatically. Auto-installs every prereq (gh, openssl, python3, openssh-client, optional tailscale) via the platform's package manager (brew / apt / dnf / pacman / apk / winget). On Windows it self-elevates once for OpenSSH Server + DefaultShell setup; you stay in your terminal.

Puts `airc` on your `PATH` and installs Claude Code skills automatically. Both installers auto-install every prereq (gh, openssl, python3, openssh-client, optional tailscale) via the platform's package manager (brew / apt / dnf / pacman / apk / winget).
> **Native-PowerShell users:** rare, but if you specifically want the PowerShell port `airc.ps1` instead of the bash binary, use `iwr https://raw.githubusercontent.com/CambrianTech/airc/main/install.ps1 | iex`. The bash install.sh is the right entry for everyone running Claude Code / Codex / Cursor on Windows (which all default to Git Bash).

## 30-Second Setup

Expand Down
Loading
Loading