# Contributing to swapdex
Thanks for your interest. swapdex is a small, security-sensitive tool; the bar
for changes that touch credential handling is high.
## Building
```sh
cargo test --all
cargo clippy --all-targets -- -D warnings
cargo fmt --all -- --check
```
All three must pass. Tests run against an isolated temp `HOME` (via
`Paths::rooted`) and never touch a real login -- keep it that way: any new path
resolution must go through `Paths`, never `dirs::home_dir()` directly.
**Manual runs during development must set `SWAPDEX_ROOT`:**
```sh
export SWAPDEX_ROOT=$(mktemp -d) # every path resolves under this dir
cargo run -- status # safe: reads the empty temp root
```
Without it, `cargo run -- use x` operates on YOUR real `~/.claude` and
`~/.codex` logins. Seed fake credentials the way the E2E tests do
(`seed_codex` / `seed_claude` in `tests/switch.rs` show the exact file shapes).
## The most useful contribution: a new tool adapter
swapdex supports Claude Code, Codex, Gemini CLI, and Antigravity today.
Adding another CLI (OpenCode, Cursor, ...) means implementing the `AuthTool`
trait in `src/adapters/`:
- `capture` reads the current live login into an opaque `Snapshot`.
- `apply` writes a snapshot back atomically (use `crate::atomic::write_secret`;
for any file that mixes credentials with unrelated config, do a field-level
read-modify-write like the Claude adapter, never a whole-file overwrite).
- `identity` returns a redacted `Account` -- never hold a token in a loggable
field.
Include a capture/apply round-trip test against an isolated `Paths::rooted`.
macOS Keychain support for Claude Code shipped in 0.17-0.24 (see the Keychain
resolution contract in `src/adapters/claude.rs`); new-adapter and hardening
contributions are the most useful right now.
## Non-negotiables
- No HTTP client or any network dependency may enter the graph. CI enforces
this.
- No command or MCP tool may print a credential, and none may switch accounts
automatically. swapdex is a switcher, not a rotator.
- Do not add an `--auto`/`--next`/`--when-rate-limited` flag or a token-export
command.
By contributing you agree your work is licensed under the MIT License.
## Releasing to the installation channels
The tag workflow builds GitHub release assets. It does not publish to npm or
crates.io; a successful GitHub release alone does not update those installers.
1. Keep the Cargo version, lockfile, npm version, pinned platform versions,
changelog section, and generated man page in the release commit.
2. Run the checks above and the npm tests: `node --test 'npm/**/*.test.mjs'`.
3. Push the version tag and wait for all four GitHub binary builds to finish.
4. From `npm/`, run `node publish.mjs <version>`. This publishes the platform
packages before the main package and checks that all five resolve on npm.
5. Publish the crate with `cargo publish` and verify the registry version.
6. Install the exact npm version on the target machine, then compare
`npm ls -g --depth=0 @youdie006/swapdex` with `swapdex --version` and the
executable found by `command -v swapdex`. Running proxies keep their old
executable until restarted; verify their version markers after applying
the update.
A failed publication remains an incomplete release. Do not reuse an already
published version or replace an old tag to repair a missing channel.