# Agent & contributor guide This orients an AI agent or a new contributor working in this repo. `CLAUDE.md` is a symlink to this file, so any assistant that reads either gets the same guidance. ## What envferry is A zero-dependency TypeScript CLI that moves `.env` files between machines over an end-to-end encrypted channel. See [README.md](README.md) for usage and [docs/](docs/) for the threat model and architecture decisions. ## Repo map | Path | What lives here | | --- | --- | | `src/env/` | `.env` parsing, masking, and comment-preserving merge | | `src/files/` | safe receive-target planning (path-traversal defenses) | | `src/transport/` | the `offer`/`accept` boundary + payload types, and the local, direct (TLS-PSK), and relay adapters; `psk.ts` holds the shared crypto config | | `src/cli.ts` | command dispatch (`run()`) | | `src/bin/` | the shebang entry point | | `test/` | Node's built-in runner; CLI tests spawn the built `dist/` artifact | | `docs/` | `threat-model`, `operating-a-relay`, and `decisions/` (ADRs) | ## Commands ```sh npm run check # typecheck + build + test + smoke + pack — the gate CI runs npm run typecheck # tsc, no emit (src + tests) npm run build # emit dist/ npm test # Node test runner via tsx (a pretest build produces dist/) ``` Node 20+ required. Tests run the TypeScript sources via `tsx`; the CLI tests spawn the compiled `dist/bin/envferry.js` so they exercise exactly what ships. ## Guardrails (non-negotiable) - **Never invent cryptographic protocols.** Wrap Node's built-in TLS — see [ADR 0002](docs/decisions/0002-tls-psk-transports.md). - **No runtime dependencies.** Dev-only tooling is fine; nothing ships in the published dependency graph. - **Never print secret values** in output, logs, errors, or tests — mask them. - **Received filenames are untrusted** — keep the path-traversal and `.env`-only checks in `src/files`. - Keep the transport boundary narrow; add new transports behind `offer`/`accept`. ## Commits Follow Conventional Commits with a scope and a bulleted body that explains *why*, per [.claude/skills/semantic-commit](.claude/skills/semantic-commit/SKILL.md). Imperative subject ≤ 72 chars, no trailing period; one logical unit per commit; each commit should leave `npm run check` green. **Never** add an AI co-author or "generated by" trailer. Scopes: `env`, `files`, `transport`, `cli`, `tests`, `docs`, `ci`, `build`, `chore`. ## When you change a transport Name the protocol/library, its maintenance status, and the security evidence in the PR. Update [docs/threat-model.md](docs/threat-model.md) and add an ADR under `docs/decisions/` for a material design change.