Skip to content

docs: Improve README, CLI UX, and documentation accuracy#147

Merged
unclesp1d3r merged 19 commits intomainfrom
updated_readme
Mar 16, 2026
Merged

docs: Improve README, CLI UX, and documentation accuracy#147
unclesp1d3r merged 19 commits intomainfrom
updated_readme

Conversation

@unclesp1d3r
Copy link
Member

@unclesp1d3r unclesp1d3r commented Mar 16, 2026

Summary

Overhaul user-facing documentation and CLI polish. Rewrites README with badges and user-focused structure, fixes stale docs (wrong MSRV, fictional CLI flags, incorrect exit codes), improves CLI UX from review findings, and simplifies Mergify merge queue config.

20 files changed (452 additions, 633 deletions -- net reduction of 181 lines)

What changed

README rewrite

  • Badge rows with link references at bottom (license, sponsors, CI, deps, codecov, issues, last commit, scorecard) -- all flat-square, modeled after libmagic-rs/dbsurveyor
  • User-focused structure: Quick Start and Usage before contributor content
  • Merged duplicate Features sections, removed "Problem with strings" / "Advantages Over" redundancy
  • Added stdin support example, release verification, Security section

Documentation fixes

  • docs/src/installation.md: Fixed MSRV from 1.70 to 1.91, removed fictional Docker section, added Releases page link, added just dev workflow
  • docs/src/performance.md: Complete rewrite -- removed 20+ fictional CLI flags (--mmap-threshold, --no-mmap, --sections, --timing, --no-classify, etc.), fictional env vars (STRINGY_MAX_MEMORY, STRINGY_THREADS), and fictional config format
  • docs/src/cli.md: Fixed exit codes from 0/1/2 to 0/1/2/3/4 matching StringyError::exit_code()
  • docs/src/quickstart.md: Added 4 missing tags to semantic tags table (demangled, version, manifest, resource) -- now covers all 21 tags

CLI improvements (from /cli-review)

  • Removed -e short flag from --enc (infrequent flag per GOTCHAS.md convention)
  • Added EXIT CODES section to --help output (0=success, 1=general, 2=config, 3=not found, 4=permission denied)
  • Converted cli_encoding_to_filter() to impl From<CliEncoding> for EncodingFilter (idiomatic Rust)
  • Improved filter-no-match diagnostic: now suggests adjusting --min-len, --only-tags, --no-tags, or --enc

Mergify simplification

  • 3 queues: dosubot (quality only), dependabot (full CI), default (manual /queue for human PRs)
  • Removed label requirements (lgtm, do-not-merge), author restrictions, and workflow file detection
  • Auto-approve rules for both bots, keep-PRs-up-to-date rule retained

Tests (7 new tests)

  • tests/integration_cli_stdin.rs (6 tests): PE, Mach-O, unknown format, JSON output, raw mode, and filtered mode via stdin
  • tests/integration_cli.rs: exit codes help text validation
  • tests/integration_flow8_diagnostics.rs: tightened filter-no-match assertion to verify hint text

Tooling config

  • Tessl MCP server configuration and skill files
  • .gitignore for tessl-generated files

Breaking changes

-e short flag removed: Scripts using stringy -e ascii must change to stringy --enc ascii. The long form --enc is unchanged.

Test plan

  • cargo nextest run -- 617 passed, 0 failed, 23 skipped
  • cargo clippy --all-targets --all-features -- -D warnings -- clean
  • cargo fmt --all -- --check -- clean
  • just ci-check -- all stages pass (pre-commit, fmt, clippy, tests, coverage, dist plan)
  • Verify badges render correctly on GitHub after merge
  • Verify stringy --help shows EXIT CODES section
  • Verify --enc no longer accepts -e short form

…-approval

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…and usage sections

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…ne run

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…ormatting

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
… CLI documentation

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…classifications and examples

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Copilot AI review requested due to automatic review settings March 16, 2026 05:05
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 16, 2026

📝 Walkthrough

Architectural Impact

Trait-based Encoding Conversion: Refactored CLI encoding argument handling by introducing a CliEncoding type and implementing From<CliEncoding> for EncodingFilter, replacing the standalone cli_encoding_to_filter() function. This shifts encoding filter creation from an imperative function call to a trait-based conversion pattern, improving type safety and composability.

Diagnostic Signal Enhancement: Updated the "no strings matched" diagnostic to provide actionable guidance (adjusting --min-len, --only-tags, --no-tags, or --enc), improving the filtering feedback loop without changing core behavior.

API Changes (Breaking)

Removed -e Short Flag: The short flag alias for --enc has been removed (breaking change). Scripts and tooling using -e must migrate to the --enc long form. All internal tests and documentation updated accordingly.

EXIT CODES Standardization: Expanded and corrected exit code scheme from 2-code to 4-code model:

  • 0: Success
  • 1: General runtime error
  • 2: Configuration/validation error (tag overlap, invalid output mode)
  • 3: File not found
  • 4: Permission denied

Explicit documentation added to --help output and CLI documentation.

Binary Format and Semantic Classification Improvements

stdin Support with Format Diversity: Comprehensive test coverage added (6 integration tests in tests/integration_cli_stdin.rs) validating parsing of PE, Mach-O, ELF, and unknown binary formats via stdin, with graceful fallback behavior on cross-platform scenarios.

Semantic Tag Completeness: Expanded semantic tag set from 17 to 21 tags by adding demangled, version, manifest, and resource, ensuring complete semantic classification coverage in quick-start documentation.

