trunk
Branches trunk
1 Branches 0 Tags
Go to file T
Code
.determinism Add determinism golden index
.github Raise all coverage gates to 100%
docs Add LSP cookbook entries for Zed, Helix, Neovim
docs-internal docs: add contributor testing guide
scripts Pre-commit hook: refuse new sprint/audit IDs in src/dlm/
src Fix version lookup to use renamed package name
tests Test scaffold: add requires_acceptance to fake resolved spec
vendor Bump dlm-lsp to 2aef89a (version-pair logging)
.editorconfig chore: add editorconfig
.gitignore chore(gitignore): untrack .claude/ + AGENTS.md (editor artifacts)
.gitmodules Add dlm-lsp and dlm-vsc as submodules
.pre-commit-config.yaml Pre-commit hook: refuse new sprint/audit IDs in src/dlm/
.python-version chore: scaffold pyproject, pin python 3.11, lock deps
CHANGELOG.md README + CHANGELOG: dlm export --emit-sway-json (S26 X1-P6)
CONTRIBUTING.md Update CONTRIBUTING with PyPI publish info
LICENSE chore: add MIT license
README.md Merge remote-tracking branch 'origin/trunk' into sprint/43-dlm-synth
mkdocs.yml Document synth workflows
pyproject.toml Merge remote-tracking branch 'origin/trunk' into sprint/43-dlm-synth
sway @ 98ad941 sway: convert in-tree subproject to git submodule pointing at tenseleyFlow/sway
uv.lock chore(deps): record soxr in uv.lock

Contributing

Hey — glad you're here. DLM is a small, opinionated project, and patches that fit the project's shape are very welcome. No sign-up, no CLA, just open an issue if the change is non-trivial and a PR when you're ready.

Getting set up

You'll need Python 3.11+ and uv.

git clone https://github.com/tenseleyFlow/DocumentLanguageModel.git
cd DocumentLanguageModel
uv sync --all-extras --dev
uv run dlm --help

The four checks CI runs — run them locally before pushing:

uv run ruff check .
uv run ruff format --check .
uv run mypy src/dlm
uv run pytest

If you've only touched one module, you can run that module's tests directly (uv run pytest tests/unit/pack -q, etc.). The full suite takes around eight seconds.

mypy --strict is non-negotiable — if you need to loosen a type, please fix the type at its source instead.

Pre-commit hooks

Install once per clone to catch ruff / mypy / non-slow-pytest failures before they reach CI:

uv run pre-commit install

The config lives at .pre-commit-config.yaml. The local hook runs pytest -m "not slow and not gpu and not online", so it's ~8 seconds on a warm cache.

Testing conventions (markers, fixtures, the tiny-model fixture, golden outputs) are documented separately at docs-internal/README-testing.md.

Coverage

We keep each shipped module above 95% line coverage; CI enforces it. When you add a new module, add a matching gate in .github/workflows/ci.yml next to the existing ones. When you add a branch that's hard to exercise in unit tests — a real-GPU path, a subprocess that needs a full HF model — mark it # pragma: no cover with a short reason, and write a slow-marked integration test for it.

Commits

I care about commits being readable later — not because there's a style police, but because git log is the one place future-you reads history when something breaks.

  • One commit per logical change. A new source file plus its tests is usually one commit. Unrelated fixes go in separate commits.
  • Imperative subject line, under ~72 chars: feat(export): emit explicit Go template in Modelfile, not Updated the export module to emit the template.
  • If the why needs a paragraph, put it in the commit body. If it doesn't, one line is fine.
  • Stage files by name (git add path/to/file.py). git add -A picks up stray files we don't want in the repo.
  • No coauthor trailers. No --no-verify. If a pre-commit hook fails, fix what it's telling you about.

Pull requests

  • Link the issue or discussion your change resolves, if there is one.
  • If your change could alter training output under a fixed seed, call it out: "this breaks the determinism golden, here's the regeneration path." Better to know up front than discover it in a retrain.
  • For larger cross-cutting changes (a new dependency, a new on-disk format, anything that touches the manifest schema), open an issue first so we can nail down the design before you write the code.

Scope

DLM has a clear story — edit a document, train a LoRA, export to Ollama, do it locally, don't forget on retrain. Contributions that fit that story are the easy ones to land. Things that add scope (new training paradigms, cloud integrations, alternate inference backends) are worth discussing in an issue first; sometimes the answer is "yes, but later," and it saves you from writing code that won't merge.

A few things we actively don't want:

  • Silent-failure surfaces. If a preflight can't verify something, it refuses rather than warns.
  • Backwards-compat shims for code that hasn't shipped yet. If a v1 hasn't gone out the door, you can rename a function without a deprecation wrapper.
  • Telemetry or network calls outside of model download. Ever.

Releasing

Tag-driven. Pushing v* triggers .github/workflows/release.yml, which runs the full CI gate, builds a "fat" source tarball (includes vendor/llama.cpp/ so the Homebrew formula can drop the convert scripts into libexec without cloning submodules), and creates a GitHub release with the tarball + computed sha256.

Docs are built strict in CI but not hosted — read them in-repo or in the brew-installed tarball. Hosting (GitHub Pages or a custom subdomain) is a separate change, deferred post-v0.9.0.

We publish to PyPI as document-language-model. The PYPI_TOKEN secret in GitHub Actions handles automated releases via .github/workflows/release.yml. We also maintain a Homebrew tap at tenseleyFlow/homebrew-tap.

Conservative versioning

Stay below v1.0.0 until a human has trained + exported + ollama run'd an adapter end-to-end. That's the only contract v1.0 actually owes users. Current target: v0.9.0 for the first tagged release.

Pre-flight (run locally before tagging)

uv run ruff check .
uv run ruff format --check .
uv run mypy src/dlm
uv run pytest
uv sync --group docs
uv run mkdocs build --strict

Bump the version in pyproject.toml, move ## [Unreleased] entries under a new ## [X.Y.Z] heading in CHANGELOG.md, and land both in one commit.

Tagging

git tag v0.9.0
git push origin v0.9.0

release.yml classifies the tag via packaging.version.Version.is_prerelease:

  • Prerelease (v0.9.0rc1, v0.9.0a1, v0.9.0-rc1): GitHub release gets the prerelease flag so it doesn't show as "latest."
  • Release (v0.9.0, v0.9.1): standard GitHub release.

Bumping the Homebrew formula

After the release workflow finishes, it prints the fat-tarball sha256 in the release notes. Bump Formula/dlm.rb in the tap:

url "https://github.com/tenseleyFlow/DocumentLanguageModel/releases/download/v0.9.0/dlm-v0.9.0.tar.gz"
sha256 "<copy from release notes>"

Then:

cd ~/path/to/homebrew-tap
brew install --build-from-source ./Formula/dlm.rb   # local smoke
brew test ./Formula/dlm.rb                          # runs the `test do` block
git commit -am "dlm: bump to v0.9.0"
git push

Rollback

Homebrew rollback is straightforward: delete the bad GitHub release (or mark it draft), revert the formula bump in the tap. Users who already installed the bad version can brew uninstall dlm && brew install dlm to pick up the revert.

Thanks again — reach out in issues if anything's unclear.

-mfw