Smith welcomes external contributions. If you have an itch, please feel free to scratch it.
To contribute code or documentation, submit a pull request. A good way to get familiar with the codebase is to tackle low-hanging fruit in the issue tracker. Before a more ambitious contribution, please open an issue first so the approach can be discussed.
- Python 3.11+ — the CLI and pipelines target 3.11 and 3.12.
- OPA and Regal — required to lint, run, and test Rego policies.
- ARES and Promptfoo — required only for adversarial test generation (install separately; see the README).
The Makefile mirrors CI — a green make ci locally means a green
pipeline:
make install # create a uv venv and install Smith (editable) + [dev] extras
make lint # ruff check + black --check over src/ (read-only)
make format # ruff --fix + black (apply formatting)
make lint-policy # Regal/OPA lint of assets/policy.rego (NOT part of `make ci`)
make license-check # verify every in-scope file carries the SPDX header
make test # policy scorecard (needs Docker + the OPA server)
make unit # env-free offline pytest subset (part of `make ci`)
make integration # the live suite: real CLI against real services (opt-in)
make ci # the gate: lint + license-check + unitPackage management uses uv. Build and publish
with make package / make publish (uv build / uv publish).
Run both of these, and paste the results in the PR description:
make ci # the gate: lint (ruff + black) + license-check + unit
make integration # the live suite, one test module per `smith --flag`make ci is read-only, it reports problems rather than fixing them. Run
make format to apply the ruff/black fixes and make license to insert missing
SPDX headers, then re-run make ci.
It is one pytest module per smith --flag <stage> — the tests run the real
CLI (python -m smith.cli --flag <stage>) against the real services and then
assert the artifacts that stage wrote. So "integration passed" means every
pipeline stage still starts, connects to its neighbours, and produces the files
the next stage reads. Currently covered flags:
get_current_agent · get_mcp_parameter · test_generation ·
bypass_case_generation · generate_promptfoo_config · test_case_evaluation ·
test_case_translation · policy_testing · policy_validation (+ _fix) ·
cross_validate (+ apply_cross_validate) · red_suggestion ·
regal_suggestion · duplication_suggestion · cpex_translate ·
save_snapshot · classify_guidance · open_explorer
Two things to know before you run it:
- Nothing is required. Each module skips cleanly when its dependency is
absent — Docker/OPA, an LLM (
OPENAI_*/MODEL_SONNET), the example agent, ARES, Promptfoo. A bare run on a fresh laptop is safe and will mostly skip. Read the skip reasons (-rais on by default): a stage you touched that skipped was not actually tested.
make integration runs everything; while iterating, run just the file for the
stage you changed:
# one stage, verbose, with skip reasons
source .venv/bin/activate
python -m pytest tests/integration/test_policy_testing_integration.py -m integration -v -ra
# a single test inside that file
python -m pytest \
tests/integration/test_policy_testing_integration.py::test_the_confusion_matrix_matches_the_frozen_expectation \
-m integration -v
# the matching unit file — offline, no .env, fast
python -m pytest tests/integration/test_policy_testing_unit.py -m unit
# see what would run without running it
python -m pytest tests/integration --collect-only -m integrationA new smith --flag <name> is not done until it has both test lanes:
| File | Marker | Runs in CI | Boundary |
|---|---|---|---|
tests/integration/test_<flag>_unit.py |
unit |
yes (make ci) |
faked — env-free, offline, no Docker/LLM |
tests/integration/test_<flag>_integration.py |
integration |
no (opt-in) | real services, coarse assertions |
Follow tests/integration/TESTING_GUIDE.md to create additional tests
— it is the normative document and gives the recipe plus a worked reference pair
(test_case_evaluation_{unit,integration}.py).
The markdown under SKILL.md, opa_policy/, and
test_generation/ is not code — it is the instructions a
coding agent follows. make ci and make integration cannot test it: they
exercise the CLI stages behind the flags, never the orchestration that decides
which flag to run when. A change to any of those files has to be validated by
actually running the skill end to end against one example agent.
1. Place the skill where your agent finds it
Claude Code resolve /smith against .claude/skills/ under
their own working directory, Bob uses .bob/skills/:
<workspace>/ # the agent's cwd
└── .claude/skills/smith/ # this repo
2. Python environment + the Smith CLI
cd .claude/skills/smith
make install # uv venv + editable install; provides the `smith` CLI
source .venv/bin/activate3. .env
cp .env_template .envPaths are relative to BASE_URL, which is the absolute path to the skill folder
with a trailing slash. For the hr-agent example:
BASE_URL=/absolute/path/to/<workspace>/.claude/skills/smith/
# the LLM Smith's own pipelines use
OPENAI_API_KEY=<your key>
OPENAI_BASE_URL=<your endpoint>
MODEL_SONNET=<model>
# the target agent
AGENT_URL=http://localhost:9000
TARGET_AGENT_PATH=examples/hr-agent/
GUIDANCE_FILE=examples/hr-agent/smith/guidance.txt
SYSTEM_VAR_FILE=examples/hr-agent/smith/system_vars.json
PROMPTFOO_CONFIG_FILE=examples/hr-agent/smith/promptfooconfig.yaml
PROMPTFOO_OUTPUT_FILE=examples/hr-agent/smith/redteam.yaml
# hr-agent serves its tool definitions at GET /tool_definitions — no MCP server
MCP_TRANSPORT=http
MCP_URL=http://localhost:9000/tool_definitions
ATTACK_TOOLS=promptfoo # or `ares,promptfoo`, or `none`Confirm it resolved: smith --flag get_current_agent should print the
target_agent path and the resolved guidance file.
4. Adversarial tooling (optional — needed only for red-team coverage; set
ATTACK_TOOLS=none to skip)
npm install -g promptfoo
export PROMPTFOO_DISABLE_TELEMETRY=1
export PROMPTFOO_DISABLE_REDTEAM_REMOTE_GENERATION=true
export PROMPTFOO_DISABLE_SHARING=trueARES installs under src/smith/test_generation/ares/ in its own venv:
cd src/smith/test_generation/ares
python -m venv .venv && source .venv/bin/activate
curl https://raw.githubusercontent.com/IBM/ares/refs/heads/main/install.sh | bash
ares install-plugin ares-autodan
ares install-plugin ares-human-jailbreak
ares install-plugin ares-garak
cp ../ares_config/qwen-owasp-llm-01.yaml ./example_configs
cp ../ares_config/human_jailbreaks.json ./assets
export ARES_HOME=/absolute/path/to/smith/src/smith/test_generation/ares
deactivate && cd ../../../../ && source .venv/bin/activate5. Start the target agent and OPA
cd examples/hr-agent
pip install -r requirements.txt
ollama pull qwen3.5 # the example's local model
uvicorn server:app --host 0.0.0.0 --port 9100 & # MCP server (own terminal)
uvicorn agent:app --host 0.0.0.0 --port 9000 & # the agent (own terminal)6. Start Claude Code
# From `<workspace>` (not the skill directory — that's where `/smith` resolves)
claude --model "model name" # claude codeThese prompts are optional, you can run all of them, or run each independantly to test a specific part.
When running a prompt, at the end, it should prompt you next steps as well.
| # | Prompt | Check it passed |
|---|---|---|
| 1 | /smith create an opa policy for target agent |
assets/policy.rego is non-empty and make lint-policy is clean, remember to check if the generated policy makes sense. |
| 2 | /smith generate test cases, generate both guidance targeted cases and policy bypass cases |
references/test_cases/allow/ and .../disallow/ are populated (adversarial cases land in disallow/ as promptfoo_test_case*.json / bypass_test_case*.json); the CLI names which attack tools ran vs were skipped. It equals to smith --flag test_generation and smith --flag bypass_case_generation |
| 3 | /smith translate test cases |
the cases carry an input.args envelope resolved via the agent's /extract_tool_call. It equals to smith --flag test_case_translation |
| 4 | /smith test my policy |
`FP/FN listed, and seems reasonable (test case number is larger than 0, some tests pass, and some might fail.) |
| 5 | /smith cross validate checking test cases |
cross validation results seem reasonable |
| 6 | /smith patch the failed test cases |
policy edited; the final result shows fewer failures and no new ones, and fixing processes/reasons are reasonable |
| 7 | /smith get regal suggestions and fix the problems |
The suggestions and fixing seems reasonable, FP and FN are not changed |
| 8 | /smith get duplication suggestions and fix the problems |
The suggestions and fixing seems reasonable, FP and FN are not changed |
| 9 | /smith test my policy |
final scorecard: failures at or below step 4's, total cases not reduced |
There are three kinds of prose in this repo, and they are maintained differently:
- The Hugo site,
docs/content/docs/— published to https://IBM.github.io/smith/ by.github/workflows/docs-deploy.yamlon every push tomainthat touchesdocs/**. One page per workflow stage, ordered by theweight:in each page's front matter. Images go indocs/static/images/and are referenced by relative path. Build it locally withhugo serverfromdocs/before pushing;docs/public/anddocs/resources/are build output — don't hand-edit them. - The skill guides,
SKILL.mdand the markdown underopa_policy//test_generation/— these are executable in the sense that an agent follows them literally. Changing them changes behavior, so they get validated by an end-to-end run (see above), not just proofread. - The root documents —
README.md, this file,CLAUDE.md. Note thatdocs/content/docs/contributing.mddeliberately summarizes and links to this file rather than duplicating it; if you change the commands here, keep that page's command list in step.
We keep a CHANGELOG.md in the
Keep a Changelog format. When your change
is user-visible — a new feature, a behavior change, a deprecation/removal, a bug
fix, or a security fix — add an entry under the ## [Unreleased] section in the
appropriate group (Added, Changed, Deprecated, Removed,
Fixed, Security). Maintainers promote the Unreleased entries under a new
dated version heading when cutting a release tag.
Contributions are accepted under the Developer Certificate of Origin (DCO) 1.1. Sign off every commit to certify you wrote the patch or otherwise have the right to submit it under the project's license:
git commit -sThis adds a Signed-off-by trailer:
Signed-off-by: Jane Doe <jane.doe@example.com>
Do not report security vulnerabilities through public issues or PRs. See SECURITY.md for private disclosure via GitHub's vulnerability reporting.
Connect with us through the issue tracker.