bash-classify 0.1.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 (169) hide show
  1. bash_classify-0.1.0/.claude/rules/command-database.md +13 -0
  2. bash_classify-0.1.0/.claude-plugin/marketplace.json +13 -0
  3. bash_classify-0.1.0/.editorconfig +21 -0
  4. bash_classify-0.1.0/.github/workflows/ci.yml +62 -0
  5. bash_classify-0.1.0/.github/workflows/publish.yml +44 -0
  6. bash_classify-0.1.0/.gitignore +30 -0
  7. bash_classify-0.1.0/.python-version +1 -0
  8. bash_classify-0.1.0/CLAUDE.md +2 -0
  9. bash_classify-0.1.0/LICENSE +21 -0
  10. bash_classify-0.1.0/PKG-INFO +147 -0
  11. bash_classify-0.1.0/README.md +118 -0
  12. bash_classify-0.1.0/SPEC.md +893 -0
  13. bash_classify-0.1.0/coding-agent-plugins/claude-code/.claude-plugin/plugin.json +11 -0
  14. bash_classify-0.1.0/coding-agent-plugins/claude-code/hooks/classify-bash.sh +44 -0
  15. bash_classify-0.1.0/coding-agent-plugins/claude-code/hooks/hooks.json +18 -0
  16. bash_classify-0.1.0/docs/classification-guidance.md +379 -0
  17. bash_classify-0.1.0/pyproject.toml +56 -0
  18. bash_classify-0.1.0/ruff.toml +6 -0
  19. bash_classify-0.1.0/schemas/command.schema.json +144 -0
  20. bash_classify-0.1.0/src/bash_classify/__init__.py +14 -0
  21. bash_classify-0.1.0/src/bash_classify/__main__.py +3 -0
  22. bash_classify-0.1.0/src/bash_classify/classifier.py +244 -0
  23. bash_classify-0.1.0/src/bash_classify/cli.py +110 -0
  24. bash_classify-0.1.0/src/bash_classify/commands/apt.yaml +23 -0
  25. bash_classify-0.1.0/src/bash_classify/commands/awk.yaml +5 -0
  26. bash_classify-0.1.0/src/bash_classify/commands/basename.yaml +5 -0
  27. bash_classify-0.1.0/src/bash_classify/commands/bash.yaml +18 -0
  28. bash_classify-0.1.0/src/bash_classify/commands/brew.yaml +25 -0
  29. bash_classify-0.1.0/src/bash_classify/commands/builtin.yaml +6 -0
  30. bash_classify-0.1.0/src/bash_classify/commands/cargo.yaml +29 -0
  31. bash_classify-0.1.0/src/bash_classify/commands/cat.yaml +5 -0
  32. bash_classify-0.1.0/src/bash_classify/commands/chgrp.yaml +8 -0
  33. bash_classify-0.1.0/src/bash_classify/commands/chmod.yaml +8 -0
  34. bash_classify-0.1.0/src/bash_classify/commands/chown.yaml +8 -0
  35. bash_classify-0.1.0/src/bash_classify/commands/column.yaml +5 -0
  36. bash_classify-0.1.0/src/bash_classify/commands/comm.yaml +5 -0
  37. bash_classify-0.1.0/src/bash_classify/commands/command.yaml +10 -0
  38. bash_classify-0.1.0/src/bash_classify/commands/cp.yaml +5 -0
  39. bash_classify-0.1.0/src/bash_classify/commands/curl.yaml +28 -0
  40. bash_classify-0.1.0/src/bash_classify/commands/cut.yaml +5 -0
  41. bash_classify-0.1.0/src/bash_classify/commands/date.yaml +8 -0
  42. bash_classify-0.1.0/src/bash_classify/commands/df.yaml +5 -0
  43. bash_classify-0.1.0/src/bash_classify/commands/diff.yaml +5 -0
  44. bash_classify-0.1.0/src/bash_classify/commands/dig.yaml +5 -0
  45. bash_classify-0.1.0/src/bash_classify/commands/dirname.yaml +5 -0
  46. bash_classify-0.1.0/src/bash_classify/commands/docker.yaml +152 -0
  47. bash_classify-0.1.0/src/bash_classify/commands/du.yaml +5 -0
  48. bash_classify-0.1.0/src/bash_classify/commands/echo.yaml +5 -0
  49. bash_classify-0.1.0/src/bash_classify/commands/env.yaml +14 -0
  50. bash_classify-0.1.0/src/bash_classify/commands/expand.yaml +5 -0
  51. bash_classify-0.1.0/src/bash_classify/commands/false.yaml +5 -0
  52. bash_classify-0.1.0/src/bash_classify/commands/file.yaml +5 -0
  53. bash_classify-0.1.0/src/bash_classify/commands/find.yaml +27 -0
  54. bash_classify-0.1.0/src/bash_classify/commands/fmt.yaml +5 -0
  55. bash_classify-0.1.0/src/bash_classify/commands/fold.yaml +5 -0
  56. bash_classify-0.1.0/src/bash_classify/commands/free.yaml +5 -0
  57. bash_classify-0.1.0/src/bash_classify/commands/gawk.yaml +5 -0
  58. bash_classify-0.1.0/src/bash_classify/commands/git.yaml +441 -0
  59. bash_classify-0.1.0/src/bash_classify/commands/go.yaml +38 -0
  60. bash_classify-0.1.0/src/bash_classify/commands/grep.yaml +5 -0
  61. bash_classify-0.1.0/src/bash_classify/commands/groups.yaml +5 -0
  62. bash_classify-0.1.0/src/bash_classify/commands/gunzip.yaml +5 -0
  63. bash_classify-0.1.0/src/bash_classify/commands/gzip.yaml +5 -0
  64. bash_classify-0.1.0/src/bash_classify/commands/head.yaml +5 -0
  65. bash_classify-0.1.0/src/bash_classify/commands/helm.yaml +127 -0
  66. bash_classify-0.1.0/src/bash_classify/commands/hostname.yaml +5 -0
  67. bash_classify-0.1.0/src/bash_classify/commands/id.yaml +5 -0
  68. bash_classify-0.1.0/src/bash_classify/commands/install.yaml +5 -0
  69. bash_classify-0.1.0/src/bash_classify/commands/join.yaml +5 -0
  70. bash_classify-0.1.0/src/bash_classify/commands/journalctl.yaml +12 -0
  71. bash_classify-0.1.0/src/bash_classify/commands/jq.yaml +5 -0
  72. bash_classify-0.1.0/src/bash_classify/commands/kill.yaml +5 -0
  73. bash_classify-0.1.0/src/bash_classify/commands/killall.yaml +5 -0
  74. bash_classify-0.1.0/src/bash_classify/commands/kubectl.yaml +190 -0
  75. bash_classify-0.1.0/src/bash_classify/commands/less.yaml +5 -0
  76. bash_classify-0.1.0/src/bash_classify/commands/ln.yaml +5 -0
  77. bash_classify-0.1.0/src/bash_classify/commands/ls.yaml +5 -0
  78. bash_classify-0.1.0/src/bash_classify/commands/make.yaml +19 -0
  79. bash_classify-0.1.0/src/bash_classify/commands/md5sum.yaml +5 -0
  80. bash_classify-0.1.0/src/bash_classify/commands/mkdir.yaml +5 -0
  81. bash_classify-0.1.0/src/bash_classify/commands/more.yaml +5 -0
  82. bash_classify-0.1.0/src/bash_classify/commands/mv.yaml +5 -0
  83. bash_classify-0.1.0/src/bash_classify/commands/netstat.yaml +5 -0
  84. bash_classify-0.1.0/src/bash_classify/commands/nice.yaml +9 -0
  85. bash_classify-0.1.0/src/bash_classify/commands/nl.yaml +5 -0
  86. bash_classify-0.1.0/src/bash_classify/commands/node.yaml +5 -0
  87. bash_classify-0.1.0/src/bash_classify/commands/nohup.yaml +6 -0
  88. bash_classify-0.1.0/src/bash_classify/commands/npm.yaml +65 -0
  89. bash_classify-0.1.0/src/bash_classify/commands/nslookup.yaml +5 -0
  90. bash_classify-0.1.0/src/bash_classify/commands/paste.yaml +5 -0
  91. bash_classify-0.1.0/src/bash_classify/commands/ping.yaml +5 -0
  92. bash_classify-0.1.0/src/bash_classify/commands/pip.yaml +29 -0
  93. bash_classify-0.1.0/src/bash_classify/commands/pip3.yaml +29 -0
  94. bash_classify-0.1.0/src/bash_classify/commands/pkill.yaml +5 -0
  95. bash_classify-0.1.0/src/bash_classify/commands/poetry.yaml +74 -0
  96. bash_classify-0.1.0/src/bash_classify/commands/printenv.yaml +5 -0
  97. bash_classify-0.1.0/src/bash_classify/commands/printf.yaml +5 -0
  98. bash_classify-0.1.0/src/bash_classify/commands/ps.yaml +5 -0
  99. bash_classify-0.1.0/src/bash_classify/commands/pwd.yaml +5 -0
  100. bash_classify-0.1.0/src/bash_classify/commands/python.yaml +5 -0
  101. bash_classify-0.1.0/src/bash_classify/commands/python3.yaml +5 -0
  102. bash_classify-0.1.0/src/bash_classify/commands/read.yaml +5 -0
  103. bash_classify-0.1.0/src/bash_classify/commands/readlink.yaml +5 -0
  104. bash_classify-0.1.0/src/bash_classify/commands/realpath.yaml +5 -0
  105. bash_classify-0.1.0/src/bash_classify/commands/rev.yaml +5 -0
  106. bash_classify-0.1.0/src/bash_classify/commands/rm.yaml +5 -0
  107. bash_classify-0.1.0/src/bash_classify/commands/rsync.yaml +10 -0
  108. bash_classify-0.1.0/src/bash_classify/commands/scp.yaml +5 -0
  109. bash_classify-0.1.0/src/bash_classify/commands/sed.yaml +12 -0
  110. bash_classify-0.1.0/src/bash_classify/commands/seq.yaml +5 -0
  111. bash_classify-0.1.0/src/bash_classify/commands/sh.yaml +12 -0
  112. bash_classify-0.1.0/src/bash_classify/commands/sha1sum.yaml +5 -0
  113. bash_classify-0.1.0/src/bash_classify/commands/sha256sum.yaml +5 -0
  114. bash_classify-0.1.0/src/bash_classify/commands/sort.yaml +8 -0
  115. bash_classify-0.1.0/src/bash_classify/commands/ss.yaml +5 -0
  116. bash_classify-0.1.0/src/bash_classify/commands/ssh.yaml +39 -0
  117. bash_classify-0.1.0/src/bash_classify/commands/stat.yaml +5 -0
  118. bash_classify-0.1.0/src/bash_classify/commands/strace.yaml +18 -0
  119. bash_classify-0.1.0/src/bash_classify/commands/sudo.yaml +22 -0
  120. bash_classify-0.1.0/src/bash_classify/commands/systemctl.yaml +56 -0
  121. bash_classify-0.1.0/src/bash_classify/commands/tac.yaml +5 -0
  122. bash_classify-0.1.0/src/bash_classify/commands/tail.yaml +5 -0
  123. bash_classify-0.1.0/src/bash_classify/commands/tar.yaml +22 -0
  124. bash_classify-0.1.0/src/bash_classify/commands/tee.yaml +5 -0
  125. bash_classify-0.1.0/src/bash_classify/commands/terraform.yaml +68 -0
  126. bash_classify-0.1.0/src/bash_classify/commands/test.yaml +5 -0
  127. bash_classify-0.1.0/src/bash_classify/commands/time.yaml +6 -0
  128. bash_classify-0.1.0/src/bash_classify/commands/timeout.yaml +15 -0
  129. bash_classify-0.1.0/src/bash_classify/commands/top.yaml +5 -0
  130. bash_classify-0.1.0/src/bash_classify/commands/touch.yaml +5 -0
  131. bash_classify-0.1.0/src/bash_classify/commands/tr.yaml +5 -0
  132. bash_classify-0.1.0/src/bash_classify/commands/traceroute.yaml +5 -0
  133. bash_classify-0.1.0/src/bash_classify/commands/true.yaml +5 -0
  134. bash_classify-0.1.0/src/bash_classify/commands/type.yaml +5 -0
  135. bash_classify-0.1.0/src/bash_classify/commands/uname.yaml +5 -0
  136. bash_classify-0.1.0/src/bash_classify/commands/unexpand.yaml +5 -0
  137. bash_classify-0.1.0/src/bash_classify/commands/uniq.yaml +5 -0
  138. bash_classify-0.1.0/src/bash_classify/commands/unzip.yaml +7 -0
  139. bash_classify-0.1.0/src/bash_classify/commands/uptime.yaml +5 -0
  140. bash_classify-0.1.0/src/bash_classify/commands/uv.yaml +117 -0
  141. bash_classify-0.1.0/src/bash_classify/commands/wc.yaml +5 -0
  142. bash_classify-0.1.0/src/bash_classify/commands/wget.yaml +5 -0
  143. bash_classify-0.1.0/src/bash_classify/commands/whereis.yaml +5 -0
  144. bash_classify-0.1.0/src/bash_classify/commands/which.yaml +5 -0
  145. bash_classify-0.1.0/src/bash_classify/commands/whoami.yaml +5 -0
  146. bash_classify-0.1.0/src/bash_classify/commands/xargs.yaml +25 -0
  147. bash_classify-0.1.0/src/bash_classify/commands/xmllint.yaml +5 -0
  148. bash_classify-0.1.0/src/bash_classify/commands/yes.yaml +5 -0
  149. bash_classify-0.1.0/src/bash_classify/commands/yq.yaml +8 -0
  150. bash_classify-0.1.0/src/bash_classify/commands/zip.yaml +5 -0
  151. bash_classify-0.1.0/src/bash_classify/commands/zsh.yaml +12 -0
  152. bash_classify-0.1.0/src/bash_classify/database.py +257 -0
  153. bash_classify-0.1.0/src/bash_classify/matcher.py +702 -0
  154. bash_classify-0.1.0/src/bash_classify/models.py +148 -0
  155. bash_classify-0.1.0/src/bash_classify/parser.py +525 -0
  156. bash_classify-0.1.0/src/bash_classify/py.typed +0 -0
  157. bash_classify-0.1.0/tests/__init__.py +0 -0
  158. bash_classify-0.1.0/tests/conftest.py +13 -0
  159. bash_classify-0.1.0/tests/test_classifier.py +544 -0
  160. bash_classify-0.1.0/tests/test_cli.py +82 -0
  161. bash_classify-0.1.0/tests/test_cli_serialization.py +184 -0
  162. bash_classify-0.1.0/tests/test_database.py +275 -0
  163. bash_classify-0.1.0/tests/test_matcher.py +553 -0
  164. bash_classify-0.1.0/tests/test_models.py +33 -0
  165. bash_classify-0.1.0/tests/test_parser.py +437 -0
  166. bash_classify-0.1.0/tests/test_real_world.py +435 -0
  167. bash_classify-0.1.0/tests/test_schema.py +28 -0
  168. bash_classify-0.1.0/tests/test_smoke.py +4 -0
  169. bash_classify-0.1.0/uv.lock +450 -0
