Canop/bacon
background code checker
Single-maintainer risk — review before adopting
weakest axiscopyleft license (AGPL-3.0) — review compatibility; no CI workflows detected
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 3w ago
- ✓10 active contributors
- ✓AGPL-3.0 licensed
Show all 7 evidence items →Show less
- ✓Tests present
- ⚠Single-maintainer risk — top contributor 81% of recent commits
- ⚠AGPL-3.0 is copyleft — check downstream compatibility
- ⚠No CI workflows detected
What would change the summary?
- →Use as dependency Concerns → Mixed if: relicense under MIT/Apache-2.0 (rare for established libs)
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/canop/bacon)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/canop/bacon on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: Canop/bacon
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/Canop/bacon shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Single-maintainer risk — review before adopting
- Last commit 3w ago
- 10 active contributors
- AGPL-3.0 licensed
- Tests present
- ⚠ Single-maintainer risk — top contributor 81% of recent commits
- ⚠ AGPL-3.0 is copyleft — check downstream compatibility
- ⚠ No CI workflows detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live Canop/bacon
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/Canop/bacon.
What it runs against: a local clone of Canop/bacon — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in Canop/bacon | Confirms the artifact applies here, not a fork |
| 2 | License is still AGPL-3.0 | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 53 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of Canop/bacon. If you don't
# have one yet, run these first:
#
# git clone https://github.com/Canop/bacon.git
# cd bacon
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of Canop/bacon and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "Canop/bacon(\\.git)?\\b" \\
&& ok "origin remote is Canop/bacon" \\
|| miss "origin remote is not Canop/bacon (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(AGPL-3\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"AGPL-3\\.0\"" package.json 2>/dev/null) \\
&& ok "license is AGPL-3.0" \\
|| miss "license drift — was AGPL-3.0 at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "src/main.rs" \\
&& ok "src/main.rs" \\
|| miss "missing critical file: src/main.rs"
test -f "src/analysis/analyzer.rs" \\
&& ok "src/analysis/analyzer.rs" \\
|| miss "missing critical file: src/analysis/analyzer.rs"
test -f "src/exec/executor.rs" \\
&& ok "src/exec/executor.rs" \\
|| miss "missing critical file: src/exec/executor.rs"
test -f "src/conf/config.rs" \\
&& ok "src/conf/config.rs" \\
|| miss "missing critical file: src/conf/config.rs"
test -f "src/analysis/standard/standard_line_analyser.rs" \\
&& ok "src/analysis/standard/standard_line_analyser.rs" \\
|| miss "missing critical file: src/analysis/standard/standard_line_analyser.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 53 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~23d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/Canop/bacon"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Bacon is a background code checker for Rust projects that runs cargo check, cargo clippy, cargo test, and custom commands in watch mode, displaying compilation errors, warnings, and test failures in a real-time terminal UI without requiring user interaction. It's designed to sit alongside your editor and notify you of issues as you code, with configurable jobs defined in bacon.toml. Single-crate monolith with src/analysis/ containing language-specific analyzers (analyzer.rs as base, cargo_json/, eslint/, biome/, cpp.rs, go.rs for different toolchains), core logic likely in root src/, configuration handling in bacon.json/bacon.toml, and resources/ containing alert sounds (mp3 files). Default configs in defaults/ directory.
👥Who it's for
Rust developers who want continuous compilation feedback while editing, without manually running cargo commands or managing separate terminal windows. Particularly useful for developers working on large codebases who benefit from passive notification of errors and test failures.
🌱Maturity & risk
Actively maintained and production-ready. Version 3.22.0 with comprehensive documentation at https://dystroy.org/bacon, Cargo.lock committed, test presence in repo, clear feature gates (clipboard, sound), and AGPL-3.0 licensing. The repository is mature with backward-compatible configuration across versions.
Low risk: single maintainer (dystroy) is a known ecosystem contributor, but repo shows stable API with mature dependencies (cargo_metadata, notify, serde) and no signs of abandonment. Moderate dependency count (~20 direct) but all well-established crates. AGPL-3.0 licensing may restrict commercial use without redistribution of modifications.
Active areas of work
Currently at v3.22.0 with support for multiple language analyzers (Biome, ESLint, Go, C++), clipboard and sound optional features, and customizable job definitions. The repo structure shows recent work on language-specific analysis pipelines (biome/ and eslint/ subdirectories with mod.rs files) and cargo JSON export functionality.
🚀Get running
git clone https://github.com/Canop/bacon.git
cd bacon
cargo install --locked --path .
# Or with optional features:
cargo install --locked --features "clipboard sound" --path .
bacon
Daily commands:
# Development build
cargo build
# Run against current project
./target/debug/bacon
# Run against another project
./target/debug/bacon --path ../other-project
# Create config template
./target/debug/bacon --init
# Run specific job
./target/debug/bacon clippy
🗺️Map of the codebase
src/main.rs— Entry point for the bacon application; orchestrates the main event loop and CLI initializationsrc/analysis/analyzer.rs— Core abstraction for pluggable language/tool analyzers; defines how different compilers and linters are parsedsrc/exec/executor.rs— Manages background task execution and on-change re-triggering; central to bacon's watch behaviorsrc/conf/config.rs— Configuration loading and merging; critical for understanding how bacon.toml and defaults are appliedsrc/analysis/standard/standard_line_analyser.rs— Rust compiler output parser; handles the majority of bacon's core functionality for Rust projectssrc/burp/mod.rs— TUI rendering and state management; visualizes analysis results and handles user interaction
🧩Components & responsibilities
- Executor (src/exec/executor.rs) (std::process::Command, crossbeam channels, debounce timers) — Spawns and manages background cargo/compiler processes; handles debouncing and output streaming
- Failure mode: Process hangs or output capture fails → user sees stale results or no updates
- Analyzer (src/analysis/analyzer.rs) (LineAnalyzer trait, regex-based parsing, JSON parsing (cargo_metadata)) — Dispatches to language-specific parsers; aggregates errors, warnings, and test results
- Failure mode: Parser regex mismatch or unhandled output format → errors/warnings not detected or wrong line numbers reported
- Config Manager (src/conf/config.rs) (toml crate, serde deserialization, directory-next for config paths) — Loads TOML, merges defaults with user config, validates keybindings and actions
- Failure mode: Malformed TOML or missing defaults → application fails to start or uses wrong job configurations
- TUI Layer (src/burp/mod.rs) (crossterm or termion, stateful widget layout, event polling) — Renders analysis results, handles keyboard input, dispatches actions
- Failure mode: Rendering lag under heavy output or input loss → user interaction feels unresponsive
🔀Data flow
File System (Watcher)→Executor— File change event triggers re-execution of jobs- `` →
undefined— undefined
🛠️How to make changes
Add a new language analyzer
- Create a new module under src/analysis/ (e.g., src/analysis/mylang/mod.rs) (
src/analysis/mylang/mod.rs) - Implement the LineAnalyzer trait to parse your language's tool output (
src/analysis/line_analyzer.rs) - Register the analyzer in src/analysis/analyzer.rs dispatcher (
src/analysis/analyzer.rs) - Add default job configuration in defaults/default-bacon.toml (
defaults/default-bacon.toml)
Add a new keybinding and action
- Define the action variant in src/conf/action.rs (
src/conf/action.rs) - Add keybinding mapping in src/conf/keybindings.rs (
src/conf/keybindings.rs) - Implement action handler in src/burp/mod.rs event dispatch (
src/burp/mod.rs) - Add help text in src/help/help_page.rs (
src/help/help_page.rs)
Add a new job type or command execution strategy
- Extend src/exec/task.rs with new task configuration fields (
src/exec/task.rs) - Update src/exec/command_builder.rs to handle new variable substitutions (
src/exec/command_builder.rs) - Configure defaults in defaults/default-bacon.toml (
defaults/default-bacon.toml)
🔧Why these technologies
- Rust + Cargo — bacon is designed to augment Rust development; native integration with cargo and rustc for parsing and re-execution
- File watcher (inotify on Linux, FSEvents on macOS) — Low-overhead background monitoring of source changes without polling; matches bacon's minimal-overhead design philosophy
- Crossterm / termion (TUI) — Cross-platform terminal rendering and keyboard input handling for real-time interactive feedback
- TOML configuration — Human-readable, simple syntax for users to customize jobs, keybindings, and analyzer behavior without complex parsing
⚖️Trade-offs already made
-
Single-threaded event loop with spawned subprocesses rather than full async runtime
- Why: Keeps dependencies light and startup fast; bacon is a watch tool, not a server
- Consequence: Simpler code and faster startup, but less fine-grained concurrency for very heavy workloads
-
Line-by-line output parsing rather than full AST analysis
- Why: Works with any compiler/linter output format without custom plugins; minimal parsing overhead
- Consequence: Some false positives or parsing edge cases possible; good enough for real-time feedback
-
Optional sound and clipboard features (behind feature flags)
- Why: Keeps core minimal and reduces external dependencies; allows users to opt-in to desktop integrations
- Consequence: Users must rebuild with features if they want audio alerts or clipboard copy
🚫Non-goals (don't propose these)
- Real-time network collaboration or remote execution
- Full IDE integration (bacon is a standalone watch tool, not a plugin)
- Language-agnostic static analysis (uses existing compiler/linter output, not custom AST parsing)
- Persistent result storage or historical analysis trends
🪤Traps & gotchas
Feature flags required at compile time: clipboard and sound are optional and disabled by default (rustup default doesn't include them), so cargo install bacon won't have copy/audio. Config backward compatibility assumption: bacon.toml format is promised to be backward compatible, but bacon.json may have breaking changes not captured in defaults. Analyzer matching: each language analyzer (biome, eslint, cargo_json) must parse its own output format precisely; regex-based parsing is fragile if tool output changes. Terminal state: bacon uses VTE for parsing ANSI sequences; full terminal emulation context may be required for accurate color/cursor tracking.
🏗️Architecture
💡Concepts to learn
- VTE (Virtual Terminal Emulator) parsing — Bacon uses the
vtecrate to parse ANSI escape sequences from compiler output to extract colors, cursors, and styled text from raw terminal streams - File system watching (inotify/FSEvents) — Core to bacon's design: the
notifycrate abstracts platform-specific file change detection (inotify on Linux, FSEvents on macOS) to trigger re-runs without polling - JSON Lines (JSONL) structured logging — Cargo's
--message-format=jsonoutputs one JSON object per line; bacon'scargo_json_export.rsparses this format to extract compiler diagnostics reliably - Lexical analysis of compiler error output — The
line_analysis.rsmodule regex-parses unstructured compiler output from multiple languages to extract file, line, column, and message; fragile but necessary for tools without JSON output - Terminal User Interface (TUI) with termimad — Bacon uses
termimadfor rendering markdown-like formatting directly to the terminal, displaying errors with colors and layout without a full TUI framework - AGPL-3.0 copyleft licensing — Bacon's license requires redistribution of modifications if deployed (e.g., in CI/CD); proprietary tools may need special licensing agreements
- Glob patterns for selective file watching — The
watchfield in bacon job configs uses glob patterns to exclude/include directories (e.g., watching onlyexamples/for an examples job); theglobcrate handles this
🔗Related repos
rust-lang/rust— Provides the Rust compiler and error message formats that bacon parses; understanding compiler output structure is essentialwatchexec/watchexec— Alternative file-watching tool for re-running commands; bacon's notify-based watching competes with thiscargo-watch/cargo-watch— Predecessor/competitor that runscargo checkon file changes; bacon improves on this with better UI and job abstractionEmbarkStudios/rust-gpu— Example user of bacon as a background checker for non-standard Rust compilation targetsbiomejs/biome— Linter/formatter integrated into bacon's analysis pipeline (src/analysis/biome/); understanding Biome's JSON output is needed to maintain that analyzer
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive unit tests for src/analysis/line_analyzer.rs and src/analysis/line_type.rs
The line analysis modules are critical for parsing compiler/linter output across multiple languages (Rust, Python, Go, C++, Swift, etc.). Currently there's no dedicated test file visible for these core parsing modules. Adding tests would catch regressions when adding support for new languages or output formats, and serve as documentation for the expected behavior of each language's line parser.
- [ ] Create src/analysis/tests/line_analyzer_tests.rs with test cases for each supported language (Rust cargo, Python pytest/ruff, Go, C++, Swift)
- [ ] Create src/analysis/tests/line_type_tests.rs testing all LineType variants and their detection logic
- [ ] Add representative sample outputs from each language's compiler/linter to use as test fixtures
- [ ] Ensure tests cover edge cases like multiline errors and warnings with different severity levels
Add GitHub Actions workflow for multi-platform testing (Linux, macOS, Windows)
The repo has .github/FUNDING.yml but no CI workflow files visible. Given that bacon supports multiple OS platforms (uses notify, crokey, platform-specific path handling) and integrates with various language toolchains, automated testing across platforms would catch OS-specific bugs early. This is especially important for features like keyboard input (crokey) and file watching (notify).
- [ ] Create .github/workflows/ci.yml to run 'cargo test --all' on Linux, macOS, and Windows
- [ ] Add 'cargo clippy' linting checks in the workflow
- [ ] Add 'cargo fmt --check' to enforce code style (rustfmt.toml exists but no CI enforcement)
- [ ] Test with features: default, clipboard, sound, and combinations thereof
Refactor src/analysis/ into a proper plugin system with per-language modules
The analysis directory currently has ad-hoc language support (biome/, cargo_json/, eslint/, python/, swift/, go.rs, cpp.rs). This makes it hard to add new language support. Creating a trait-based plugin system with consistent interfaces would reduce code duplication (many modules have similar line_analyser.rs patterns) and make the codebase more maintainable for contributors wanting to add language support.
- [ ] Create src/analysis/language_analyzer.rs defining a LanguageAnalyzer trait with parse() and format_line() methods
- [ ] Refactor src/analysis/standard/, src/analysis/python/, src/analysis/swift/ to implement this trait consistently
- [ ] Create a registry in src/analysis/mod.rs that auto-discovers and registers analyzers
- [ ] Add a CONTRIBUTING.md section documenting how to add a new language analyzer using the plugin pattern
🌿Good first issues
- Add missing documentation or examples for the
watchfield in job definitions (visible in README but not clearly documented for all use cases in bacon.toml) - Write integration tests for
src/analysis/line_analysis.rscovering edge cases in error line parsing across different Rust compiler versions (tests likely missing given no tests/ directory in file list) - Implement support for Python linters (pylint, flake8) by creating
src/analysis/python.rsfollowing the pattern ofsrc/analysis/go.rsandsrc/analysis/cpp.rs, opening bacon to non-Rust projects
⭐Top contributors
Click to expand
Top contributors
- @Canop — 81 commits
- @cehteh — 6 commits
- @alerque — 4 commits
- @narpfel — 3 commits
- @faultymajority — 1 commits
📝Recent commits
Click to expand
Recent commits
2d81921— add /** to ignored patterns (#440) (Canop)5925551— web doc: explain--config-tomlarg in config page (Canop)d7f37d5— fix logo link (Canop)d3e3194— website now leverages ddoc plugins (Canop)20a4b72— website: insist on the use of log (Canop)f91c050— remove default keybinding 'p'->'job:pedantic' (Canop)6d99911— update changelog (Canop)553776c— show_command_error_code job parameter (#436) (Canop)bd0243c— website: fix clippy lint example (Canop)d625921— fix copy-paste miss (#433) (cehteh)
🔒Security observations
The bacon project demonstrates generally good security posture. It is a well-maintained Rust tool with limited external dependencies and no obvious injection vulnerabilities or hardcoded secrets. Primary concerns are AGPL-3.0 license compliance requirements, optional dependency version pinning, and ensuring configuration validation is properly implemented. The codebase shows no exposed credentials, SQL injection risks, or infrastructure misconfigurations. Recommended improvements include adding cargo-audit to CI/CD, documenting audio file provenance, and ensuring input validation throughout configuration handling.
- Medium · AGPL-3.0 License Compliance Risk —
Cargo.toml, LICENSE. The project is licensed under AGPL-3.0, which requires that any modifications or derivatives must also be open-sourced under the same license. This can create legal risks if the software is modified and used in proprietary contexts without proper compliance. Fix: Ensure proper license compliance documentation. Consider adding COPYING file and license headers to source files. Document any derivative works appropriately. - Low · Optional Dependencies Not Pinned to Specific Versions —
Cargo.toml - dependencies: arboard, rodio. Optional dependencies like 'arboard' and 'rodio' use semver ranges without explicit feature restrictions. While this is acceptable, it increases attack surface if a compromised version is released. Fix: Consider using=versionfor exact pinning in security-sensitive contexts, or add dependency auditing to CI/CD pipeline using 'cargo-audit'. - Low · Patch Crates-io Section Commented Out —
Cargo.toml - [patch.crates-io]. The [patch.crates-io] section contains commented-out local path overrides. If these are re-enabled without proper version control, they could introduce unexpected behavior or allow local path traversal attacks. Fix: Remove commented code or document why it exists. If local patches are needed, ensure they're version-controlled and reviewed. Use explicit version constraints. - Low · Audio Resources with Unclear Provenance —
resources/*.mp3 files. The resources/audio files (MP3s) lack documentation regarding licensing and provenance. Audio files can potentially contain embedded malware or license violations. Fix: Add a comprehensive README in resources/ documenting source, license, and integrity checksums (SHA256) for all audio files. Consider verifying file integrity at runtime. - Low · No Input Validation Configuration Visible —
src/conf/ directory, configuration parsing logic. Configuration files (bacon.toml, bacon.json) are parsed without visible validation schemas. User-provided configurations could potentially cause issues if not properly validated. Fix: Ensure all configuration parsing uses schemars for validation. Implement strict input validation for all user-provided configuration values.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.