Documentation Corrections (Accuracy)

Removed Fictional Content: Corrected stale documentation by eliminating 20+ fictional CLI flags, fictional environment variables, fictional config formats, and a non-existent Docker section.

MSRV Correction: Updated minimum supported Rust version from 1.70 to 1.91 in installation documentation.

Performance Documentation Rewrite: Replaced 355 lines of vague performance metrics with targeted prose describing the single-threaded sequential pipeline, Big-O complexity phases, and practical CLI narrowing strategies for optimization.

Testing Additions

Added 7 new integration tests targeting stdin handling (PE, Mach-O, ELF, JSON output, raw mode, filtered mode), exit code validation, and diagnostic message accuracy. All 617 existing tests pass; clippy and fmt checks clean.

Configuration Tooling

Mergify configuration simplified from complex label/author/workflow detection to three streamlined queues (dosubot, dependabot, default) with unified auto-approval rules for bot PRs. Tessl MCP server configuration added across multiple IDE/tool config files (.cursor/mcp.json, .gemini/settings.json, .mcp.json, .codex/config.toml) for AI-assisted development support.

Walkthrough

Adds tessl MCP server entries across multiple config formats, removes the -e short CLI flag in favor of a new CliEncoding type with From conversion, restructures Mergify rules for dependabot/dosubot, updates docs and tests (stdin and help/diagnostics), and adds vendored tessl.json dependency metadata.

Changes

Cohort / File(s) Summary
MCP Server Configuration
.codex/config.toml, .cursor/mcp.json, .gemini/settings.json, .mcp.json
Added tessl MCP server definitions (type = "stdio", command = "tessl", args = ["mcp","start"]) across TOML/JSON config files.
Git Ignore
.gitignore
Added tessl-generated ignore patterns: **/tessl__*, .tessl/tiles/.
CI/CD Automation
.mergify.yml
Reworked queue_rules and pull_request_rules: added dosubot and dependabot queues, auto-approve rules for bots, and author-based exclusions in default queue and CI protections.
CLI Encoding Refactor
src/main.rs, AGENTS.md, GOTCHAS.md, tests/integration_cli_short_flags.rs, tests/integration_cli.rs
Introduced CliEncoding and impl From<CliEncoding> for EncodingFilter; removed -e short flag (now --enc only); updated help text, docs, and tests to reflect the change.
Diagnostics & Tests
src/pipeline/mod.rs, tests/integration_flow8_diagnostics.rs
Expanded "no strings matched" informational message to suggest adjusting --min-len, --only-tags, --no-tags, or --enc; updated tests to assert new guidance text.
Integration Stdin Tests
tests/integration_cli_stdin.rs
Added extensive stdin-focused integration tests (PE, Mach-O, ELF, unknown input) covering JSON/raw modes and filter flags.
Documentation Restructuring
README.md, docs/src/cli.md, docs/src/installation.md, docs/src/performance.md, docs/src/quickstart.md
Overhauled README and docs: condensed onboarding, explicit 4-code exit scheme (1 runtime, 2 validation, 3 not found, 4 permission), streamlined install, replaced detailed perf tuning with pipeline overview, expanded tags table.
Vendored Skills Config
tessl.json
Added vendored tessl.json declaring actionbook/rust-skills dependency with included skill list for Rust tooling/analysis topics.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🧵 Tessl wakes and speaks through stdio,
Flags trimmed down where enc will go,
Bots approved and tests run true,
Docs polished, pipelines too—hooroo! 🚀

🚥 Pre-merge checks | ✅ 5 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Title check ⚠️ Warning Title follows Conventional Commits format with valid type (docs) and scope (missing scope requirement). Add a scope from the allowed list (e.g., cli, docs). Example: 'docs(cli): Improve README, CLI UX, and documentation accuracy' or split into multiple commits with specific scopes.
File Size Limit ⚠️ Warning src/pipeline/mod.rs exceeds 500-line limit at 533 lines, violating project file size guidelines. Refactor src/pipeline/mod.rs by extracting functionality into separate submodules to reduce main module size below 500 lines.
Section Weight Consistency ❓ Inconclusive Cannot evaluate section weight consistency without actual PR changes or git repository context. Provide the actual git diff output or specific files modified in the pull request to assess container parser modifications.
✅ Passed checks (5 passed)
Check name Status Explanation
Description check ✅ Passed Description is detailed and directly related to the changeset, covering README rewrites, documentation fixes, CLI improvements, Mergify config changes, and test additions.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 70.00%.
No Unsafe Code ✅ Passed Pull request maintains strict unsafe-code safety standards with #![forbid(unsafe_code)] directives in both crate entry points and zero unsafe code blocks detected across all modifications.
Error Handling ✅ Passed All runtime errors wrapped in StringyError variants with contextual messages; external errors mapped via #[from] or explicit constructors; no raw-string errors or unchecked unwraps outside Clap parser.
Ascii Only ✅ Passed Python-based UTF-8 analysis confirmed all modified files contain only ASCII characters or valid UTF-8 sequences with no problematic non-ASCII punctuation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch updated_readme
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

@mergify
Copy link
Contributor

mergify bot commented Mar 16, 2026

Merge Protections

Your pull request matches the following merge protections and will not be merged until they are valid.

🟢 📃 Configuration Change Requirements

Wonderful, this rule succeeded.