@@ -0,0 +1,13 @@
1
+ ---
2
+ paths:
3
+ - "src/bash_classify/commands/**"
4
+ ---
5
+
6
+ @docs/classification-guidance.md
7
+ @schemas/command.schema.json
8
+
9
+ Every YAML file must:
10
+ - Start with `# $schema: ../../../schemas/command.schema.json` on the first line
11
+ - Have a `command:` field matching the filename (without `.yaml`)
12
+ - Have a `description:` field with a short one-liner
13
+ - Pass schema validation (`uv run pytest tests/test_schema.py`)
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "bash-classify",
3
+ "description": "Bash command classifier with Claude Code plugin for auto-allowing readonly commands",
4
+ "metadata": {
5
+ "pluginRoot": "./coding-agent-plugins/claude-code"
6
+ },
7
+ "plugins": [
8
+ {
9
+ "name": "bash-classify-hook",
10
+ "source": "."
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,21 @@
1
+ root = true
2
+
3
+ [*]
4
+ end_of_line = lf
5
+ insert_final_newline = true
6
+ trim_trailing_whitespace = true
7
+ charset = utf-8
8
+
9
+ [*.py]
10
+ indent_style = space
11
+ indent_size = 4
12
+
13
+ [*.{yaml,yml,json,toml}]
14
+ indent_style = space
15
+ indent_size = 2
16
+
17
+ [*.md]
18
+ trim_trailing_whitespace = false
19
+
20
+ [Makefile]
21
+ indent_style = tab
@@ -0,0 +1,62 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ pull_request:
7
+
8
+ jobs:
9
+ lint:
10
+ name: Lint
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - uses: astral-sh/setup-uv@v7
16
+ with:
17
+ enable-cache: true
18
+
19
+ - name: Install dependencies
20
+ run: uv sync --locked --dev
21
+
22
+ - name: Ruff check
23
+ run: uv run ruff check --output-format github .
24
+
25
+ - name: Ruff format check
26
+ run: uv run ruff format --check .
27
+
28
+ test:
29
+ name: Test (Python ${{ matrix.python-version }})
30
+ runs-on: ubuntu-latest
31
+ strategy:
32
+ matrix:
33
+ python-version: ["3.12", "3.13"]
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+
37
+ - uses: astral-sh/setup-uv@v7
38
+ with:
39
+ python-version: ${{ matrix.python-version }}
40
+ enable-cache: true
41
+
42
+ - name: Install dependencies
43
+ run: uv sync --locked --dev
44
+
45
+ - name: Run tests
46
+ run: uv run pytest
47
+
48
+ schema:
49
+ name: Validate YAML schema
50
+ runs-on: ubuntu-latest
51
+ steps:
52
+ - uses: actions/checkout@v4
53
+
54
+ - uses: astral-sh/setup-uv@v7
55
+ with:
56
+ enable-cache: true
57
+
58
+ - name: Install dependencies
59
+ run: uv sync --locked --dev
60
+
61
+ - name: Validate command database
62
+ run: uv run pytest tests/test_schema.py -v
@@ -0,0 +1,44 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ build:
10
+ name: Build
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ with:
15
+ fetch-depth: 0
16
+
17
+ - uses: astral-sh/setup-uv@v7
18
+ with:
19
+ enable-cache: true
20
+
21
+ - name: Build package
22
+ run: uv build
23
+
24
+ - uses: actions/upload-artifact@v4
25
+ with:
26
+ name: dist
27
+ path: dist/
28
+
29
+ publish:
30
+ name: Publish
31
+ needs: build
32
+ runs-on: ubuntu-latest
33
+ environment:
34
+ name: pypi
35
+ url: https://pypi.org/p/bash-classify
36
+ permissions:
37
+ id-token: write
38
+ steps:
39
+ - uses: actions/download-artifact@v4
40
+ with:
41
+ name: dist
42
+ path: dist/
43
+
44
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,30 @@
1
+ # Python
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+ *.egg-info/
6
+ dist/
7
+ build/
8
+
9
+ # Virtual environments
10
+ .venv/
11
+ venv/
12
+
13
+ # Testing / Coverage
14
+ .coverage
15
+ .pytest_cache/
16
+ htmlcov/
17
+
18
+ # Linting
19
+ .ruff_cache/
20
+
21
+ # IDEs
22
+ .idea/
23
+ .vscode/
24
+ *.swp
25
+ *.swo
26
+ *~
27
+
28
+ # OS
29
+ .DS_Store
30
+ Thumbs.db
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,2 @@
1
+ @README.md
2
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Filip Prochazka
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,147 @@
1
+ Metadata-Version: 2.4
2
+ Name: bash-classify
3
+ Version: 0.1.0
4
+ Summary: Classify bash commands as READONLY, WRITE, DANGEROUS, or UNKNOWN
5
+ Project-URL: Homepage, https://github.com/fprochazka/bash-classify
6
+ Project-URL: Repository, https://github.com/fprochazka/bash-classify
7
+ Project-URL: Issues, https://github.com/fprochazka/bash-classify/issues
8
+ Project-URL: Documentation, https://github.com/fprochazka/bash-classify/blob/main/SPEC.md
9
+ Author-email: Filip Procházka <dev@fprochazka.cz>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: bash,classification,cli,security,tree-sitter
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Security
21
+ Classifier: Topic :: Software Development :: Libraries
22
+ Classifier: Topic :: System :: Shells
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.12
25
+ Requires-Dist: pyyaml>=6.0
26
+ Requires-Dist: tree-sitter-bash>=0.23
27
+ Requires-Dist: tree-sitter>=0.24
28
+ Description-Content-Type: text/markdown
29
+
30
+ # bash-classify
31
+
32
+ Classify bash commands by their side-effect risk level.
33
+
34
+ ## What it does
35
+
36
+ bash-classify parses bash expressions using tree-sitter, classifies each command against a database of 120+ known commands, and outputs a structured JSON verdict. Commands are classified into four levels: `READONLY`, `WRITE`, `DANGEROUS`, and `UNKNOWN`.
37
+
38
+ Designed primarily as a [Claude Code](https://docs.anthropic.com/en/docs/claude-code) hook to automatically allow safe, read-only commands while flagging risky ones for human review.
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ uv tool install bash-classify
44
+ # or
45
+ pip install bash-classify
46
+ ```
47
+
48
+ ## Quick start
49
+
50
+ ```bash
51
+ $ echo 'kubectl get pods -n production' | bash-classify | jq '.classification'
52
+ "READONLY"
53
+
54
+ $ echo 'git push --force origin main' | bash-classify | jq '.classification'
55
+ "DANGEROUS"
56
+
57
+ $ echo 'cp file.txt /etc/config' | bash-classify | jq '.classification'
58
+ "DANGEROUS"
59
+
60
+ $ echo 'find . -name "*.pyc" -delete' | bash-classify | jq '.classification'
61
+ "DANGEROUS"
62
+ ```
63
+
64
+ ## Claude Code hook
65
+
66
+ Install as a Claude Code hook to auto-allow read-only commands and require approval for everything else:
67
+
68
+ ```json
69
+ {
70
+ "hooks": {
71
+ "PreToolUse": [
72
+ {
73
+ "matcher": "Bash",
74
+ "hooks": [
75
+ {
76
+ "type": "command",
77
+ "command": "echo \"$CLAUDE_TOOL_INPUT\" | jq -r '.command' | bash-classify",
78
+ "timeout": 5000,
79
+ "on_output": [
80
+ {
81
+ "matcher": "\"classification\": \"READONLY\"",
82
+ "action": "approve"
83
+ }
84
+ ]
85
+ }
86
+ ]
87
+ }
88
+ ]
89
+ }
90
+ }
91
+ ```
92
+
93
+ ## Command database
94
+
95
+ The classification database includes 120+ command definitions covering common Unix utilities, package managers, container tools, cloud CLIs, and more.
96
+
97
+ - See [docs/classification-guidance.md](docs/classification-guidance.md) for how to add new commands
98
+ - YAML definitions are validated against a JSON Schema for IDE autocomplete and CI checks
99
+
100
+ ## Classification levels
101
+
102
+ | Level | Description | Examples |
103
+ |---|---|---|
104
+ | `READONLY` | No side effects, safe to auto-approve | `ls`, `cat`, `grep`, `kubectl get` |
105
+ | `WRITE` | Modifies local files or state | `mkdir`, `cp`, `git commit` |
106
+ | `DANGEROUS` | Destructive, system-wide, or irreversible | `rm -rf`, `git push --force`, `chmod` |
107
+ | `UNKNOWN` | Command not in database | Any unrecognized command |
108
+
109
+ ## How it works
110
+
111
+ - **Tree-sitter parsing** -- bash expressions are parsed into an AST for accurate command extraction, handling pipes, subshells, and command substitution
112
+ - **YAML command database** -- each command has classification rules with subcommand and option matching
113
+ - **Subcommand matching** -- `kubectl get` and `kubectl delete` can have different classifications
114
+ - **Delegation for wrappers** -- commands like `xargs`, `sudo`, and `env` delegate classification to the inner command
115
+
116
+ ## Python API
117
+
118
+ ```python
119
+ from bash_classify import classify_expression
120
+
121
+ result = classify_expression("kubectl get pods")
122
+ print(result.classification) # Classification.READONLY
123
+ ```
124
+
125
+ See [SPEC.md](SPEC.md) for the full specification.
126
+
127
+ ## Development
128
+
129
+ ```bash
130
+ git clone https://github.com/fprochazka/bash-classify.git
131
+ cd bash-classify
132
+ uv sync --dev
133
+ ```
134
+
135
+ Run tests and linting before committing:
136
+
137
+ ```bash
138
+ uv run ruff format .
139
+ uv run ruff check .
140
+ uv run pytest
141
+ ```
142
+
143
+ To add or modify command definitions, see [docs/classification-guidance.md](docs/classification-guidance.md). All YAML files in `src/bash_classify/commands/` are validated against a [JSON Schema](schemas/command.schema.json) — your IDE will provide autocomplete if it supports the `# $schema:` comment.
144
+
145
+ ## License
146
+
147
+ [MIT](LICENSE)
@@ -0,0 +1,118 @@
1
+ # bash-classify
2
+
3
+ Classify bash commands by their side-effect risk level.
4
+
5
+ ## What it does
6
+
7
+ bash-classify parses bash expressions using tree-sitter, classifies each command against a database of 120+ known commands, and outputs a structured JSON verdict. Commands are classified into four levels: `READONLY`, `WRITE`, `DANGEROUS`, and `UNKNOWN`.
8
+
9
+ Designed primarily as a [Claude Code](https://docs.anthropic.com/en/docs/claude-code) hook to automatically allow safe, read-only commands while flagging risky ones for human review.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ uv tool install bash-classify
15
+ # or
16
+ pip install bash-classify
17
+ ```
18
+
19
+ ## Quick start
20
+
21
+ ```bash
22
+ $ echo 'kubectl get pods -n production' | bash-classify | jq '.classification'
23
+ "READONLY"
24
+
25
+ $ echo 'git push --force origin main' | bash-classify | jq '.classification'
26
+ "DANGEROUS"
27
+
28
+ $ echo 'cp file.txt /etc/config' | bash-classify | jq '.classification'
29
+ "DANGEROUS"
30
+
31
+ $ echo 'find . -name "*.pyc" -delete' | bash-classify | jq '.classification'
32
+ "DANGEROUS"
33
+ ```
34
+
35
+ ## Claude Code hook
36
+
37
+ Install as a Claude Code hook to auto-allow read-only commands and require approval for everything else:
38
+
39
+ ```json
40
+ {
41
+ "hooks": {
42
+ "PreToolUse": [
43
+ {
44
+ "matcher": "Bash",
45
+ "hooks": [
46
+ {
47
+ "type": "command",
48
+ "command": "echo \"$CLAUDE_TOOL_INPUT\" | jq -r '.command' | bash-classify",
49
+ "timeout": 5000,
50
+ "on_output": [
51
+ {
52
+ "matcher": "\"classification\": \"READONLY\"",
53
+ "action": "approve"
54
+ }
55
+ ]
56
+ }
57
+ ]
58
+ }
59
+ ]
60
+ }
61
+ }
62
+ ```
63
+
64
+ ## Command database
65
+
66
+ The classification database includes 120+ command definitions covering common Unix utilities, package managers, container tools, cloud CLIs, and more.
67
+
68
+ - See [docs/classification-guidance.md](docs/classification-guidance.md) for how to add new commands
69
+ - YAML definitions are validated against a JSON Schema for IDE autocomplete and CI checks
70
+
71
+ ## Classification levels
72
+
73
+ | Level | Description | Examples |
74
+ |---|---|---|
75
+ | `READONLY` | No side effects, safe to auto-approve | `ls`, `cat`, `grep`, `kubectl get` |
76
+ | `WRITE` | Modifies local files or state | `mkdir`, `cp`, `git commit` |
77
+ | `DANGEROUS` | Destructive, system-wide, or irreversible | `rm -rf`, `git push --force`, `chmod` |
78
+ | `UNKNOWN` | Command not in database | Any unrecognized command |
79
+
80
+ ## How it works
81
+
82
+ - **Tree-sitter parsing** -- bash expressions are parsed into an AST for accurate command extraction, handling pipes, subshells, and command substitution
83
+ - **YAML command database** -- each command has classification rules with subcommand and option matching
84
+ - **Subcommand matching** -- `kubectl get` and `kubectl delete` can have different classifications
85
+ - **Delegation for wrappers** -- commands like `xargs`, `sudo`, and `env` delegate classification to the inner command
86
+
87
+ ## Python API
88
+
89
+ ```python
90
+ from bash_classify import classify_expression
91
+
92
+ result = classify_expression("kubectl get pods")
93
+ print(result.classification) # Classification.READONLY
94
+ ```
95
+
96
+ See [SPEC.md](SPEC.md) for the full specification.
97
+
98
+ ## Development
99
+
100
+ ```bash
101
+ git clone https://github.com/fprochazka/bash-classify.git
102
+ cd bash-classify
103
+ uv sync --dev
104
+ ```
105
+
106
+ Run tests and linting before committing:
107
+
108
+ ```bash
109
+ uv run ruff format .
110
+ uv run ruff check .
111
+ uv run pytest
112
+ ```
113
+
114
+ To add or modify command definitions, see [docs/classification-guidance.md](docs/classification-guidance.md). All YAML files in `src/bash_classify/commands/` are validated against a [JSON Schema](schemas/command.schema.json) — your IDE will provide autocomplete if it supports the `# $schema:` comment.
115
+
116
+ ## License
117
+
118
+ [MIT](LICENSE)