FoolDev commited on
Commit
9ca8700
·
1 Parent(s): 7766f0b

Add Makefile, GGUF_PATH override, and harden .gitignore

Browse files

Makefile: thin wrapper over scripts/*. 'make help' lists targets
(build / smoke / check / hooks / clean). All variables (QUANT, PROFILE,
TAG, GGUF_PATH, MODEL) are overridable on the command line.

scripts/build.sh: honor GGUF_PATH so users with weights already on disk
(shared model dirs, NAS mounts, an Ollama blob copied out of
~/.ollama/models/blobs) don't have to copy or symlink. Also defers the
HF-CLI requirement until a download is actually needed.

.gitignore: exclude .cache/, *.incomplete, *.lock — running 'hf download'
inside the repo creates a .cache/huggingface/ tree, and a previous
session committed an empty version of it. Belt-and-suspenders.

README + CHANGELOG updated to reflect the new flow.

Files changed (5) hide show
  1. .gitignore +7 -0
  2. CHANGELOG.md +17 -1
  3. Makefile +61 -0
  4. README.md +10 -10
  5. scripts/build.sh +30 -20
.gitignore CHANGED
@@ -10,8 +10,15 @@ venv/
10
  *.safetensors
11
  *.bin
12
 
 
 
 
 
 
 
13
  # Editor / OS
14
  .DS_Store
15
  .idea/
16
  .vscode/
17
  *.swp
 
 
10
  *.safetensors
11
  *.bin
12
 
13
+ # Build / runtime artifacts that get created if anyone runs hf download or
14
+ # scripts/build.sh from inside the repo.
15
+ .cache/
16
+ *.incomplete
17
+ *.lock
18
+
19
  # Editor / OS
20
  .DS_Store
21
  .idea/
22
  .vscode/
23
  *.swp
24
+ *~
CHANGELOG.md CHANGED
@@ -7,13 +7,29 @@ and documentation**, not the underlying base model.
7
 
8
  ## [Unreleased]
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  ### Added
11
  - `scripts/check.sh` — local lint runner: `bash -n`, optional `shellcheck`,
12
  `pyflakes`, `py_compile`, plus a guard regex for the dash/dot filename
13
  bug. Returns non-zero on failure.
14
  - `scripts/install-hooks.sh` — installs `check.sh` as a git pre-commit
15
  hook so footguns can't slip past again.
16
- - `CHANGELOG.md` (this file).
17
 
18
  ## [0.2.1] - 2026-05-02 — `82677d0`
19
 
 
7
 
8
  ## [Unreleased]
9
 
10
+ ### Added
11
+ - `Makefile` — convenience wrapper. `make help` lists targets:
12
+ `build` / `smoke` / `check` / `hooks` / `clean`. Variables
13
+ `QUANT`, `PROFILE`, `TAG`, `GGUF_PATH`, `MODEL` are overridable.
14
+
15
+ ### Changed
16
+ - `scripts/build.sh` now honors `GGUF_PATH` so users with weights already
17
+ on disk (e.g. shared model dirs, NAS mounts) don't have to download or
18
+ symlink. Also defers the HF-CLI requirement until a download is
19
+ actually needed.
20
+ - `.gitignore` now excludes `.cache/`, `*.incomplete`, and `*.lock` so
21
+ ephemeral artifacts from running `hf download` inside the repo never
22
+ get committed.
23
+
24
+ ## [0.3.0] - 2026-05-02 — `7766f0b`
25
+
26
  ### Added
27
  - `scripts/check.sh` — local lint runner: `bash -n`, optional `shellcheck`,
28
  `pyflakes`, `py_compile`, plus a guard regex for the dash/dot filename
29
  bug. Returns non-zero on failure.
30
  - `scripts/install-hooks.sh` — installs `check.sh` as a git pre-commit
31
  hook so footguns can't slip past again.
32
+ - `CHANGELOG.md`.
33
 
34
  ## [0.2.1] - 2026-05-02 — `82677d0`
35
 
Makefile ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Janus-27B convenience Makefile.
2
+ #
3
+ # All work is delegated to scripts/* — this file just gives common
4
+ # operations short, discoverable names.
5
+ #
6
+ # Variables you can override on the command line:
7
+ # QUANT GGUF quant suffix (default: Q4_K_M)
8
+ # PROFILE default | z13 (default: default)
9
+ # TAG Ollama model tag (auto: janus-27b or janus-27b-z13)
10
+ # GGUF_PATH path to existing GGUF (skip the download)
11
+ # MODEL model tag for smoke (default: $(TAG))
12
+ #
13
+ # Examples:
14
+ # make build # default profile, Q4_K_M
15
+ # make build PROFILE=z13 QUANT=Q3_K_S
16
+ # make build GGUF_PATH=~/models/Qwen3.6-27B-Q4_K_M.gguf
17
+ # make smoke
18
+ # make check
19
+ # make clean
20
+
21
+ QUANT ?= Q4_K_M
22
+ PROFILE ?= default
23
+
24
+ ifeq ($(PROFILE),z13)
25
+ TAG ?= janus-27b-z13
26
+ else
27
+ TAG ?= janus-27b
28
+ endif
29
+
30
+ MODEL ?= $(TAG)
31
+
32
+ .DEFAULT_GOAL := help
33
+
34
+ .PHONY: help build smoke check hooks clean
35
+
36
+ help: ## Show this help.
37
+ @awk 'BEGIN {FS = ":.*##"; printf "Targets:\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-12s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST)
38
+ @echo
39
+ @echo "Current settings:"
40
+ @echo " QUANT=$(QUANT) PROFILE=$(PROFILE) TAG=$(TAG)"
41
+ ifdef GGUF_PATH
42
+ @echo " GGUF_PATH=$(GGUF_PATH)"
43
+ endif
44
+
45
+ build: ## Download GGUF (if needed) and run 'ollama create'.
46
+ GGUF_PATH=$(GGUF_PATH) ./scripts/build.sh $(QUANT) $(PROFILE)
47
+
48
+ smoke: ## Verify the model is reachable and round-trips.
49
+ MODEL=$(MODEL) ./scripts/smoke_test.sh
50
+
51
+ check: ## Lint shell + python files; block dot-pattern footgun.
52
+ ./scripts/check.sh
53
+
54
+ hooks: ## Install scripts/check.sh as the git pre-commit hook.
55
+ ./scripts/install-hooks.sh
56
+
57
+ clean: ## Remove local GGUF copies and ephemeral caches in this repo.
58
+ @echo "[*] removing local GGUFs and ephemeral caches in $$PWD"
59
+ @rm -f ./Qwen3.6-27B-*.gguf
60
+ @rm -rf ./.cache __pycache__ examples/__pycache__
61
+ @echo "[+] clean"
README.md CHANGED
@@ -89,6 +89,7 @@ The 27B is **dense**: every parameter participates in every forward pass. It's s
89
  | `scripts/smoke_test.sh` | Verifies an Ollama daemon + model and runs a round-trip |
90
  | `scripts/check.sh` | Local lint: `bash -n`, `pyflakes`, `py_compile`, footgun-grep |
91
  | `scripts/install-hooks.sh` | Installs `check.sh` as a git pre-commit hook |
 
92
  | `LICENSE`, `CITATION.cff` | Apache-2.0 license and citation metadata |
93
  | `CHANGELOG.md` | Versioned tooling/docs changes |
94
  | `README.md` | This file |
@@ -113,25 +114,24 @@ If you want the safetensors for `transformers`, fetch them from [`Qwen/Qwen3.6-2
113
 
114
  ### Ollama (one-liner)
115
 
116
- `scripts/build.sh` will download the GGUF and create the Ollama model in one shot:
117
-
118
  ```bash
119
- ./scripts/build.sh # Q4_K_M, default profile -> janus-27b
120
- ./scripts/build.sh Q3_K_S z13 # Z13 profile (Modelfile.z13) -> janus-27b-z13
121
- ./scripts/build.sh Q5_K_M # higher-quality quant -> janus-27b
122
  ollama run janus-27b
123
  ```
124
 
125
- Or do it manually if you already have a GGUF on disk — edit the `FROM` line in `Modelfile` and run:
 
 
126
 
127
- ```bash
128
- ollama create janus-27b -f Modelfile && ollama run janus-27b
129
- ```
130
 
131
  Confirm everything works:
132
 
133
  ```bash
134
- ./scripts/smoke_test.sh # checks server, model, round-trip
135
  python examples/ollama_chat.py # full demo: chat, streaming, tools, OpenAI-compat
136
  ```
137
 
 
89
  | `scripts/smoke_test.sh` | Verifies an Ollama daemon + model and runs a round-trip |
90
  | `scripts/check.sh` | Local lint: `bash -n`, `pyflakes`, `py_compile`, footgun-grep |
91
  | `scripts/install-hooks.sh` | Installs `check.sh` as a git pre-commit hook |
92
+ | `Makefile` | Convenience wrapper — `make help` lists targets |
93
  | `LICENSE`, `CITATION.cff` | Apache-2.0 license and citation metadata |
94
  | `CHANGELOG.md` | Versioned tooling/docs changes |
95
  | `README.md` | This file |
 
114
 
115
  ### Ollama (one-liner)
116
 
 
 
117
  ```bash
118
+ make build # Q4_K_M, default profile -> janus-27b
119
+ make build PROFILE=z13 QUANT=Q3_K_S # Z13 profile (Modelfile.z13) -> janus-27b-z13
120
+ make build GGUF_PATH=~/models/Qwen3.6-27B-Q4_K_M.gguf # skip download
121
  ollama run janus-27b
122
  ```
123
 
124
+ Under the hood, `make build` calls `scripts/build.sh`, which downloads the
125
+ GGUF if missing (set `GGUF_PATH` to point at one you already have) and
126
+ runs `ollama create` with the matching `Modelfile`.
127
 
128
+ If you'd rather do it by hand: edit the `FROM` line in `Modelfile` and
129
+ run `ollama create janus-27b -f Modelfile && ollama run janus-27b`.
 
130
 
131
  Confirm everything works:
132
 
133
  ```bash
134
+ make smoke # checks server, model, round-trip
135
  python examples/ollama_chat.py # full demo: chat, streaming, tools, OpenAI-compat
136
  ```
137
 
scripts/build.sh CHANGED
@@ -7,7 +7,10 @@
7
  # ./scripts/build.sh Q3_K_S z13 # quant + Z13 profile (uses Modelfile.z13)
8
  # QUANT=Q6_K PROFILE=default ./scripts/build.sh
9
  #
10
- # Requires: huggingface-cli (or hf), ollama, awk, sed.
 
 
 
11
  set -euo pipefail
12
 
13
  QUANT="${1:-${QUANT:-Q4_K_M}}"
@@ -22,7 +25,9 @@ REPO_ID="${REPO_ID:-unsloth/Qwen3.6-27B-GGUF}"
22
  # UD-Q5_K_XL UD-Q6_K_XL UD-Q8_K_XL
23
  GGUF_NAME="Qwen3.6-27B-${QUANT}.gguf"
24
  ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
25
- GGUF_PATH="${ROOT}/${GGUF_NAME}"
 
 
26
 
27
  case "${PROFILE}" in
28
  default) MODELFILE="${ROOT}/Modelfile"; TAG="janus-27b" ;;
@@ -46,33 +51,38 @@ if [[ ! -f "${MODELFILE}" ]]; then
46
  echo "[!] Missing ${MODELFILE}" >&2; exit 1
47
  fi
48
 
49
- # ---- 2. Pick a HuggingFace CLI ----------------------------------------------
50
-
51
- HF=""
52
- if command -v hf >/dev/null 2>&1; then
53
- HF="hf"
54
- elif command -v huggingface-cli >/dev/null 2>&1; then
55
- HF="huggingface-cli"
56
- else
57
- echo "[!] Neither 'hf' nor 'huggingface-cli' found." >&2
58
- echo " pip install -U huggingface_hub" >&2
59
- exit 1
60
- fi
61
-
62
- # ---- 3. Download GGUF if missing --------------------------------------------
63
 
64
  if [[ -f "${GGUF_PATH}" ]]; then
65
- echo "[=] GGUF already present, skipping download."
66
  else
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  echo "[*] Downloading ${GGUF_NAME} from ${REPO_ID} ..."
 
 
68
  case "${HF}" in
69
- hf) hf download "${REPO_ID}" "${GGUF_NAME}" --local-dir "${ROOT}" ;;
70
- huggingface-cli) huggingface-cli download "${REPO_ID}" "${GGUF_NAME}" --local-dir "${ROOT}" ;;
71
  esac
72
  fi
73
 
74
  if [[ ! -f "${GGUF_PATH}" ]]; then
75
- echo "[!] Download failed: ${GGUF_PATH} not present." >&2; exit 1
 
76
  fi
77
 
78
  # ---- 4. Patch the Modelfile FROM line in a temp copy -------------------------
 
7
  # ./scripts/build.sh Q3_K_S z13 # quant + Z13 profile (uses Modelfile.z13)
8
  # QUANT=Q6_K PROFILE=default ./scripts/build.sh
9
  #
10
+ # Skip the download by pointing at a GGUF you already have:
11
+ # GGUF_PATH=/path/to/Qwen3.6-27B-Q4_K_M.gguf ./scripts/build.sh Q4_K_M
12
+ #
13
+ # Requires: huggingface-cli (or hf), ollama, awk.
14
  set -euo pipefail
15
 
16
  QUANT="${1:-${QUANT:-Q4_K_M}}"
 
25
  # UD-Q5_K_XL UD-Q6_K_XL UD-Q8_K_XL
26
  GGUF_NAME="Qwen3.6-27B-${QUANT}.gguf"
27
  ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
28
+ # GGUF_PATH defaults to ${ROOT}/${GGUF_NAME}, but can be overridden so users
29
+ # with cached weights elsewhere don't have to copy or symlink anything.
30
+ GGUF_PATH="${GGUF_PATH:-${ROOT}/${GGUF_NAME}}"
31
 
32
  case "${PROFILE}" in
33
  default) MODELFILE="${ROOT}/Modelfile"; TAG="janus-27b" ;;
 
51
  echo "[!] Missing ${MODELFILE}" >&2; exit 1
52
  fi
53
 
54
+ # ---- 2. Download GGUF if missing --------------------------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  if [[ -f "${GGUF_PATH}" ]]; then
57
+ echo "[=] GGUF already present at ${GGUF_PATH}, skipping download."
58
  else
59
+ # Need a HF CLI to fetch the file.
60
+ HF=""
61
+ if command -v hf >/dev/null 2>&1; then
62
+ HF="hf"
63
+ elif command -v huggingface-cli >/dev/null 2>&1; then
64
+ HF="huggingface-cli"
65
+ else
66
+ echo "[!] ${GGUF_PATH} not found, and neither 'hf' nor" >&2
67
+ echo " 'huggingface-cli' is installed to download it." >&2
68
+ echo " Either:" >&2
69
+ echo " pip install -U huggingface_hub" >&2
70
+ echo " or set GGUF_PATH to an existing GGUF and rerun." >&2
71
+ exit 1
72
+ fi
73
+
74
  echo "[*] Downloading ${GGUF_NAME} from ${REPO_ID} ..."
75
+ DEST_DIR="$(dirname "${GGUF_PATH}")"
76
+ mkdir -p "${DEST_DIR}"
77
  case "${HF}" in
78
+ hf) hf download "${REPO_ID}" "${GGUF_NAME}" --local-dir "${DEST_DIR}" ;;
79
+ huggingface-cli) huggingface-cli download "${REPO_ID}" "${GGUF_NAME}" --local-dir "${DEST_DIR}" ;;
80
  esac
81
  fi
82
 
83
  if [[ ! -f "${GGUF_PATH}" ]]; then
84
+ echo "[!] GGUF still not present at ${GGUF_PATH} after download attempt." >&2
85
+ exit 1
86
  fi
87
 
88
  # ---- 4. Patch the Modelfile FROM line in a temp copy -------------------------