Thanks for considering a contribution to ptykit. This guide covers the dev setup, conventions, and the submission process.
- Bun v1.2+ (used for dev, tests, and CI).
bun-ptyis the tested PTY backend and runs under Bun. - Node 18+ if you want to exercise the experimental
node-ptypath.
ptykit ships as a TypeScript ESM library running on Node 18+ and Bun, with a
browser client entry. Use bun for all package management and scripts.
git clone https://github.com/YOUR_USERNAME/ptykit.git
cd ptykit
git remote add upstream https://github.com/myrialabs/ptykit.git
bun install
bun run typecheck && bun run lint && bun run test && bun run buildAll of these should pass on a fresh clone.
git checkout main && git pull upstream main
git checkout -b feature/your-feature
# develop & verify:
bun run typecheck && bun run lint && bun run test && bun run build
git commit -m "feat(server): enforce anti-hijack on attach"
git push origin feature/your-feature # then open a PR targeting mainNon-negotiable — a PR that breaks one needs explicit discussion first:
- WebSocket only. No SSE, no
transportoption in the public API. - Cross-runtime core.
src/must run on Node 18+ and Bun. The PTY backend is chosen by runtime auto-detect (bun-ptyon Bun,node-ptyon Node) via dynamic import; gateBun.*/node:*behind feature checks. - bun-pty is the tested path; node-pty is experimental until the scale and auto-detect benchmarks gate it. Don't quietly promote it — keep the type/docs honest.
- Persist output to the headless terminal first, even with zero listeners, and reattach via serialized replay (not raw byte history). Clear old listeners before attaching new ones.
- Collaborative by default. Output broadcasts to a room; the client filters
by
sessionId. N clients ↔ 1 session must keep working. - Quiet core. The library never writes to stdout/stderr on its own; diagnostics go through an injectable logger, off by default.
- Public API changes are documented. Update
README.mdand the relevantdocs/*.mdin the same PR.
- TypeScript, strict mode.
constby default;letonly when reassigned. - ESM with explicit
.jsimport specifiers (required byNodeNext). - Tabs, single quotes, semicolons. No Prettier — manual consistency.
- Naming:
camelCasevalues,PascalCasetypes/classes,UPPER_SNAKE_CASEconstants,kebab-casefiles. anyis acceptable only at the runtime boundary (Bun globals, dynamically importedbun-pty/node-pty, xterm addon shapes, framework payloads).
Add a *.test.ts next to the source using bun:test for any non-trivial logic
where a regression would be silent — idempotent create, seq dedup, env
hygiene, kill semantics, serialize-replay correctness, authorize allow/deny,
room fan-out, reconnect/heal, fit debounce.
bun test src/core/session.test.ts # single file
bun test # full suiteAll repository-facing text — branch names, commit messages, PR titles and descriptions, PR comments — must be in English.
<type>/<description> — lowercase, kebab-case, exactly one /.
Types: feature/, fix/, docs/, chore/.
<type>(<scope>): <subject> — imperative, lowercase, no period, ≤72 chars.
Types: feat, fix, docs, chore, release.
Common scopes: core, backend, server, client, svelte, bench,
readme, examples.
feat(core): idempotent createSession reuses by id
fix(client): heal-reconnect on open-but-dead socket
docs(server): document the authorize hook contract
-
bun run typecheckpasses -
bun run lintpasses -
bun run testpasses -
bun run buildemitsdist/cleanly - Public API change reflected in
README.md+docs/
## Summary
What this PR does, in a sentence or two.
## Why
The motivation — bug it fixes, behavior it changes.
## Changes
- concrete bullet list
## Notes (optional)
Trade-offs, follow-ups.Add ## Breaking changes with a migration note whenever the public API changes.
bun run typecheck # tsc --noEmit
bun run lint # eslint
bun run test # bun:test
bun run build # emit dist/