State
`airc` (bash) is at canary HEAD with all the recent IRC verb work, sticky /part, cross-scope whois, etc.
`airc.ps1` was last touched at #114 (3f812af, "fix(tailscale): just run `tailscale up` synchronously"). Since then, the bash port has shipped:
| PR |
What |
Mirrored in airc.ps1? |
| #115 |
cold-host split-brain race-loser detection |
NO |
| #116 |
three resume bugs |
NO |
| #117 |
dead-monitor send check |
NO |
| #118 |
stale-gist 404 self-heal |
NO |
| #120 |
resume success banner |
NO |
| #122 |
default-on #general sidecar (multi-room) |
NO |
| #123 |
--room flag (cross-room send) |
NO |
| #124 |
peers cross-scope aggregation |
NO |
| #125 |
part keeps sidecar |
NO |
| #129 |
platform adapters extraction |
NO |
| #131 |
always-discover (delete resume code) |
NO |
| #135 |
whois cross-scope |
NO |
| #138 |
sticky /part with parted_rooms |
NO |
| #139 |
airc away/back + IRC verb coverage |
NO |
| #150 |
_primary_scope_for empty-prefix guard |
NO |
A Windows user on the current main (post-#144 promotion) gets a substantively different airc than a Mac user. Same surface area but ~half the implementation.
Why this matters
Joel's CLAUDE.md (`Native-truth, thin-SDK-per-language architecture`):
The performant native layer is the truth. Higher-level languages get thin SDKs that wrap it idiomatically — they don't reimplement, they don't carry their own version of the truth, and they don't shortcut around the native layer "for ease."
airc currently violates this. There's no native truth — there are TWO partial truths in different shells, and they drift.
Joel 2026-04-27: "look for ways to keep these consistent, permanently."
Proposed direction
Python truth-layer. Both `airc` (bash) and `airc.ps1` (powershell) become thin dispatchers that exec a Python core for business logic. Python is already a hard prereq (the bash script invokes `python3` dozens of times in heredocs), so adoption cost is zero — we just promote the embedded heredocs to proper modules.
What stays in shell:
- Process management (spawn, kill, signal handling)
- Port binding (only because Python's socket module cleanup-on-exit is fussy under SIGTERM)
- SSH command construction (shell-out is the natural call shape)
- arg parsing (each shell has its own idioms; thin)
What moves to Python:
What stays per-shell:
- `airc.ps1` arg parsing + dispatch
- `airc` arg parsing + dispatch
- Platform adapters that are GENUINELY platform-specific (Windows Task Scheduler vs systemd vs launchd — these can't be Python-unified because the OS-level service registration is fundamentally different)
Migration strategy
Don't rewrite. Adopt incrementally:
- Pick ONE feature with high duplication risk (e.g. parted_rooms — read/write/clear).
- Implement in `lib/state.py` as a CLI: `python3 -m lib.state record-parted general`.
- Have `airc` shell out to it; have `airc.ps1` shell out to the same thing.
- Verify both work; ship.
- Repeat for the next feature.
Each migration ships with cross-port tests (drive both `airc` and `airc.ps1` through the same scenario, compare output) so drift becomes mechanical to catch.
Risk
- Python startup overhead (~50-100ms cold start) per shell-out. Acceptable for non-hot-path commands; might be noticeable for frequent ones (cmd_send, monitor formatter). Mitigation: keep hot-path logic in shell where the latency matters, move only the cold-path business logic.
Out of scope
This is the architectural piece. Concrete migrations land as separate issues per feature.
State
`airc` (bash) is at canary HEAD with all the recent IRC verb work, sticky /part, cross-scope whois, etc.
`airc.ps1` was last touched at #114 (3f812af, "fix(tailscale): just run `tailscale up` synchronously"). Since then, the bash port has shipped:
A Windows user on the current main (post-#144 promotion) gets a substantively different airc than a Mac user. Same surface area but ~half the implementation.
Why this matters
Joel's CLAUDE.md (`Native-truth, thin-SDK-per-language architecture`):
airc currently violates this. There's no native truth — there are TWO partial truths in different shells, and they drift.
Joel 2026-04-27: "look for ways to keep these consistent, permanently."
Proposed direction
Python truth-layer. Both `airc` (bash) and `airc.ps1` (powershell) become thin dispatchers that exec a Python core for business logic. Python is already a hard prereq (the bash script invokes `python3` dozens of times in heredocs), so adoption cost is zero — we just promote the embedded heredocs to proper modules.
What stays in shell:
What moves to Python:
What stays per-shell:
Migration strategy
Don't rewrite. Adopt incrementally:
Each migration ships with cross-port tests (drive both `airc` and `airc.ps1` through the same scenario, compare output) so drift becomes mechanical to catch.
Risk
Out of scope
This is the architectural piece. Concrete migrations land as separate issues per feature.