https://github.com/discretetom/defect
Call LLMs in your pipeline, e.g. local git hook, GitHub Actions and more.
https://github.com/discretetom/defect
ai cicd codereview git-hooks github-actions llm pipeline workflow
Last synced: 8 months ago
JSON representation
Call LLMs in your pipeline, e.g. local git hook, GitHub Actions and more.
- Host: GitHub
- URL: https://github.com/discretetom/defect
- Owner: DiscreteTom
- License: mit
- Created: 2025-02-20T11:37:29.000Z (12 months ago)
- Default Branch: main
- Last Pushed: 2025-04-01T08:10:40.000Z (11 months ago)
- Last Synced: 2025-04-01T09:24:41.174Z (11 months ago)
- Topics: ai, cicd, codereview, git-hooks, github-actions, llm, pipeline, workflow
- Language: Rust
- Homepage:
- Size: 162 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Defect

[](https://github.com/DiscreteTom/defect/releases/latest)
Call LLMs in your pipeline, e.g. local [git hook](#git-hook), [GitHub Actions](#github-actions) and more.
## Features
- Single static-linked binary executable. You don't need to be familiar with Python or any framework.
- Customizable prompt. Suitable for all kinds of tasks. See [examples](#prompt-engineering) below.
- Support OpenAI (or compatible) and AWS Bedrock models.
## Installation
Just download the pre-built binary. E.g. for Linux x86_64 environment:
```bash
wget https://github.com/DiscreteTom/defect/releases/download/v0.3.3/defect-v0.3.3-x86_64-unknown-linux-musl.zip
unzip defect-v0.3.3-x86_64-unknown-linux-musl.zip
rm defect-v0.3.3-x86_64-unknown-linux-musl.zip
chmod +x defect
```
See the [latest GitHub releases](https://github.com/DiscreteTom/defect/releases/latest) page for more pre-built binaries.
> [!IMPORTANT]
> Remember to include the binary in your `PATH`.
## Usage
```bash
$ defect --help
Call LLMs in your pipeline, print the text response to stdout
Usage: defect [OPTIONS] [PROMPT]
Arguments:
[PROMPT] The prompt to use. If not provided or equal to "-", the program will read from stdin
Options:
-m, --model The model to use [default: gpt-4o]
-s, --schema The API schema to use [default: openai] [possible values: openai, bedrock]
-S, --system Optional system instructions
-h, --help Print help
-V, --version Print version
```
### Choose a Model
```bash
# You can use `--model` to specify a custom OpenAI model.
# Make sure you have set the "OPENAI_API_KEY" environment variable.
export OPENAI_API_KEY=""
defect "who are you"
defect --model=gpt-4o "who are you"
# For OpenAI compatible models, e.g. OpenRouter,
# specify a custom endpoint via the "OPENAI_API_BASE" environment variable.
# Make sure you have also set the "OPENAI_API_KEY" environment variable.
export OPENAI_API_BASE="https://openrouter.ai/api/v1"
defect --model=deepseek/deepseek-r1 "who are you"
# For AWS Bedrock models, set the `schema` option.
# Make sure you have AWS credentials set up.
defect --schema bedrock --model=anthropic.claude-3-5-sonnet-20240620-v1:0 "who are you"
```
> To set AWS credentials, you can [use environment variables](https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-envvars.html), or [use AWS CLI](https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-files.html#cli-configure-files-methods). See AWS official documentations for more information.
## Prompt Engineering
The functionality of this tool is highly dependent on the prompt you provide.
You can construct complex prompts in bash scripts and pass it to the tool.
```bash
# insert the content of a file by using string interpolation in bash
prompt="Summarize the file. `cat README.md`"
defect "$prompt"
```
Here are some prompt examples.
General Code Review
```bash
prompt="
You are a coding expert.
Review the following code and give me suggestions.
`cat main.rs`
"
```
Code Review with a Guideline
Your team may have a coding guideline. You can insert the guideline into the prompt.
```bash
prompt="
You are a coding expert.
Review the code below following my provided guideline
and give me suggestions.
`cat guideline.md 2>/dev/null || curl https://your-server.com/guideline.md`
`cat main.rs`
"
```
Document Validation
```bash
# review comments
prompt="
You are a coding expert.
Review the following code, ensure the comments adheres to the functionality of the code.
If not, provide suggestions to update the comments.
`cat main.rs`
"
# review documentation
prompt="
You are a coding expert.
Review the following code, ensure the provided documentation adheres to the functionality of the code.
If not, provide suggestions to update the documentation.
`cat documentation.md`
`cat main.rs`
"
```
## Workflow
### Abort a Workflow Execution
When using this tool in a workflow or pipeline, you may want to abort the execution if the result is not as expected.
This requires your LLM output is structured in a way that you can parse it.
A simple example:
```bash
prompt="
...
If you think the code is correct, output 'OK' with nothing else.
Otherwise, output suggestions in markdown format.
"
output=$(defect "$prompt")
if [ "$output" != "OK" ]; then
echo "$output"
exit 1
fi
```
### Webhook Callback
If your workflow execution is aborted by LLM, you may want to send a webhook callback to, for example, Slack, Lark, or your own issue tracker.
```bash
...
if [ "$output" != "OK" ]; then
echo "$output"
commit=$(git rev-parse HEAD)
escaped_output=$(jq -n --arg val "$output" '$val')
body="{\"commit\":\"$commit\",\"feedback\":$escaped_output}"
curl -X POST -d "$body" https://your-server.com/webhook
exit 1
fi
```
### Git Hook
You can review your code locally via git hooks to reduce the feedback loop time, instead of waiting for CI/CD.
An example of `pre-commit` hook:
```bash
#!/bin/sh
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=$(git hash-object -t tree /dev/null)
fi
# Get the diff of the staged files with 100 lines of context
diff=$(git diff --cached -U100 $against)
prompt="
You are a coding expert.
Review the following code diff and give me suggestions.
If you think the code is correct, output 'OK' with nothing else.
Otherwise, output suggestions in markdown format.
$diff
"
output=$(defect "$prompt")
if [ "$output" != "OK" ]; then
echo "$output"
exit 1
fi
```
### GitHub Actions
There is a [setup-defect](https://github.com/DiscreteTom/setup-defect) action available to simplify the setup process.
Review each commit:
```yaml
on:
push:
# only trigger on branches, not on tags
branches: "**"
jobs:
validate:
runs-on: ubuntu-latest
steps:
# fetch at least 2 commits so we can get the diff of the latest commit
- uses: actions/checkout@v4
with:
fetch-depth: 2
# get the diff of the latest commit with 100 lines of context
- name: Get the diff
run: |
git diff -U100 HEAD^ HEAD > /tmp/diff
cat /tmp/diff
- name: Setup defect
uses: DiscreteTom/setup-defect@v0.1.1
with:
version: "0.3.3"
- name: Review the diff using defect
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
diff=$(cat /tmp/diff)
prompt="
You are a coding expert.
Review the following code diff and give me suggestions.
If you think the code is correct, output 'OK' with nothing else.
Otherwise, output suggestions in markdown format.
$diff
"
defect "$prompt" > /tmp/suggestions
cat /tmp/suggestions
- name: Abort if suggestions are not empty
run: |
suggestions=$(cat /tmp/suggestions)
if [ "$suggestions" != "OK" ]; then
exit 1
fi
```
Review each PR (get the diff between the PR branch and the base branch):
```yaml
on:
pull_request:
types: [opened, synchronize]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Fetch the origin/main branch
run: |
git fetch origin main:refs/remotes/origin/main
- name: Get the diff
run: |
git diff origin/main HEAD > /tmp/diff
cat /tmp/diff
# ...
```
## Telemetry
Currently this project doesn't emit any telemetry data.
To collect the LLM usage data, you can use an AI gateway like [OpenRouter](https://openrouter.ai/), [LiteLLM](https://www.litellm.ai/) or [Kong](https://konghq.com/).
To collect the LLM response data, just send the response to your own server or write to your own database.
```bash
...
if [ "$output" != "OK" ]; then
echo "$output"
# e.g. send telemetry with a webhook callback
curl -X POST -d "some-data" https://your-server.com/webhook
# e.g. convert output to metrics using LLM
# and save to AWS S3 so you can query using AWS Athena
metrics_prompt="
Below is a code review feedback,
tell me how many suggestions are there.
You should output a JSON object with the following format:
{\"suggestions\": 123}
You should only output the JSON object with nothing else.
$output
"
metrics=$(defect "$metrics_prompt")
timestamp=$(date +%s)
echo "$metrics" > $timestamp.json
date=$(date +'%Y/%m/%d')
author=$(git log -1 --pretty=format:'%an')
aws s3 cp $timestamp.json "s3://your-bucket/suggestions/$date/$author/$timestamp.json"
exit 1
fi
```
## Cost Optimization
Tips to save your money:
- Prevent unnecessary calls. E.g. in code review scenarios, use traditional formatters and linters before calling LLMs.
- Use cheaper models for frequent tasks. E.g. review commits with DeepSeek models while review PRs with Claude models.
## Demo
See [`defect-demo`](https://github.com/DiscreteTom/defect-demo) for a demo project.
## Debug
This project uses [EnvFilter](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html) to filter logs.
All the logs will be printed to `stderr`.
Here is an example to enable debug logs:
```bash
export RUST_LOG="defect=debug"
```
## [CHANGELOG](./CHANGELOG.md)