A commit-safety CLI for AI-assisted workflows
Classify your diff into a conventional-commit type(scope), guard git commit and file deletion behind model-judged rules, and enforce per-project conventions from a codesafe.yaml.
curl -fsSL https://raw.githubusercontent.com/LingyeNBird/codesafe/main/install.sh | bashOr grab a binary from Releases:
| Platform | File |
|---|---|
| Windows (x64) | codesafe-windows-amd64.exe |
| Linux (x64) | codesafe-linux-amd64 |
| macOS (Apple Silicon) | codesafe-darwin-arm64 |
| macOS (Intel) | codesafe-darwin-amd64 |
| Command | What it does |
|---|---|
codesafe |
Suggest a type(scope) for the staged/worktree diff (single line, pipe into git commit -m). |
codesafe commit -m ... |
Validate message + code rules, generate the prefix, run git commit. |
codesafe diff |
Check the diff against codesafe.yaml rules; report violations. Oversized diffs are truncated and flagged (split the commit for full coverage); --pass <glob> exempts files from judgement. |
codesafe delete <path> |
Judge safety before deleting — safe deletes, sensitive quarantines, dangerous aborts. |
codesafe init |
Write a commented codesafe.yaml template + print an AI prompt for filling it. |
codesafe agent |
Print a rules block to paste into AGENTS.md / CLAUDE.md so AI agents use codesafe. |
codesafe todo <task> |
Set the current task; commit/diff verify the diff implements it. |
codesafe intent "<text>" |
Classify user intent — whether to modify code plus which responses they want (answer/plan/review/execute). --json for the full probability vector, --context for surrounding context. |
./codesafe # staged diff, else worktree → prints e.g. "feat(cli)!"
./codesafe --detail # full percentages + token/cost stats
./codesafe --source worktree # unstaged only; --source <sha> for a commit
./codesafe --source staged # staged only./codesafe commit -m "重构为 conventional-commit 分类器" -m "- 新增 scope 筛选"Checks commit_rules (e.g. subject must be Chinese), then rules against the staged diff, generates the prefix, and runs git commit. A self-supplied type(scope): prefix in the first -m is honored or replaced per prefix_conflict (keep_user / override); --reclassify ignores any existing or malformed prefix and regenerates it unconditionally — restricted: use only when the user explicitly wants the prefix regenerated or the subject's prefix is malformed, never to override a prefix you merely disagree with. The user's subject text is also fed to the classifier as reference context. Breaking is never inferred from the diff — declare it explicitly with codesafe commit --breaking to append ! (e.g. feat!).
./codesafe delete build/ # judge then act
./codesafe delete build/ --check # verdict only, no delete/move
./codesafe delete tmp/ --yes # skip the verdictVerdicts: safe → os.RemoveAll; sensitive → moved to a quarantine dir under the system temp dir (recoverable); dangerous → aborts.
./codesafe todo "add OAuth login" # record the current task for this repo
./codesafe todo # show it
./codesafe todo --clear # clear it (also auto-cleared on successful commit)When a todo is set, codesafe commit/codesafe diff additionally ask the model whether the diff implements that task — a mismatch aborts the commit. Rules may embed {{TODO}} in text/pass/fail to reference the current task; todo_mode (off|loose|strict, default loose) controls whether a {{TODO}} rule requires a set todo — strict aborts the commit when no todo is set, and can be set per-rule.
lang: zh
allow_none: true
prefix_conflict: override
scopes: # this project's scope vocabulary
cli: "command-line entrypoint / subcommands"
api: "HTTP/RPC layer"
ci: "CI / release workflows"
rules: # code rules — checked against the diff
- id: vue-css-split
level: error # error aborts · warn only prints
files: "*.vue" # only asked when the diff touches matching files
text: .vue files must not contain <style> blocks
pass: all .vue styles live in external .css files
fail: a .vue file still contains an inline <style> block
- id: file-purpose
level: error
files: "*.go"
lines: "1-8" # judge this rule on file line ranges, not the diff —
# feeds the matched files' lines 1-8 to the model.
# ranges: "1-4,-10--1" (negatives = from end), comma-separated
text: every .go file must have a purpose comment at the top
pass: all touched .go files have a top purpose comment
fail: some .go file lacks a top purpose comment
commit_rules: # rules about the commit message itself
- id: subject-zh
on: subject # subject | body | prefix | all — prefix only applies under prefix_conflict=keep_user
text: the subject must be in Chinese
pass: the subject is primarily Chinese
fail: the subject is not ChineseA rule with lines is judged on the matched files' raw line ranges instead of the shared diff — useful for rules about content the diff can't show (file headers, unmodified regions). lines is a comma-separated list of 1-based inclusive ranges; negative numbers count from the end (-1 = last line), so "1-8" reads the header, "-10--1" reads the last ten lines.
If scopes is absent, codesafe screens a built-in vocabulary against your directory tree (a scope like cli is dropped when the whole project is a CLI) and caches the result per project.
./codesafe agent # prints a rules block for AGENTS.md / CLAUDE.mdPaste the output into your agent rules file so the AI uses codesafe delete/commit/diff instead of raw rm/git commit.
./codesafe --config api_key=<key> # save TypeSafe key (console.typesafe.ai)
./codesafe --config lang=zh|en
./codesafe --config scopes=cli|server|web
./codesafe --config nonescope=false
./codesafe --config cache=false # disable the response cache (bbolt, keyed by request SHA-256, 1h TTL)
./codesafe --set lang=en # one-run override, not saved
./codesafe diff --refresh # bypass cache and re-judge once
./codesafe diff --pass 'dist/**' # skip files matching a glob (repeatable) — useful when a single file is still too large after splittingPriority: codesafe.yaml > --config > built-in / screened defaults.
Get one at console.typesafe.ai. First run prompts and saves it to the user config dir (0600).