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.
Files changed (115) hide show
  1. {sft_cli-0.1.0 → sft_cli-0.2.0}/.github/workflows/ci.yml +44 -4
  2. sft_cli-0.2.0/.gitignore +34 -0
  3. sft_cli-0.2.0/AGENTS.md +92 -0
  4. sft_cli-0.2.0/PKG-INFO +111 -0
  5. sft_cli-0.2.0/README.md +80 -0
  6. sft_cli-0.2.0/docs/plans/2026-03-06-implementation-plan.md +1431 -0
  7. sft_cli-0.2.0/docs/plans/2026-03-06-sft-toolkit-design.md +863 -0
  8. {sft_cli-0.1.0 → sft_cli-0.2.0}/pyproject.toml +21 -1
  9. sft_cli-0.2.0/scripts/build_skill_reference.py +113 -0
  10. sft_cli-0.2.0/scripts/generate_test_models.py +306 -0
  11. sft_cli-0.2.0/scripts/hatch_build_hook.py +49 -0
  12. {sft_cli-0.1.0 → sft_cli-0.2.0}/src/sft/__init__.py +1 -1
  13. sft_cli-0.2.0/src/sft/browser.py +2447 -0
  14. sft_cli-0.2.0/src/sft/cli.py +205 -0
  15. sft_cli-0.2.0/src/sft/commands/__init__.py +0 -0
  16. sft_cli-0.2.0/src/sft/commands/cast.py +103 -0
  17. sft_cli-0.2.0/src/sft/commands/cat.py +90 -0
  18. sft_cli-0.2.0/src/sft/commands/check.py +80 -0
  19. sft_cli-0.2.0/src/sft/commands/convert.py +80 -0
  20. sft_cli-0.2.0/src/sft/commands/diff.py +208 -0
  21. sft_cli-0.2.0/src/sft/commands/info.py +73 -0
  22. sft_cli-0.2.0/src/sft/commands/lora.py +743 -0
  23. sft_cli-0.2.0/src/sft/commands/ls.py +117 -0
  24. sft_cli-0.2.0/src/sft/commands/metadata.py +96 -0
  25. sft_cli-0.2.0/src/sft/commands/rename.py +111 -0
  26. sft_cli-0.2.0/src/sft/commands/skill.py +519 -0
  27. sft_cli-0.2.0/src/sft/commands/slice.py +89 -0
  28. sft_cli-0.2.0/src/sft/commands/split.py +111 -0
  29. sft_cli-0.2.0/src/sft/commands/stat.py +134 -0
  30. sft_cli-0.2.0/src/sft/commands/strip.py +78 -0
  31. sft_cli-0.2.0/src/sft/commands/tree.py +120 -0
  32. sft_cli-0.2.0/src/sft/ops/__init__.py +0 -0
  33. sft_cli-0.2.0/src/sft/ops/cast.py +68 -0
  34. sft_cli-0.2.0/src/sft/ops/cat.py +70 -0
  35. sft_cli-0.2.0/src/sft/ops/check.py +88 -0
  36. sft_cli-0.2.0/src/sft/ops/convert.py +60 -0
  37. sft_cli-0.2.0/src/sft/ops/diff.py +167 -0
  38. sft_cli-0.2.0/src/sft/ops/info.py +73 -0
  39. sft_cli-0.2.0/src/sft/ops/lora/__init__.py +0 -0
  40. sft_cli-0.2.0/src/sft/ops/lora/add.py +131 -0
  41. sft_cli-0.2.0/src/sft/ops/lora/compat.py +79 -0
  42. sft_cli-0.2.0/src/sft/ops/lora/convert.py +286 -0
  43. sft_cli-0.2.0/src/sft/ops/lora/detect.py +179 -0
  44. sft_cli-0.2.0/src/sft/ops/lora/extract.py +115 -0
  45. sft_cli-0.2.0/src/sft/ops/lora/info.py +15 -0
  46. sft_cli-0.2.0/src/sft/ops/lora/merge.py +78 -0
  47. sft_cli-0.2.0/src/sft/ops/lora/resize.py +155 -0
  48. sft_cli-0.2.0/src/sft/ops/lora/stack.py +221 -0
  49. sft_cli-0.2.0/src/sft/ops/lora/svd.py +140 -0
  50. sft_cli-0.2.0/src/sft/ops/ls.py +48 -0
  51. sft_cli-0.2.0/src/sft/ops/metadata.py +44 -0
  52. sft_cli-0.2.0/src/sft/ops/rename.py +65 -0
  53. sft_cli-0.2.0/src/sft/ops/slice.py +86 -0
  54. sft_cli-0.2.0/src/sft/ops/split.py +128 -0
  55. sft_cli-0.2.0/src/sft/ops/stat.py +82 -0
  56. sft_cli-0.2.0/src/sft/ops/tree.py +126 -0
  57. sft_cli-0.2.0/src/sft/skill/REFERENCE.md +586 -0
  58. sft_cli-0.2.0/src/sft/skill/SKILL.md +146 -0
  59. sft_cli-0.2.0/src/sft/utils/__init__.py +0 -0
  60. sft_cli-0.2.0/src/sft/utils/dtypes.py +50 -0
  61. sft_cli-0.2.0/src/sft/utils/formatting.py +59 -0
  62. sft_cli-0.2.0/src/sft/utils/glob.py +73 -0
  63. sft_cli-0.2.0/src/sft/utils/linking.py +277 -0
  64. sft_cli-0.2.0/src/sft/utils/output.py +21 -0
  65. sft_cli-0.2.0/src/sft/utils/tensor_io.py +165 -0
  66. sft_cli-0.2.0/tests/__init__.py +0 -0
  67. sft_cli-0.2.0/tests/conftest.py +134 -0
  68. sft_cli-0.2.0/tests/test_build_hook.py +66 -0
  69. sft_cli-0.2.0/tests/test_cast.py +109 -0
  70. sft_cli-0.2.0/tests/test_cat.py +198 -0
  71. sft_cli-0.2.0/tests/test_check.py +44 -0
  72. sft_cli-0.2.0/tests/test_cli.py +102 -0
  73. sft_cli-0.2.0/tests/test_cli_contract.py +305 -0
  74. sft_cli-0.2.0/tests/test_convert.py +132 -0
  75. sft_cli-0.2.0/tests/test_diff.py +306 -0
  76. sft_cli-0.2.0/tests/test_e2e_subprocess.py +194 -0
  77. sft_cli-0.2.0/tests/test_info.py +59 -0
  78. sft_cli-0.2.0/tests/test_lora_add.py +135 -0
  79. sft_cli-0.2.0/tests/test_lora_compat.py +90 -0
  80. sft_cli-0.2.0/tests/test_lora_convert.py +250 -0
  81. sft_cli-0.2.0/tests/test_lora_detect.py +63 -0
  82. sft_cli-0.2.0/tests/test_lora_extract.py +90 -0
  83. sft_cli-0.2.0/tests/test_lora_info.py +42 -0
  84. sft_cli-0.2.0/tests/test_lora_merge.py +78 -0
  85. sft_cli-0.2.0/tests/test_lora_properties.py +353 -0
  86. sft_cli-0.2.0/tests/test_lora_resize.py +254 -0
  87. sft_cli-0.2.0/tests/test_lora_stack.py +389 -0
  88. sft_cli-0.2.0/tests/test_lora_svd.py +148 -0
  89. sft_cli-0.2.0/tests/test_ls.py +82 -0
  90. sft_cli-0.2.0/tests/test_metadata.py +126 -0
  91. sft_cli-0.2.0/tests/test_perf.py +74 -0
  92. sft_cli-0.2.0/tests/test_pipelines.py +280 -0
  93. sft_cli-0.2.0/tests/test_properties.py +100 -0
  94. sft_cli-0.2.0/tests/test_rename.py +169 -0
  95. sft_cli-0.2.0/tests/test_skill_install.py +299 -0
  96. sft_cli-0.2.0/tests/test_slice.py +105 -0
  97. sft_cli-0.2.0/tests/test_split.py +174 -0
  98. sft_cli-0.2.0/tests/test_stat.py +70 -0
  99. sft_cli-0.2.0/tests/test_strip.py +134 -0
  100. sft_cli-0.2.0/tests/test_tensor_io.py +96 -0
  101. sft_cli-0.2.0/tests/test_tree.py +44 -0
  102. sft_cli-0.2.0/tests/test_tui.py +793 -0
  103. sft_cli-0.2.0/tests/test_utils.py +160 -0
  104. sft_cli-0.2.0/uv.lock +1621 -0
  105. sft_cli-0.1.0/.gitignore +0 -23
  106. sft_cli-0.1.0/PKG-INFO +0 -115
  107. sft_cli-0.1.0/README.md +0 -89
  108. sft_cli-0.1.0/src/sft/browser.py +0 -947
  109. sft_cli-0.1.0/src/sft/cli.py +0 -63
  110. sft_cli-0.1.0/uv.lock +0 -504
  111. {sft_cli-0.1.0 → sft_cli-0.2.0}/.github/workflows/publish.yml +0 -0
  112. {sft_cli-0.1.0 → sft_cli-0.2.0}/.pre-commit-config.yaml +0 -0
  113. {sft_cli-0.1.0 → sft_cli-0.2.0}/.python-version +0 -0
  114. {sft_cli-0.1.0 → sft_cli-0.2.0}/scripts/create_test_file.py +0 -0
  115. {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
- runs-on: ubuntu-latest
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
- python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
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.14
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:
@@ -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
@@ -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
@@ -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