Development¶
Setup¶
This installs all runtime and dev dependencies (pytest, ruff, ty, etc.) into .venv/.
Verify the install:
Or activate the environment:
Running checks¶
make checks # ruff lint + ty type-check + pytest
make test # tests only
make ruff # lint only
make ty # type-check only
Project structure¶
src/exist_shell/
main.py # Typer app, global callback, subcommand registration
client.py # ExistClient — thin httpx wrapper over the eXist REST API
completions.py # Dynamic shell completion (hits the server at tab time)
config.py # Config model and ~/.config/exsh/config.toml I/O
models.py # Pydantic models for REST responses
exceptions.py # ExistError hierarchy
cache.py # Completion cache helpers
utils.py # Shared utilities (MIME guessing, error handling, path parsing)
commands/ # One module per subcommand
cat.py
collection.py
cp.py
edit.py
ls.py
mkdir.py
put.py
rm.py
server.py
sync.py
Conventions¶
- Python 3.11+ — use builtin generics (
list[str],str | None) instead oftyping. - Every function parameter and return type must be annotated.
- Every public module, class, and method must have a Google-style docstring.
- All REST calls go through
ExistClient. Commands receive a client viatyper.Context.objor instantiate one directly. - Use
typer.Option(...)with direct assignment; avoidAnnotatedunless the option is reused across commands.
Adding a new command¶
- Create
src/exist_shell/commands/<name>.pywith a function named after the command. - Register it in
main.pyviaapp.add_typer()or@app.command(). - Add unit tests under
tests/. - Update the command table in
docs/commands.md.
Branching and PRs¶
All changes must go through a pull request — never commit directly to main.
git checkout -b feature/<short-description>- Make changes and commit with a signed commit (
git commit -S). gh pr create- CI must pass (tests, ruff, ty, e2e) before merging.