Mergify configuration change

  • check-success = Configuration changed

🟢 Enforce conventional commit

Wonderful, this rule succeeded.

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert)(?:\(.+\))?:

🟢 CI must pass

Wonderful, this rule succeeded.

All CI checks must pass. This protection prevents manual merges that bypass the merge queue.

  • check-success = coverage
  • check-success = msrv (stable minus 1 releases)
  • check-success = msrv (stable minus 2 releases)
  • check-success = msrv (stable minus 3 releases)
  • check-success = msrv (stable minus 4 releases)
  • check-success = msrv (stable)
  • check-success = quality
  • check-success = test
  • check-success = test-cross-platform (macos-latest, macOS)
  • check-success = test-cross-platform (ubuntu-latest, Linux)
  • check-success = test-cross-platform (windows-latest, Windows)

🟢 Do not merge outdated PRs

Wonderful, this rule succeeded.

Make sure PRs are within 10 commits of the base branch before merging

  • #commits-behind <= 10

@coderabbitai coderabbitai bot added documentation Improvements or additions to documentation enhancement New feature or request labels Mar 16, 2026
@unclesp1d3r unclesp1d3r self-assigned this Mar 16, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves Stringy user-facing documentation and CLI ergonomics, aligning help text and docs with current behavior while adding integration tests for stdin and flag UX.

Changes:

  • Updates CLI help/error UX (exit codes in --help, --enc long-only, improved diagnostics) and adds stdin-focused integration tests.
  • Rewrites/refreshes docs (installation, performance, CLI reference, quickstart tags) and modernizes README structure/badges.
  • Simplifies Mergify configuration into bot-specific queues plus a default queue.

Reviewed changes

Copilot reviewed 19 out of 20 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/integration_cli_stdin.rs Adds stdin edge-case integration tests for multiple input types and modes.
tests/integration_cli_short_flags.rs Removes -e coverage and updates short-flag tests around --enc.
tests/integration_cli.rs Verifies --help includes an EXIT CODES: section.
tessl.json Adds Tessl configuration (vendored skill dependency list).
src/types/error.rs Adds recovery hints to selected error messages.
src/pipeline/mod.rs Improves no-filter-match diagnostic guidance.
src/main.rs Removes -e, adds exit codes to help, and refactors encoding mapping via From.
docs/src/quickstart.md Completes the semantic tag table with additional tags/examples.
docs/src/performance.md Replaces stale/fictional performance docs with current behavior and real commands.
docs/src/installation.md Updates install guidance (MSRV, releases, removes fictional Docker section).
docs/src/cli.md Aligns documented exit codes with StringyError::exit_code() and clarifies clap behavior.
README.md Restructures README with badges, quickstart, security notes, and link references.
GOTCHAS.md Updates CLI short-flag notes and clap derive limitations guidance.
AGENTS.md Updates CLI flag matrix to reflect --enc long-only.
.mergify.yml Simplifies queue rules and auto-approval for bots; adjusts protections.
.mcp.json Adds MCP server config for Tessl.
.gitignore Ignores Tessl-generated artifacts.
.gemini/settings.json Adds Tessl MCP server config for Gemini tooling.
.cursor/mcp.json Adds Tessl MCP server config for Cursor tooling.
.codex/config.toml Adds Tessl MCP server config for Codex tooling.

Comment on lines +29 to +34
stringy()
.arg("-")
.write_stdin(fixture_data)
.assert()
.success()
.stdout(predicate::str::is_empty().not());
- name: Full CI must pass
description: All CI checks must pass. This protection prevents manual merges that bypass the merge queue.
if:
- base = main
Comment on lines 124 to 128
.arg("10")
.arg("-t")
.arg("5")
.arg("-e")
.arg("--enc")
.arg("ascii")
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.mergify.yml:
- Around line 2-10: The dosubot mergify rule named "dosubot" currently allows
merging when only the "quality" check passes; update the rule to also require
the "test" check (or another full CI gate) before merge by modifying the
merge_conditions for the dosubot rule so it includes "- check-success = test" in
addition to "- check-success = quality", ensuring substantive code changes get
the full CI matrix validation.

In `@docs/src/installation.md`:
- Around line 46-49: The fenced code block containing the cargo commands is
missing a language specifier; update the opening fence from ``` to ```bash so it
reads ```bash followed by the lines "cargo build --release" and "cargo test" and
the closing ``` to satisfy the MD040 rule and enable proper syntax highlighting
in the docs.

In `@src/pipeline/mod.rs`:
- Around line 111-114: The multi-line string literal starting with "Info: No
strings matched the current filters" in src/pipeline/mod.rs is using backslash
line-continuation which preserves the next line's indentation and injects
unwanted spaces; change it to a single uninterrupted string or concatenate two
string literals without leading whitespace (or use format!/format_args! / raw
string) so the "{total_count} extracted, 0 shown" and the "Try removing ..."
sentence are printed without the extra indentation; locate the literal text and
update it (the string containing "{total_count} extracted, 0 shown" and the
following "Try removing --only-tags..." clause) to remove the embedded leading
spaces.

In `@tests/integration_cli_short_flags.rs`:
- Around line 103-114: Add a negative test to ensure the removed short flag `-e`
is rejected: create a new test (e.g., fn test_enc_short_flag_rejected()) that
uses the same helper stringy() and the same elf_path
("tests/fixtures/test_binary_elf") but passes "-e" "ascii" instead of "--enc",
then assert that the command fails (non-success) and/or returns a specific error
code or stderr message; reference the existing test function
test_enc_long_flag_only and the stringy() helper so maintainers can locate where
to add the new failing assertion.

