sft-cli 0.1.0__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sft_cli-0.1.0 → sft_cli-0.2.0}/.github/workflows/ci.yml +44 -4
- sft_cli-0.2.0/.gitignore +34 -0
- sft_cli-0.2.0/AGENTS.md +92 -0
- sft_cli-0.2.0/PKG-INFO +111 -0
- sft_cli-0.2.0/README.md +80 -0
- sft_cli-0.2.0/docs/plans/2026-03-06-implementation-plan.md +1431 -0
- sft_cli-0.2.0/docs/plans/2026-03-06-sft-toolkit-design.md +863 -0
- {sft_cli-0.1.0 → sft_cli-0.2.0}/pyproject.toml +21 -1
- sft_cli-0.2.0/scripts/build_skill_reference.py +113 -0
- sft_cli-0.2.0/scripts/generate_test_models.py +306 -0
- sft_cli-0.2.0/scripts/hatch_build_hook.py +49 -0
- {sft_cli-0.1.0 → sft_cli-0.2.0}/src/sft/__init__.py +1 -1
- sft_cli-0.2.0/src/sft/browser.py +2447 -0
- sft_cli-0.2.0/src/sft/cli.py +205 -0
- sft_cli-0.2.0/src/sft/commands/__init__.py +0 -0
- sft_cli-0.2.0/src/sft/commands/cast.py +103 -0
- sft_cli-0.2.0/src/sft/commands/cat.py +90 -0
- sft_cli-0.2.0/src/sft/commands/check.py +80 -0
- sft_cli-0.2.0/src/sft/commands/convert.py +80 -0
- sft_cli-0.2.0/src/sft/commands/diff.py +208 -0
- sft_cli-0.2.0/src/sft/commands/info.py +73 -0
- sft_cli-0.2.0/src/sft/commands/lora.py +743 -0
- sft_cli-0.2.0/src/sft/commands/ls.py +117 -0
- sft_cli-0.2.0/src/sft/commands/metadata.py +96 -0
- sft_cli-0.2.0/src/sft/commands/rename.py +111 -0
- sft_cli-0.2.0/src/sft/commands/skill.py +519 -0
- sft_cli-0.2.0/src/sft/commands/slice.py +89 -0
- sft_cli-0.2.0/src/sft/commands/split.py +111 -0
- sft_cli-0.2.0/src/sft/commands/stat.py +134 -0
- sft_cli-0.2.0/src/sft/commands/strip.py +78 -0
- sft_cli-0.2.0/src/sft/commands/tree.py +120 -0
- sft_cli-0.2.0/src/sft/ops/__init__.py +0 -0
- sft_cli-0.2.0/src/sft/ops/cast.py +68 -0
- sft_cli-0.2.0/src/sft/ops/cat.py +70 -0
- sft_cli-0.2.0/src/sft/ops/check.py +88 -0
- sft_cli-0.2.0/src/sft/ops/convert.py +60 -0
- sft_cli-0.2.0/src/sft/ops/diff.py +167 -0
- sft_cli-0.2.0/src/sft/ops/info.py +73 -0
- sft_cli-0.2.0/src/sft/ops/lora/__init__.py +0 -0
- sft_cli-0.2.0/src/sft/ops/lora/add.py +131 -0
- sft_cli-0.2.0/src/sft/ops/lora/compat.py +79 -0
- sft_cli-0.2.0/src/sft/ops/lora/convert.py +286 -0
- sft_cli-0.2.0/src/sft/ops/lora/detect.py +179 -0
- sft_cli-0.2.0/src/sft/ops/lora/extract.py +115 -0
- sft_cli-0.2.0/src/sft/ops/lora/info.py +15 -0
- sft_cli-0.2.0/src/sft/ops/lora/merge.py +78 -0
- sft_cli-0.2.0/src/sft/ops/lora/resize.py +155 -0
- sft_cli-0.2.0/src/sft/ops/lora/stack.py +221 -0
- sft_cli-0.2.0/src/sft/ops/lora/svd.py +140 -0
- sft_cli-0.2.0/src/sft/ops/ls.py +48 -0
- sft_cli-0.2.0/src/sft/ops/metadata.py +44 -0
- sft_cli-0.2.0/src/sft/ops/rename.py +65 -0
- sft_cli-0.2.0/src/sft/ops/slice.py +86 -0
- sft_cli-0.2.0/src/sft/ops/split.py +128 -0
- sft_cli-0.2.0/src/sft/ops/stat.py +82 -0
- sft_cli-0.2.0/src/sft/ops/tree.py +126 -0
- sft_cli-0.2.0/src/sft/skill/REFERENCE.md +586 -0
- sft_cli-0.2.0/src/sft/skill/SKILL.md +146 -0
- sft_cli-0.2.0/src/sft/utils/__init__.py +0 -0
- sft_cli-0.2.0/src/sft/utils/dtypes.py +50 -0
- sft_cli-0.2.0/src/sft/utils/formatting.py +59 -0
- sft_cli-0.2.0/src/sft/utils/glob.py +73 -0
- sft_cli-0.2.0/src/sft/utils/linking.py +277 -0
- sft_cli-0.2.0/src/sft/utils/output.py +21 -0
- sft_cli-0.2.0/src/sft/utils/tensor_io.py +165 -0
- sft_cli-0.2.0/tests/__init__.py +0 -0
- sft_cli-0.2.0/tests/conftest.py +134 -0
- sft_cli-0.2.0/tests/test_build_hook.py +66 -0
- sft_cli-0.2.0/tests/test_cast.py +109 -0
- sft_cli-0.2.0/tests/test_cat.py +198 -0
- sft_cli-0.2.0/tests/test_check.py +44 -0
- sft_cli-0.2.0/tests/test_cli.py +102 -0
- sft_cli-0.2.0/tests/test_cli_contract.py +305 -0
- sft_cli-0.2.0/tests/test_convert.py +132 -0
- sft_cli-0.2.0/tests/test_diff.py +306 -0
- sft_cli-0.2.0/tests/test_e2e_subprocess.py +194 -0
- sft_cli-0.2.0/tests/test_info.py +59 -0
- sft_cli-0.2.0/tests/test_lora_add.py +135 -0
- sft_cli-0.2.0/tests/test_lora_compat.py +90 -0
- sft_cli-0.2.0/tests/test_lora_convert.py +250 -0
- sft_cli-0.2.0/tests/test_lora_detect.py +63 -0
- sft_cli-0.2.0/tests/test_lora_extract.py +90 -0
- sft_cli-0.2.0/tests/test_lora_info.py +42 -0
- sft_cli-0.2.0/tests/test_lora_merge.py +78 -0
- sft_cli-0.2.0/tests/test_lora_properties.py +353 -0
- sft_cli-0.2.0/tests/test_lora_resize.py +254 -0
- sft_cli-0.2.0/tests/test_lora_stack.py +389 -0
- sft_cli-0.2.0/tests/test_lora_svd.py +148 -0
- sft_cli-0.2.0/tests/test_ls.py +82 -0
- sft_cli-0.2.0/tests/test_metadata.py +126 -0
- sft_cli-0.2.0/tests/test_perf.py +74 -0
- sft_cli-0.2.0/tests/test_pipelines.py +280 -0
- sft_cli-0.2.0/tests/test_properties.py +100 -0
- sft_cli-0.2.0/tests/test_rename.py +169 -0
- sft_cli-0.2.0/tests/test_skill_install.py +299 -0
- sft_cli-0.2.0/tests/test_slice.py +105 -0
- sft_cli-0.2.0/tests/test_split.py +174 -0
- sft_cli-0.2.0/tests/test_stat.py +70 -0
- sft_cli-0.2.0/tests/test_strip.py +134 -0
- sft_cli-0.2.0/tests/test_tensor_io.py +96 -0
- sft_cli-0.2.0/tests/test_tree.py +44 -0
- sft_cli-0.2.0/tests/test_tui.py +793 -0
- sft_cli-0.2.0/tests/test_utils.py +160 -0
- sft_cli-0.2.0/uv.lock +1621 -0
- sft_cli-0.1.0/.gitignore +0 -23
- sft_cli-0.1.0/PKG-INFO +0 -115
- sft_cli-0.1.0/README.md +0 -89
- sft_cli-0.1.0/src/sft/browser.py +0 -947
- sft_cli-0.1.0/src/sft/cli.py +0 -63
- sft_cli-0.1.0/uv.lock +0 -504
- {sft_cli-0.1.0 → sft_cli-0.2.0}/.github/workflows/publish.yml +0 -0
- {sft_cli-0.1.0 → sft_cli-0.2.0}/.pre-commit-config.yaml +0 -0
- {sft_cli-0.1.0 → sft_cli-0.2.0}/.python-version +0 -0
- {sft_cli-0.1.0 → sft_cli-0.2.0}/scripts/create_test_file.py +0 -0
- {sft_cli-0.1.0 → sft_cli-0.2.0}/src/sft/index.py +0 -0
|
@@ -32,11 +32,13 @@ jobs:
|
|
|
32
32
|
run: uv run ruff format --check .
|
|
33
33
|
|
|
34
34
|
test:
|
|
35
|
-
|
|
35
|
+
name: test (py${{ matrix.python-version }} / ${{ matrix.os }})
|
|
36
|
+
runs-on: ${{ matrix.os }}
|
|
36
37
|
strategy:
|
|
37
38
|
fail-fast: false
|
|
38
39
|
matrix:
|
|
39
|
-
|
|
40
|
+
os: [ubuntu-latest, macos-latest]
|
|
41
|
+
python-version: ["3.9", "3.11", "3.12"]
|
|
40
42
|
steps:
|
|
41
43
|
- uses: actions/checkout@v4
|
|
42
44
|
|
|
@@ -47,13 +49,43 @@ jobs:
|
|
|
47
49
|
run: uv python install ${{ matrix.python-version }}
|
|
48
50
|
|
|
49
51
|
- name: Install dependencies
|
|
50
|
-
run: uv sync
|
|
52
|
+
run: uv sync --dev
|
|
51
53
|
|
|
52
54
|
- name: Verify package imports
|
|
53
55
|
run: uv run python -c "from sft.cli import app; from sft.browser import SftApp; from sft.index import TensorIndex; print('All imports successful')"
|
|
54
56
|
|
|
57
|
+
- name: Run fast test suite
|
|
58
|
+
run: uv run pytest -q
|
|
59
|
+
|
|
60
|
+
test-slow:
|
|
61
|
+
# Long-running tests (subprocess E2E, perf smoke, build-hook) only need
|
|
62
|
+
# to pass on one cell — they exercise behavior that's OS- and version-
|
|
63
|
+
# independent.
|
|
64
|
+
name: slow tests (py3.12 / ubuntu)
|
|
65
|
+
runs-on: ubuntu-latest
|
|
66
|
+
needs: test
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v4
|
|
69
|
+
|
|
70
|
+
- name: Install uv
|
|
71
|
+
uses: astral-sh/setup-uv@v4
|
|
72
|
+
|
|
73
|
+
- name: Set up Python
|
|
74
|
+
run: uv python install 3.12
|
|
75
|
+
|
|
76
|
+
- name: Install dependencies
|
|
77
|
+
run: uv sync --dev
|
|
78
|
+
|
|
79
|
+
- name: Install package (so the `sft` console script is on PATH)
|
|
80
|
+
run: uv pip install -e .
|
|
81
|
+
|
|
82
|
+
- name: Run slow tests
|
|
83
|
+
run: uv run pytest -q -m slow
|
|
84
|
+
|
|
55
85
|
build:
|
|
86
|
+
name: build wheel + smoke install
|
|
56
87
|
runs-on: ubuntu-latest
|
|
88
|
+
needs: test
|
|
57
89
|
steps:
|
|
58
90
|
- uses: actions/checkout@v4
|
|
59
91
|
|
|
@@ -61,11 +93,19 @@ jobs:
|
|
|
61
93
|
uses: astral-sh/setup-uv@v4
|
|
62
94
|
|
|
63
95
|
- name: Set up Python
|
|
64
|
-
run: uv python install 3.
|
|
96
|
+
run: uv python install 3.12
|
|
65
97
|
|
|
66
98
|
- name: Build package
|
|
67
99
|
run: uv build
|
|
68
100
|
|
|
101
|
+
- name: Smoke install + help from a clean venv
|
|
102
|
+
run: |
|
|
103
|
+
python3 -m venv /tmp/sft-smoke
|
|
104
|
+
/tmp/sft-smoke/bin/pip install --upgrade pip
|
|
105
|
+
/tmp/sft-smoke/bin/pip install dist/sft_cli-*.whl
|
|
106
|
+
/tmp/sft-smoke/bin/sft --help
|
|
107
|
+
/tmp/sft-smoke/bin/sft --version
|
|
108
|
+
|
|
69
109
|
- name: Upload build artifacts
|
|
70
110
|
uses: actions/upload-artifact@v4
|
|
71
111
|
with:
|
sft_cli-0.2.0/.gitignore
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# macOS
|
|
2
|
+
.DS_Store
|
|
3
|
+
|
|
4
|
+
# Generated demo artifacts
|
|
5
|
+
demo.gif
|
|
6
|
+
demo.tape
|
|
7
|
+
|
|
8
|
+
# AI agent documents
|
|
9
|
+
.ai/
|
|
10
|
+
|
|
11
|
+
# Python
|
|
12
|
+
__pycache__/
|
|
13
|
+
*.py[cod]
|
|
14
|
+
*.so
|
|
15
|
+
dist/
|
|
16
|
+
*.egg-info/
|
|
17
|
+
|
|
18
|
+
# Virtual environments
|
|
19
|
+
.venv/
|
|
20
|
+
|
|
21
|
+
# IDE
|
|
22
|
+
.vscode/
|
|
23
|
+
.idea/
|
|
24
|
+
|
|
25
|
+
# Testing
|
|
26
|
+
.pytest_cache/
|
|
27
|
+
.coverage
|
|
28
|
+
|
|
29
|
+
# Test files
|
|
30
|
+
*.safetensors
|
|
31
|
+
|
|
32
|
+
# Skill installer state (written by `sft skill install` into the source dir
|
|
33
|
+
# when developing locally — not source code).
|
|
34
|
+
.sft-skill-install.json
|
sft_cli-0.2.0/AGENTS.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# AGENTS.md — guidance for AI agents working on `sft-cli`
|
|
2
|
+
|
|
3
|
+
This file is read by Claude Code, Cursor, Codex CLI, and other agents to understand the repo. It is meant for agents **modifying this codebase**, not end-users of the CLI.
|
|
4
|
+
|
|
5
|
+
## What this project is
|
|
6
|
+
|
|
7
|
+
`sft-cli` is a CLI ("`sft`") for inspecting and editing `.safetensors` files. It is published on PyPI as `sft-cli` and the user-facing command is `sft`.
|
|
8
|
+
|
|
9
|
+
## Repo layout
|
|
10
|
+
|
|
11
|
+
- `src/sft/cli.py` — Typer app entry point, the auto-`browse` shim, and top-level commands (`browse`, `info`, `check`). Every other subcommand is registered by importing its module at the bottom of this file.
|
|
12
|
+
- `src/sft/commands/<name>.py` — thin CLI wrappers (Typer surface, argument parsing, formatting, `--json`). They delegate to `src/sft/ops/<name>.py`.
|
|
13
|
+
- `src/sft/ops/<name>.py` — pure business logic. No Typer, no printing; returns dataclasses. Always testable in isolation.
|
|
14
|
+
- `src/sft/utils/` — shared helpers (formatting, dtype mapping, glob filtering, tensor IO, cross-platform linking for the skill installer).
|
|
15
|
+
- `src/sft/browser.py` — the interactive Textual TUI (the `browse` command). Self-contained, do not import from other commands.
|
|
16
|
+
- `src/sft/index.py` — the `TensorIndex` / `PrefixTree` data model, parsed header-only from `.safetensors` files.
|
|
17
|
+
- `src/sft/skill/` — the agent skill that ships inside the wheel and is installed by `sft skill install`. Two files: `SKILL.md` (hand-written: trigger description, command map, cookbook of cross-command patterns) and `REFERENCE.md` (**auto-generated** — never edit by hand).
|
|
18
|
+
- `scripts/build_skill_reference.py` — regenerates `src/sft/skill/REFERENCE.md` from the live Typer CLI.
|
|
19
|
+
- `scripts/hatch_build_hook.py` — hatch build hook that runs the regenerator at wheel-build time (tolerates missing deps in isolated builds).
|
|
20
|
+
- `tests/` — pytest tests, one file per command. Shared fixtures in `tests/conftest.py`.
|
|
21
|
+
|
|
22
|
+
## Conventions
|
|
23
|
+
|
|
24
|
+
1. **`--json` everywhere on commands an agent might parse.** Every command supports `--json` and outputs a stable JSON contract. When you add a new command, add `--json` from day one and update `SKILL.md`. The pattern is:
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
if json_output:
|
|
28
|
+
typer.echo(json.dumps(data, indent=2))
|
|
29
|
+
return
|
|
30
|
+
# human-readable fallback below
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Errors raised via `--json` should also be JSON: `typer.echo(json.dumps({"error": str(e)}, indent=2))` before `raise typer.Exit(code=1)`.
|
|
34
|
+
|
|
35
|
+
2. **Separation of concerns.** A new feature `foo` means:
|
|
36
|
+
- Pure logic in `src/sft/ops/foo.py` (returns a dataclass).
|
|
37
|
+
- CLI wrapper in `src/sft/commands/foo.py` (imports `ops/foo.py`, owns flags and printing).
|
|
38
|
+
- Register by adding `import sft.commands.foo` to the bottom of `src/sft/cli.py` (the imports there look stylistically dead but they trigger `@app.command(...)` decorators — keep them sorted alphabetically).
|
|
39
|
+
- Tests in `tests/test_foo.py` (CLI tests use `typer.testing.CliRunner`).
|
|
40
|
+
|
|
41
|
+
3. **The auto-`browse` shim** in `_entry()` rewrites `sft x.safetensors` → `sft browse x.safetensors`. Do not add subcommands whose names end in `.safetensors`.
|
|
42
|
+
|
|
43
|
+
4. **`validate_safetensors(path)`** in `src/sft/cli.py` is the canonical "is this a `.safetensors` file?" check. Use it from every command that takes a `.safetensors` argument.
|
|
44
|
+
|
|
45
|
+
5. **Output paths** use the `resolve_output(output, src, suffix)` helper in `src/sft/utils/output.py` to default to `{stem}.{suffix}.safetensors`. Write commands should never overwrite the source file.
|
|
46
|
+
|
|
47
|
+
6. **Dry-run.** Every write-side command exposes `--dry-run` and the underlying op must support `dry_run=True` to return a result without touching disk.
|
|
48
|
+
|
|
49
|
+
7. **Header-only reads.** Prefer `TensorIndex.from_file(path)` (header-only, milliseconds) over loading tensor data unless you specifically need values. Header-only operations are why `sft` exists.
|
|
50
|
+
|
|
51
|
+
## Updating the agent skill
|
|
52
|
+
|
|
53
|
+
The shipped skill lives in `src/sft/skill/`:
|
|
54
|
+
|
|
55
|
+
- `SKILL.md` — hand-written: trigger description (YAML frontmatter), golden `--json` rule, command map, "when to use" guidance, and an inline cookbook of cross-command patterns and `jq` recipes.
|
|
56
|
+
- `REFERENCE.md` — **auto-generated** from Typer introspection. Regenerate with:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
python scripts/build_skill_reference.py
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This also runs as a hatch build hook during `uv build`, so the wheel always contains an up-to-date reference. The script is best-effort: if it can't import `sft` (e.g. inside an isolated build env), it leaves the committed file alone.
|
|
63
|
+
|
|
64
|
+
When you add a new command or flag, also:
|
|
65
|
+
|
|
66
|
+
- Update the command-map table in `SKILL.md` if the command is something agents should reach for.
|
|
67
|
+
- If the command enables a cross-command workflow or a useful `--json` parsing pattern that isn't obvious from the single-command help, add it to the "Cookbook" section in `SKILL.md`. Resist the urge to write per-command tutorials — `REFERENCE.md` already covers single-command usage.
|
|
68
|
+
|
|
69
|
+
## Dev commands
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
uv sync # install deps
|
|
73
|
+
uv run pytest -q # full test suite
|
|
74
|
+
uv run pytest tests/test_<command>.py -q # one file
|
|
75
|
+
uv run ruff check # lint
|
|
76
|
+
uv run ruff format # format
|
|
77
|
+
python scripts/build_skill_reference.py # regenerate skill reference
|
|
78
|
+
uv build # produce wheel + sdist (regenerates skill ref via hook)
|
|
79
|
+
uv run sft skill install --dry-run # preview a skill install locally
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Known stylistic notes
|
|
83
|
+
|
|
84
|
+
- Top-level imports in `src/sft/cli.py` use `# noqa: F401, E402` because they're after function definitions and are imported for their side effect (registering commands). Keep that pattern.
|
|
85
|
+
- We support Python ≥ 3.9. Avoid `match` statements, walrus inside comprehensions, and other newer syntax in shared code paths. Use `from __future__ import annotations` at the top of every module.
|
|
86
|
+
- The pre-commit config runs `ruff` (lint + format). Run `uv run ruff check` and `uv run ruff format` before committing.
|
|
87
|
+
|
|
88
|
+
## Out-of-scope for changes
|
|
89
|
+
|
|
90
|
+
- Do **not** add an MCP server module. The skill + reliable `--json` is the intended agent integration story.
|
|
91
|
+
- Do **not** silently rewrite `src/sft/skill/REFERENCE.md` by hand; always regenerate via the script.
|
|
92
|
+
- Do **not** invent new install locations for the skill installer without updating `AGENT_DIRS` in `src/sft/commands/skill.py` and the corresponding docs in `SKILL.md` and `README.md`.
|
sft_cli-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sft-cli
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: An interactive terminal browser for .safetensors files
|
|
5
|
+
Project-URL: Homepage, https://github.com/matanby/sft-cli
|
|
6
|
+
Project-URL: Repository, https://github.com/matanby/sft-cli
|
|
7
|
+
Author: Matan Ben-Yosef
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: browser,cli,machine-learning,safetensors,tui
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Classifier: Topic :: Utilities
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Requires-Dist: ml-dtypes>=0.3
|
|
24
|
+
Requires-Dist: numpy>=1.24
|
|
25
|
+
Requires-Dist: safetensors>=0.4
|
|
26
|
+
Requires-Dist: textual>=0.40
|
|
27
|
+
Requires-Dist: typer>=0.9
|
|
28
|
+
Provides-Extra: torch
|
|
29
|
+
Requires-Dist: torch>=2.0; extra == 'torch'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# sft
|
|
33
|
+
|
|
34
|
+
A fast, interactive terminal browser for `.safetensors` files.
|
|
35
|
+
AI-agent friendly — run `sft skill install` to teach Claude, Cursor, and Codex CLI how to use it.
|
|
36
|
+
|
|
37
|
+
<p align="center">
|
|
38
|
+
<img src="https://vhs.charm.sh/vhs-6eQ3Cv0oexkfUshZ7PmO3b.gif" alt="sft demo">
|
|
39
|
+
</p>
|
|
40
|
+
|
|
41
|
+
## Why?
|
|
42
|
+
|
|
43
|
+
If you work with ML models, you've probably found yourself wondering "what's actually in this .safetensors file?" — the layer names, shapes, dtypes, sizes. Maybe you want to check if a model has the layers you expect, compare two checkpoints, or just explore an unfamiliar architecture.
|
|
44
|
+
|
|
45
|
+
`sft` lets you do that instantly from your terminal. No Python scripts, no notebooks, no waiting for tensors to load into memory. It reads only the file header, so even multi-gigabyte models open in milliseconds.
|
|
46
|
+
|
|
47
|
+
## ⚡ Installation
|
|
48
|
+
|
|
49
|
+
The recommended way to install is via [uv](https://docs.astral.sh/uv/):
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
uv tool install sft-cli
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This makes `sft` available globally as a command.
|
|
56
|
+
|
|
57
|
+
Or install with pip:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install sft-cli
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Usage
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
sft model.safetensors
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
That's it. Navigate with arrow keys, search with `/`, quit with `q`.
|
|
70
|
+
|
|
71
|
+
## ✨ Features
|
|
72
|
+
|
|
73
|
+
- **Hierarchical browser** — Tensors grouped by namespace (e.g., `model.layers.0.attention`)
|
|
74
|
+
- **Instant startup** — Header-only parsing, works on multi-GB files
|
|
75
|
+
- **Search** — Filter tensors by name with `/`
|
|
76
|
+
- **Sort** — By name, size, or rank with `s`
|
|
77
|
+
- **Inspect** — View full tensor details with `Space`
|
|
78
|
+
- **Metadata** — See embedded file metadata with `m`
|
|
79
|
+
- **Read-only** — Never touches your model files
|
|
80
|
+
|
|
81
|
+
## ⌨️ Keybindings
|
|
82
|
+
|
|
83
|
+
| Key | Action |
|
|
84
|
+
|-----|--------|
|
|
85
|
+
| `↑`/`↓` | Navigate |
|
|
86
|
+
| `←`/`→` | Collapse/expand tree |
|
|
87
|
+
| `Tab` | Switch panels |
|
|
88
|
+
| `/` | Search |
|
|
89
|
+
| `s` | Cycle sort mode |
|
|
90
|
+
| `Space` | Tensor details |
|
|
91
|
+
| `m` | File metadata |
|
|
92
|
+
| `f` | Filter by dtype |
|
|
93
|
+
| `q` | Quit |
|
|
94
|
+
|
|
95
|
+
## Use with AI agents
|
|
96
|
+
|
|
97
|
+
`sft` ships with an installable agent skill that teaches AI coding agents (Claude Code, Cursor, Codex CLI, and anything supporting the `~/.agents/skills/` open standard) when and how to use the CLI:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
sft skill install # auto-detects installed agents
|
|
101
|
+
sft skill status # see where it's installed and how
|
|
102
|
+
sft skill uninstall # tidy up
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The default install is a symlink (or directory junction on Windows) into each agent's well-known skills directory, so the skill auto-updates whenever you upgrade `sft-cli` (`uv tool upgrade sft-cli` / `pip install -U sft-cli`). Pass `--mode copy` if you'd rather have a frozen copy.
|
|
106
|
+
|
|
107
|
+
Every command also supports `--json` for reliable parsing — agents are taught to always pass `--json` when their output will be parsed.
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
MIT
|
sft_cli-0.2.0/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# sft
|
|
2
|
+
|
|
3
|
+
A fast, interactive terminal browser for `.safetensors` files.
|
|
4
|
+
AI-agent friendly — run `sft skill install` to teach Claude, Cursor, and Codex CLI how to use it.
|
|
5
|
+
|
|
6
|
+
<p align="center">
|
|
7
|
+
<img src="https://vhs.charm.sh/vhs-6eQ3Cv0oexkfUshZ7PmO3b.gif" alt="sft demo">
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
## Why?
|
|
11
|
+
|
|
12
|
+
If you work with ML models, you've probably found yourself wondering "what's actually in this .safetensors file?" — the layer names, shapes, dtypes, sizes. Maybe you want to check if a model has the layers you expect, compare two checkpoints, or just explore an unfamiliar architecture.
|
|
13
|
+
|
|
14
|
+
`sft` lets you do that instantly from your terminal. No Python scripts, no notebooks, no waiting for tensors to load into memory. It reads only the file header, so even multi-gigabyte models open in milliseconds.
|
|
15
|
+
|
|
16
|
+
## ⚡ Installation
|
|
17
|
+
|
|
18
|
+
The recommended way to install is via [uv](https://docs.astral.sh/uv/):
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
uv tool install sft-cli
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
This makes `sft` available globally as a command.
|
|
25
|
+
|
|
26
|
+
Or install with pip:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install sft-cli
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
sft model.safetensors
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
That's it. Navigate with arrow keys, search with `/`, quit with `q`.
|
|
39
|
+
|
|
40
|
+
## ✨ Features
|
|
41
|
+
|
|
42
|
+
- **Hierarchical browser** — Tensors grouped by namespace (e.g., `model.layers.0.attention`)
|
|
43
|
+
- **Instant startup** — Header-only parsing, works on multi-GB files
|
|
44
|
+
- **Search** — Filter tensors by name with `/`
|
|
45
|
+
- **Sort** — By name, size, or rank with `s`
|
|
46
|
+
- **Inspect** — View full tensor details with `Space`
|
|
47
|
+
- **Metadata** — See embedded file metadata with `m`
|
|
48
|
+
- **Read-only** — Never touches your model files
|
|
49
|
+
|
|
50
|
+
## ⌨️ Keybindings
|
|
51
|
+
|
|
52
|
+
| Key | Action |
|
|
53
|
+
|-----|--------|
|
|
54
|
+
| `↑`/`↓` | Navigate |
|
|
55
|
+
| `←`/`→` | Collapse/expand tree |
|
|
56
|
+
| `Tab` | Switch panels |
|
|
57
|
+
| `/` | Search |
|
|
58
|
+
| `s` | Cycle sort mode |
|
|
59
|
+
| `Space` | Tensor details |
|
|
60
|
+
| `m` | File metadata |
|
|
61
|
+
| `f` | Filter by dtype |
|
|
62
|
+
| `q` | Quit |
|
|
63
|
+
|
|
64
|
+
## Use with AI agents
|
|
65
|
+
|
|
66
|
+
`sft` ships with an installable agent skill that teaches AI coding agents (Claude Code, Cursor, Codex CLI, and anything supporting the `~/.agents/skills/` open standard) when and how to use the CLI:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
sft skill install # auto-detects installed agents
|
|
70
|
+
sft skill status # see where it's installed and how
|
|
71
|
+
sft skill uninstall # tidy up
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The default install is a symlink (or directory junction on Windows) into each agent's well-known skills directory, so the skill auto-updates whenever you upgrade `sft-cli` (`uv tool upgrade sft-cli` / `pip install -U sft-cli`). Pass `--mode copy` if you'd rather have a frozen copy.
|
|
75
|
+
|
|
76
|
+
Every command also supports `--json` for reliable parsing — agents are taught to always pass `--json` when their output will be parsed.
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT
|