This guide walks you through adding new detections to Dev Machine Guard. Whether it is a new IDE, AI CLI tool, AI agent, or MCP config source, the process follows a consistent pattern.
Back to README | See also: SCAN_COVERAGE.md | CONTRIBUTING.md
Dev Machine Guard uses array-driven detection. Each detection category has a function that iterates over a defined array of entries. To add a new detection, you add an entry to the appropriate array and (optionally) handle any special cases.
The detection code lives in the internal/detector/ directory, with each detector category in its own .go file.
"App Name|type_id|Vendor|/Applications/App.app|Contents/MacOS/binary|--version"
| Field | Description |
|---|---|
| App Name | Human-readable display name (e.g., "Visual Studio Code") |
| type_id | Unique identifier for the IDE type, used in JSON output (e.g., vscode, cursor, zed) |
| Vendor | The company or organization that makes the app (e.g., "Microsoft", "Cursor") |
| App path | Full path to the .app bundle in /Applications/ |
| Binary path | Relative path (from the app bundle root) to the binary used for version extraction. Leave empty if version comes from Info.plist. |
| Version command | The CLI flag to get the version (e.g., --version). Leave empty if not applicable. |
Find the apps array inside the IDE detector and add:
{
Name: "CodeForge",
TypeID: "codeforge",
Vendor: "CodeForge Inc",
AppPath: "/Applications/CodeForge.app",
BinaryPath: "Contents/MacOS/CodeForge",
VersionCommand: "--version",
}If the app stores its version in Info.plist instead of a CLI binary, leave the binary path and version command empty. The scanner will automatically fall back to reading CFBundleShortVersionString from Info.plist.
"tool-name|Vendor|binary1,binary2|~/.config-dir1,~/.config-dir2"
| Field | Description |
|---|---|
| tool-name | Unique name for the tool, used in JSON output (e.g., claude-code, codex) |
| Vendor | The company or organization (e.g., "Anthropic", "OpenAI", "OpenSource") |
| binary_names | Comma-separated list of binary names to search for in PATH |
| config_dirs | Comma-separated list of config directory paths (use ~ for home directory) |
{
Name: "devpilot",
Vendor: "DevPilot Inc",
Binaries: []string{"devpilot", "dp"},
ConfigDirs: []string{"~/.devpilot", "~/.config/devpilot"},
}The scanner will:
- Check if
devpilotordpexists in the user's PATH - If found, run
devpilot --version(ordp --version) to get the version - Check if
~/.devpilotor~/.config/devpilotexists as a config directory
"agent-name|Vendor|/detection/path1,/detection/path2|binary1,binary2"
| Field | Description |
|---|---|
| agent-name | Unique name for the agent (e.g., openclaw, gpt-engineer) |
| Vendor | The company or organization (e.g., "OpenSource", "Anthropic") |
| detection_paths | Comma-separated paths (directories or files) that indicate the agent is installed |
| binary_names | Comma-separated binary names for version extraction |
{
Name: "autodev",
Vendor: "AutoDev Inc",
DetectionPaths: []string{"~/.autodev"},
Binaries: []string{"autodev"},
}The scanner will:
- Check if
~/.autodevexists (directory or file) - If not found, check if
autodevbinary exists in PATH - If found either way, try to run
autodev --versionfor version info
"source_name|/path/to/config.json|Vendor"
| Field | Description |
|---|---|
| source_name | Unique identifier for the source (e.g., claude_desktop, cursor) |
| config_path | Full path to the config file. Use ~ for the home directory. |
| Vendor | The company or organization (e.g., "Anthropic", "Cursor") |
{
Source: "codeassist",
ConfigPath: "~/.codeassist/mcp_config.json",
Vendor: "CodeAssist Inc",
}The scanner will:
- Check if the config file exists at the specified path
- Read the file contents
- In enterprise mode: filter to extract only server names and commands, then base64-encode
- In community mode: display the server information locally
After making changes, build and test locally with all three output formats:
# Build the binary
make build
# Pretty output with progress messages
./stepsecurity-dev-machine-guard --verbose
# JSON output (validate it is well-formed)
./stepsecurity-dev-machine-guard --json | python3 -m json.tool
# HTML report
./stepsecurity-dev-machine-guard --html test-report.htmlThe CI pipeline runs golangci-lint and tests on every PR. Run them locally before submitting:
make lint
make test
make smoke- If possible, install the tool you are adding detection for.
- Run the scanner with
--verboseto see progress messages. - Look for "Found: [your-tool-name]" in the progress output.
- Verify the tool appears in the correct section of the output.
You can still verify your detection is correct by:
- Creating a test directory or dummy binary that matches the detection path
- Running the scanner against it
- Cleaning up after testing
After adding a new detection, update the following:
- SCAN_COVERAGE.md -- add your new detection to the appropriate table
- README.md -- update the "What It Detects" table if applicable
- Fork the repository
- Create a feature branch:
git checkout -b add-detection-codeforge - Make your changes
- Test locally (all three output formats)
- Run
make lintandmake test - Submit a PR using the PR template
See CONTRIBUTING.md for full contribution guidelines.