In `@tests/integration_cli_stdin.rs`:
- Around line 13-14: Replace relative fixture reads in
tests/integration_cli_stdin.rs with manifest-rooted paths using the
CARGO_MANIFEST_DIR env macro: locate each std::fs::read call that currently uses
"tests/fixtures/..." (e.g., the fixture_data binding and the repeated reads at
the other mentioned locations) and construct the path by joining
env!("CARGO_MANIFEST_DIR") with "tests/fixtures/<filename>" before calling
std::fs::read so the tests no longer depend on the current working directory.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d291dac0-44da-43ac-b9f4-5f27148b2849

📥 Commits

Reviewing files that changed from the base of the PR and between c9a466f and eace435.

📒 Files selected for processing (20)
  • .codex/config.toml
  • .cursor/mcp.json
  • .gemini/settings.json
  • .gitignore
  • .mcp.json
  • .mergify.yml
  • AGENTS.md
  • GOTCHAS.md
  • README.md
  • docs/src/cli.md
  • docs/src/installation.md
  • docs/src/performance.md
  • docs/src/quickstart.md
  • src/main.rs
  • src/pipeline/mod.rs
  • src/types/error.rs
  • tessl.json
  • tests/integration_cli.rs
  • tests/integration_cli_short_flags.rs
  • tests/integration_cli_stdin.rs

Comment on lines 46 to 49
```bash
xcode-select --install
```

### Windows

Install Visual Studio Build Tools or Visual Studio Community with C++ support.

Alternatively, use the GNU toolchain:

```bash
rustup toolchain install stable-x86_64-pc-windows-gnu
rustup default stable-x86_64-pc-windows-gnu
```

## Docker (Alternative)

If you prefer containerized builds:

```dockerfile
FROM rust:1.70 as builder
WORKDIR /app
COPY . .
RUN cargo build --release

FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/stringy /usr/local/bin/
ENTRYPOINT ["stringy"]
```

Build and run:

```bash
docker build -t stringy .
docker run --rm -v $(pwd):/data stringy /data/binary_file
cargo build --release
cargo test
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add language specifier to fenced code block.

Static analysis flagged this code block as missing a language identifier (MD040). Adding bash improves syntax highlighting and accessibility.

Proposed fix
-```
+```bash
 cargo build --release
 cargo test

</details>

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/installation.md` around lines 46 - 49, The fenced code block
containing the cargo commands is missing a language specifier; update the
opening fence from ``` to ```bash so it reads ```bash followed by the lines
"cargo build --release" and "cargo test" and the closing ``` to satisfy the
MD040 rule and enable proper syntax highlighting in the docs.

Comment on lines +111 to 114
"Info: No strings matched the current filters \
({total_count} extracted, 0 shown)\n \
Try removing --only-tags, --no-tags, or --enc filters to see more results"
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

String continuation includes leading whitespace, producing malformed output.

The backslash line continuation in Rust string literals includes all leading whitespace from the next line. This produces output with excessive spaces:

Info: No strings matched the current filters                  (5 extracted, 0 shown)
Proposed fix
         if filtered.is_empty() && total_count > 0 {
             eprintln!(
-                "Info: No strings matched the current filters \
-                 ({total_count} extracted, 0 shown)\n  \
-                 Try removing --only-tags, --no-tags, or --enc filters to see more results"
+                "Info: No strings matched the current filters ({total_count} extracted, 0 shown)\n  \
+Try removing --only-tags, --no-tags, or --enc filters to see more results"
             );
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pipeline/mod.rs` around lines 111 - 114, The multi-line string literal
starting with "Info: No strings matched the current filters" in
src/pipeline/mod.rs is using backslash line-continuation which preserves the
next line's indentation and injects unwanted spaces; change it to a single
uninterrupted string or concatenate two string literals without leading
whitespace (or use format!/format_args! / raw string) so the "{total_count}
extracted, 0 shown" and the "Try removing ..." sentence are printed without the
extra indentation; locate the literal text and update it (the string containing
"{total_count} extracted, 0 shown" and the following "Try removing
--only-tags..." clause) to remove the embedded leading spaces.

Comment on lines +13 to +14
let fixture_data =
std::fs::read("tests/fixtures/test_binary_pe.exe").expect("PE fixture should exist");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use manifest-rooted fixture paths to avoid cwd-dependent test failures.

Line 14 and the repeated fixture reads rely on relative paths (tests/fixtures/...). This is brittle outside the default cargo test working directory.

Proposed fix
+use std::path::PathBuf;
 use assert_cmd::Command;
 use assert_cmd::cargo_bin_cmd;
 use predicates::prelude::*;
 
 fn stringy() -> Command {
     cargo_bin_cmd!("stringy")
 }
+
+fn fixture_path(name: &str) -> PathBuf {
+    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
+        .join("tests")
+        .join("fixtures")
+        .join(name)
+}
+
+fn read_fixture(name: &str, label: &str) -> Vec<u8> {
+    std::fs::read(fixture_path(name)).expect(label)
+}
@@
-    let fixture_data =
-        std::fs::read("tests/fixtures/test_binary_pe.exe").expect("PE fixture should exist");
+    let fixture_data = read_fixture("test_binary_pe.exe", "PE fixture should exist");
@@
-    let fixture_data =
-        std::fs::read("tests/fixtures/test_binary_macho").expect("Mach-O fixture should exist");
+    let fixture_data = read_fixture("test_binary_macho", "Mach-O fixture should exist");
@@
-    let fixture_data =
-        std::fs::read("tests/fixtures/test_unknown.bin").expect("unknown fixture should exist");
+    let fixture_data = read_fixture("test_unknown.bin", "unknown fixture should exist");
@@
-    let fixture_data =
-        std::fs::read("tests/fixtures/test_binary_elf").expect("ELF fixture should exist");
+    let fixture_data = read_fixture("test_binary_elf", "ELF fixture should exist");
@@
-    let fixture_data =
-        std::fs::read("tests/fixtures/test_binary_elf").expect("ELF fixture should exist");
+    let fixture_data = read_fixture("test_binary_elf", "ELF fixture should exist");
@@
-    let fixture_data =
-        std::fs::read("tests/fixtures/test_binary_elf").expect("ELF fixture should exist");
+    let fixture_data = read_fixture("test_binary_elf", "ELF fixture should exist");

As per coding guidelines, "tests/{integration_.rs,test_.rs}: Store binary test fixtures in tests/fixtures/ and reference them using env!(\"CARGO_MANIFEST_DIR\") pattern".

Also applies to: 26-27, 39-40, 52-53, 66-67, 80-81

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integration_cli_stdin.rs` around lines 13 - 14, Replace relative
fixture reads in tests/integration_cli_stdin.rs with manifest-rooted paths using
the CARGO_MANIFEST_DIR env macro: locate each std::fs::read call that currently
uses "tests/fixtures/..." (e.g., the fixture_data binding and the repeated reads
at the other mentioned locations) and construct the path by joining
env!("CARGO_MANIFEST_DIR") with "tests/fixtures/<filename>" before calling
std::fs::read so the tests no longer depend on the current working directory.

@codecov
Copy link

codecov bot commented Mar 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

…stic

- Remove recovery hints from ParseError and MemoryMapError #[error]
  attributes: ParseError is used for both format-detection and UTF-16
  decode errors, so "ensure the file is a valid binary" is wrong in
  decode contexts. MemoryMapError is never constructed anywhere.
- Add --min-len to filter-no-match diagnostic (was missing from the
  list of adjustable filters)
- Tighten flow8 filter-no-match test to assert on hint text

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
@unclesp1d3r unclesp1d3r changed the title docs: Improve README, CLI UX, and documentation accuracy docs(docs): Improve README, CLI UX, and documentation accuracy Mar 16, 2026
@unclesp1d3r unclesp1d3r changed the title docs(docs): Improve README, CLI UX, and documentation accuracy docs: Improve README, CLI UX, and documentation accuracy Mar 16, 2026
Match the pattern used by cli_macho_binary in integration_cli.rs:
allow graceful failure on platforms where Mach-O parsing may not work.

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Copilot AI review requested due to automatic review settings March 16, 2026 05:28
@unclesp1d3r unclesp1d3r enabled auto-merge (squash) March 16, 2026 05:31
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates user-facing documentation and CLI UX to better match actual behavior, while adding integration tests around stdin usage and help text to prevent regressions.

Changes:

  • Polishes CLI UX (remove -e short flag, add EXIT CODES to --help, improve filter-no-match diagnostic, make encoding conversion idiomatic).
  • Fixes and restructures documentation (README rewrite, correct MSRV/flags/exit codes, rewrite performance guide).
  • Simplifies Mergify configuration and adds tooling config for Tessl MCP.

Reviewed changes

Copilot reviewed 19 out of 20 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/main.rs Removes -e, adds EXIT CODES to help output, uses From<CliEncoding> for EncodingFilter, updates tag help text comments.
src/pipeline/mod.rs Expands the “filters matched nothing” diagnostic with actionable hints.
tests/integration_flow8_diagnostics.rs Tightens stderr assertions to require the new hint text.
tests/integration_cli.rs Adds coverage that --help includes an EXIT CODES section.
tests/integration_cli_short_flags.rs Updates short-flag tests to reflect removal of -e and use --enc.
tests/integration_cli_stdin.rs Adds stdin-focused CLI integration coverage (formats, output modes, filters).
README.md Rewrites README structure, adds badges/sections, updates examples and feature list.
docs/src/installation.md Corrects MSRV and installation guidance; removes fictional Docker section.
docs/src/performance.md Rewrites performance guide to match real flags/behavior and benchmark tooling.
docs/src/quickstart.md Expands semantic tags table to include missing tags.
docs/src/cli.md Updates exit code documentation to match StringyError::exit_code().
GOTCHAS.md Updates documented CLI conventions (short flags) and help-text sync guidance.
AGENTS.md Updates the CLI flags reference table (removes -e).
.mergify.yml Simplifies queue rules and bot auto-approval/merge requirements.
tessl.json Adds vendored Tessl dependency configuration for skills.
.mcp.json Adds MCP server config for Tessl.
.gemini/settings.json Adds Gemini MCP server config for Tessl.
.cursor/mcp.json Adds Cursor MCP server config for Tessl.
.codex/config.toml Adds Codex MCP server config for Tessl.
.gitignore Ignores Tessl-generated files/directories.

.arg("--enc")
.arg("ascii")
.assert()
.success();
Comment on lines 34 to 38
```bash
cargo run -- --help
```

---

## Usage

```bash
# Basic analysis with ranked output
# Ranked output with semantic tags
stringy target_binary

# Filter by semantic tags
- **PE resources**: VERSIONINFO, STRINGTABLE, and MANIFEST extraction
- **Import/export analysis**: Symbol extraction from all supported formats
- **Ranking**: Section-aware scoring with band-mapped 0-100 normalization
- **Deduplication**: Canonical string grouping with configurable similarity threshold
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
tests/integration_cli_stdin.rs (1)

13-14: ⚠️ Potential issue | 🟠 Major

Use manifest-rooted fixture paths for deterministic test execution.

These reads are cwd-dependent and can fail in non-default runners. Use env!("CARGO_MANIFEST_DIR")-rooted paths (preferably through a helper) for all fixture loads.

Proposed fix
+use std::path::PathBuf;
 use assert_cmd::Command;
 use assert_cmd::cargo_bin_cmd;
 use predicates::prelude::*;
 
 fn stringy() -> Command {
     cargo_bin_cmd!("stringy")
 }
+
+fn fixture_path(name: &str) -> PathBuf {
+    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
+        .join("tests")
+        .join("fixtures")
+        .join(name)
+}
+
+fn read_fixture(name: &str, msg: &str) -> Vec<u8> {
+    std::fs::read(fixture_path(name)).expect(msg)
+}
@@
-    let fixture_data =
-        std::fs::read("tests/fixtures/test_binary_pe.exe").expect("PE fixture should exist");
+    let fixture_data = read_fixture("test_binary_pe.exe", "PE fixture should exist");
@@
-    let fixture_data =
-        std::fs::read("tests/fixtures/test_binary_macho").expect("Mach-O fixture should exist");
+    let fixture_data = read_fixture("test_binary_macho", "Mach-O fixture should exist");
@@
-    let fixture_data =
-        std::fs::read("tests/fixtures/test_unknown.bin").expect("unknown fixture should exist");
+    let fixture_data = read_fixture("test_unknown.bin", "unknown fixture should exist");
@@
-    let fixture_data =
-        std::fs::read("tests/fixtures/test_binary_elf").expect("ELF fixture should exist");
+    let fixture_data = read_fixture("test_binary_elf", "ELF fixture should exist");
@@
-    let fixture_data =
-        std::fs::read("tests/fixtures/test_binary_elf").expect("ELF fixture should exist");
+    let fixture_data = read_fixture("test_binary_elf", "ELF fixture should exist");
@@
-    let fixture_data =
-        std::fs::read("tests/fixtures/test_binary_elf").expect("ELF fixture should exist");
+    let fixture_data = read_fixture("test_binary_elf", "ELF fixture should exist");

As per coding guidelines, "tests/{integration_.rs,test_.rs}: Store binary test fixtures in tests/fixtures/ and reference them using env!(\"CARGO_MANIFEST_DIR\") pattern".

Also applies to: 26-27, 42-43, 55-56, 69-70, 83-84

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integration_cli_stdin.rs` around lines 13 - 14, The test uses
cwd-dependent paths when reading fixtures (e.g., the let fixture_data =
std::fs::read("tests/fixtures/test_binary_pe.exe") call); change all such reads
in tests/integration_cli_stdin.rs (including the other occurrences referenced)
to use manifest-rooted paths via env!("CARGO_MANIFEST_DIR") (or a small helper
like fixture_path) so the file lookup is deterministic across runners; update
the code that constructs fixture_data and the other fixture reads to join
env!("CARGO_MANIFEST_DIR") with "tests/fixtures/..." instead of using relative
paths.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/integration_cli_stdin.rs`:
- Line 12: Rename the test functions to follow the project's test naming
convention test_<function>_<scenario>: for example change fn
stdin_pipe_pe_binary() to fn test_stdin_pipe_pe_binary_success() (or another
clear scenario suffix), and apply the same pattern to the other test functions
in this file so each name begins with "test_" and includes the function and
scenario (e.g., test_<originalName>_<scenario>).
- Around line 11-94: The tests in this file lack insta snapshot assertions;
update the three representative tests stdin_pipe_json_output,
stdin_pipe_raw_mode, and stdin_pipe_with_filters to capture the command stdout
via .output() (instead of .assert()), convert to a UTF-8 string (e.g., from
result.stdout using String::from_utf8_lossy), and replace the current
non-empty/success assertions with insta::assert_snapshot!(stdout_string) calls
(ensure the tests import the insta macro and produce stable snapshots for
JSON/raw/filtered outputs); keep existing success checks only if you still call
.status and include the stdout snapshot assertion immediately after running the
command.

---

Duplicate comments:
In `@tests/integration_cli_stdin.rs`:
- Around line 13-14: The test uses cwd-dependent paths when reading fixtures
(e.g., the let fixture_data = std::fs::read("tests/fixtures/test_binary_pe.exe")
call); change all such reads in tests/integration_cli_stdin.rs (including the
other occurrences referenced) to use manifest-rooted paths via
env!("CARGO_MANIFEST_DIR") (or a small helper like fixture_path) so the file
lookup is deterministic across runners; update the code that constructs
fixture_data and the other fixture reads to join env!("CARGO_MANIFEST_DIR") with
"tests/fixtures/..." instead of using relative paths.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2ce6f332-fce4-422c-b315-4c73815416f3

📥 Commits

Reviewing files that changed from the base of the PR and between ea2a9d6 and 4e00fa1.

📒 Files selected for processing (1)
  • tests/integration_cli_stdin.rs

Comment on lines +11 to +94
#[test]
fn stdin_pipe_pe_binary() {
let fixture_data =
std::fs::read("tests/fixtures/test_binary_pe.exe").expect("PE fixture should exist");

stringy()
.arg("-")
.write_stdin(fixture_data)
.assert()
.success()
.stdout(predicate::str::is_empty().not());
}

#[test]
fn stdin_pipe_macho_binary() {
let fixture_data =
std::fs::read("tests/fixtures/test_binary_macho").expect("Mach-O fixture should exist");

// Mach-O fixtures may not parse on all platforms; verify it runs without panicking
let result = stringy()
.arg("-")
.write_stdin(fixture_data)
.output()
.expect("should execute");

assert!(result.status.success() || !result.stderr.is_empty());
}

#[test]
fn stdin_pipe_unknown_data() {
let fixture_data =
std::fs::read("tests/fixtures/test_unknown.bin").expect("unknown fixture should exist");

// Unknown format falls back to unstructured byte scan (succeeds, may emit info)
stringy()
.arg("-")
.write_stdin(fixture_data)
.assert()
.success();
}

#[test]
fn stdin_pipe_json_output() {
let fixture_data =
std::fs::read("tests/fixtures/test_binary_elf").expect("ELF fixture should exist");

stringy()
.arg("-")
.arg("--json")
.write_stdin(fixture_data)
.assert()
.success()
.stdout(predicate::str::is_empty().not());
}

#[test]
fn stdin_pipe_raw_mode() {
let fixture_data =
std::fs::read("tests/fixtures/test_binary_elf").expect("ELF fixture should exist");

stringy()
.arg("-")
.arg("--raw")
.write_stdin(fixture_data)
.assert()
.success()
.stdout(predicate::str::is_empty().not());
}

#[test]
fn stdin_pipe_with_filters() {
let fixture_data =
std::fs::read("tests/fixtures/test_binary_elf").expect("ELF fixture should exist");

stringy()
.arg("-")
.arg("--min-len")
.arg("8")
.arg("--top")
.arg("10")
.write_stdin(fixture_data)
.assert()
.success();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify snapshot coverage in this integration test file.
rg -n --type=rust -C2 'assert_debug_snapshot!\(' tests/integration_cli_stdin.rs
rg -n --type=rust -C2 'stdout\(predicate::str::is_empty\(\)\.not\(\)\)|\.success\(\);' tests/integration_cli_stdin.rs

Repository: EvilBit-Labs/Stringy

Length of output: 571


🏁 Script executed:

# Check if insta is a dependency
grep -E 'insta|test' Cargo.toml | head -20

Repository: EvilBit-Labs/Stringy

Length of output: 123


🏁 Script executed:

# Find other integration test files and check for snapshot usage
find tests -name "integration_*.rs" -o -name "test_*.rs" | head -10

Repository: EvilBit-Labs/Stringy

Length of output: 386


🏁 Script executed:

# Check for existing snapshot test patterns in integration tests
rg -l 'assert_debug_snapshot|assert_snapshot' tests/

Repository: EvilBit-Labs/Stringy

Length of output: 338


🏁 Script executed:

# Check a sample of integration test files for snapshot usage
rg -n 'assert.*snapshot' tests/integration_cli.rs | head -10

Repository: EvilBit-Labs/Stringy

Length of output: 46


🏁 Script executed:

# Check the specific file for any insta usage
rg -n 'insta|snapshot' tests/integration_cli_stdin.rs

Repository: EvilBit-Labs/Stringy

Length of output: 46


🏁 Script executed:

# Check another integration test for comparison
rg -n 'assert.*snapshot' tests/integration_elf.rs | head -5

Repository: EvilBit-Labs/Stringy

Length of output: 156


🏁 Script executed:

# Review the structure of one integration test using snapshots
head -50 tests/output_json_integration.rs

Repository: EvilBit-Labs/Stringy

Length of output: 1402


🏁 Script executed:

# Check how assert_snapshot is used in the JSON integration test more fully
sed -n '30,45p' tests/output_json_integration.rs

Repository: EvilBit-Labs/Stringy

Length of output: 455


🏁 Script executed:

# Verify the approach used in another integration test file
rg -A10 'assert_snapshot!' tests/integration_elf.rs | head -20

Repository: EvilBit-Labs/Stringy

Length of output: 413


🏁 Script executed:

# Check how snapshot tests capture output in CLI integration tests
rg -B5 -A5 'get_output\|assert.*snapshot' tests/integration_cli.rs | head -30

Repository: EvilBit-Labs/Stringy

Length of output: 46


🏁 Script executed:

# Check integration_cli.rs for snapshot patterns
rg -B3 -A8 'assert_snapshot' tests/integration_cli.rs | head -30

Repository: EvilBit-Labs/Stringy

Length of output: 46


🏁 Script executed:

# Count how many tests exist in integration_cli_stdin.rs
rg -c '#\[test\]' tests/integration_cli_stdin.rs

Repository: EvilBit-Labs/Stringy

Length of output: 65


🏁 Script executed:

# Look at the full context of integration_cli_stdin.rs to understand test structure
wc -l tests/integration_cli_stdin.rs

Repository: EvilBit-Labs/Stringy

Length of output: 97


🏁 Script executed:

# Check if assert_debug_snapshot is used anywhere in the project
rg 'assert_debug_snapshot' tests/

Repository: EvilBit-Labs/Stringy

Length of output: 207


🏁 Script executed:

# Verify the actual snapshot output patterns used in the project
rg -B2 'assert_snapshot!\(' tests/output_json_integration.rs tests/integration_elf.rs | head -25

Repository: EvilBit-Labs/Stringy

Length of output: 1564


🏁 Script executed:

# Check if the review comment's .get_output() pattern is valid for assert_cmd
rg 'get_output\|write_stdin' tests/integration_cli_stdin.rs

Repository: EvilBit-Labs/Stringy

Length of output: 46


🏁 Script executed:

# Check how other CLI tests capture and handle output
cat tests/integration_cli.rs | head -100

Repository: EvilBit-Labs/Stringy

Length of output: 2496


🏁 Script executed:

# Verify the assert_cmd API used in tests
rg -B5 -A10 'write_stdin.*output\(' tests/ | head -30

Repository: EvilBit-Labs/Stringy

Length of output: 46


🏁 Script executed:

# Check how snapshots are stored/named in the project
ls -la tests/snapshots/ | head -20

Repository: EvilBit-Labs/Stringy

Length of output: 1839


🏁 Script executed:

# Verify the exact snapshot naming convention used
rg -B2 'assert_snapshot!\(' tests/output_json_integration.rs | grep 'fn test' | head -5

Repository: EvilBit-Labs/Stringy

Length of output: 94


🏁 Script executed:

# Check the exact pattern for capturing output in integration_cli.rs
sed -n '20,30p' tests/integration_cli.rs

Repository: EvilBit-Labs/Stringy

Length of output: 417


🏁 Script executed:

# Verify if .get_output() is the correct API
rg 'get_output\(\)' tests/

Repository: EvilBit-Labs/Stringy

Length of output: 2911


🏁 Script executed:

# Check how assert_cmd is imported and used
head -5 tests/integration_cli.rs

Repository: EvilBit-Labs/Stringy

Length of output: 190


🏁 Script executed:

# Check the snapshot naming patterns in integration_flows_1_5.rs for CLI tests
rg -B3 -A3 'assert_snapshot!' tests/integration_flows_1_5.rs | head -30

Repository: EvilBit-Labs/Stringy

Length of output: 462


🏁 Script executed:

# Check if assert_debug_snapshot is used for CLI output or just for debugging data
rg -B5 -A2 'assert_debug_snapshot' tests/classification_integration.rs

Repository: EvilBit-Labs/Stringy

Length of output: 369


Add snapshot testing to CLI stdin tests per guideline requirement.

Coding guidelines mandate insta snapshot testing for integration_*.rs files. Current tests only assert success/non-empty output, missing output regressions in formatting and content. Add snapshots for representative modes: --json, --raw, and filtered output.

The example should use assert_snapshot!() (not assert_debug_snapshot!()) for string CLI output:

Example direction
+use insta::assert_snapshot;
@@
 #[test]
 fn stdin_pipe_json_output() {
@@
     let fixture_data =
         std::fs::read("tests/fixtures/test_binary_elf").expect("ELF fixture should exist");
 
-    stringy()
+    let assert = stringy()
         .arg("-")
         .arg("--json")
         .write_stdin(fixture_data)
-        .assert()
-        .success()
-        .stdout(predicate::str::is_empty().not());
+        .assert()
+        .success();
+
+    let stdout = String::from_utf8(assert.get_output().stdout.clone()).unwrap();
+    insta::assert_snapshot!("stdin_pipe_json_output", stdout);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integration_cli_stdin.rs` around lines 11 - 94, The tests in this file
lack insta snapshot assertions; update the three representative tests
stdin_pipe_json_output, stdin_pipe_raw_mode, and stdin_pipe_with_filters to
capture the command stdout via .output() (instead of .assert()), convert to a
UTF-8 string (e.g., from result.stdout using String::from_utf8_lossy), and
replace the current non-empty/success assertions with
insta::assert_snapshot!(stdout_string) calls (ensure the tests import the insta
macro and produce stable snapshots for JSON/raw/filtered outputs); keep existing
success checks only if you still call .status and include the stdout snapshot
assertion immediately after running the command.

// ---------- Stdin edge cases ----------

#[test]
fn stdin_pipe_pe_binary() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Align test names with the project test naming convention.

Rename these functions to test_<function>_<scenario> format for consistency and discoverability (for example, test_stdin_pipe_pe_binary_success).

As per coding guidelines, "tests/**/*.rs: Test names follow test_<function>_<scenario> pattern".

Also applies to: 25-25, 40-40, 53-53, 67-67, 81-81

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integration_cli_stdin.rs` at line 12, Rename the test functions to
follow the project's test naming convention test_<function>_<scenario>: for
example change fn stdin_pipe_pe_binary() to fn
test_stdin_pipe_pe_binary_success() (or another clear scenario suffix), and
apply the same pattern to the other test functions in this file so each name
begins with "test_" and includes the function and scenario (e.g.,
test_<originalName>_<scenario>).

@unclesp1d3r unclesp1d3r disabled auto-merge March 16, 2026 05:39
@unclesp1d3r unclesp1d3r merged commit cde9ad3 into main Mar 16, 2026
31 checks passed
@unclesp1d3r unclesp1d3r deleted the updated_readme branch March 16, 2026 05:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants