ChatArchiveGuard: a local read-only pre-flight check for chat exports
Audit AI chat exports locally before sharing or migration. Find possible secrets, personal-data patterns, broken JSON/JSONL, SQLite issues, and scan gaps—without uploading the archive.
At a glance
- What is it?
- ChatArchiveGuard audits JSON, JSONL and SQLite chat exports on your own machine before you share or migrate them, flagging secret patterns, personal-data shapes, format errors and scan gaps. It is an audit gate, not a reader, importer or search tool.
- Who is it for?
- Adopt ChatArchiveGuard if you hand chat exports to analysts, migration scripts or backup pipelines and want a fixed-exit-code gate that never uploads the archive. Skip it if you need a conversation reader, an importer, or proof that no messages were lost: the README states plainly that it cannot show message-level completeness or provenance.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 23 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 16, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The handoff problem ChatArchiveGuard targets
A chat export usually leaves one machine and lands somewhere else: an analyst's notebook, a migration script, a backup bucket, a support ticket. Between export and handoff there is normally no check. Secrets pasted into a conversation years ago travel with the file. A truncated JSONL line breaks a downstream parser. A SQLite database sitting next to a stale WAL file may look fine and read wrong. ChatArchiveGuard exists to answer three questions before that handoff: does supported content contain common secret, credential or personal-data shapes; do JSON, JSONL and SQLite read as expected and does the SQLite quick check pass; and did the scan actually cover everything in scope, or did a read error, a rejected file or a resource limit leave a blind spot. The audience is developers and system administrators who already treat the export as an artifact to be validated. The README is explicit that this is a pre-delivery audit gate, not a chat archive reader, importer or search tool, and that its notion of completeness covers file format, SQLite structure and scan coverage, not whether messages were lost.
How the scan is structured, file type by file type
The tool dispatches on file type rather than running one generic pass. Text, JSON and JSONL files are checked for UTF-8 validity and structural format, then scanned for the supported secret and personal-data patterns. SQLite databases get a `PRAGMA quick_check(1)` run against a private snapshot, and the scanner walks ordinary tables plus any accessible FTS virtual table text, with FTS shadow tables excluded so hits are not double counted. WAL and SHM sidecars are copied together with their main database into a private temporary directory, and SQLite opens the copy rather than the original. Directory coverage is reported through four counters: `files_seen`, `files_scanned`, `complete` and `truncated`, which separate what was walked from what was actually content-checked. Rotated logs are treated as independent files, and only ones whose final extension is supported (the README's example is `history.1.log`) enter text scanning; `history.log.1` and gzipped files are not auto-recognised as text. The tool does not stitch rotated sequences together and does not judge whether time ranges are contiguous. That is a deliberate scope line, and it means a multi-part log set can pass while a gap between parts goes unnoticed.
Installing ChatArchiveGuard and running a first scan
The package requires Python 3.11 or later and installs from PyPI. The README recommends an isolated environment first so the system Python is untouched. On macOS or Linux:
python3 -m venv .venv
. .venv/bin/activate
python -m pip install chat-archive-guardOn Windows PowerShell the README uses the Python Launcher and explicit paths:
py -3 -m venv .venv
.\.venv\Scripts\python.exe -m pip install chat-archive-guardThen point it at a directory. The default report shows relative file names so you can locate problems locally; adding `--json --summary-only` produces a report that omits file names and hit values entirely, which is what you would attach to a CI job or share with someone else.
chat-archive-guard /path/to/archive
chat-archive-guard /path/to/archive --json --summary-onlyRead the exit code together with `ok`, `complete` and `truncated`. The README states that `ok` is only true when there are no findings, the scan is complete, and nothing was truncated. Exit code 0 means no findings and full coverage of in-scope content; 1 means findings or incomplete coverage; 2 means the path or arguments were invalid. If you are auditing an unreleased candidate or want a source install, run `python -m pip install .` from the repository root that contains `pyproject.toml`, inside the activated environment. There is also a wheel path: download `SHA256SUMS` and `chat_archive_guard-0.1.0-py3-none-any.whl` from the same GitHub Release page, verify the hash, then install with `python -m pip install --no-index --no-deps ./chat_archive_guard-0.1.0-py3-none-any.whl`. The README notes that a matching SHA-256 only confirms the wheel agrees with that manifest; it does not replace verifying where the release came from.
The synthetic demo, and what its exit code 1 means
The repository ships a generator that creates exactly two fixed fictional artifacts, one JSONL and one SQLite, without reading existing files or overwriting an existing directory. The planted markers are labelled as never valid and exist only to prove the checker fires. From the repository root on macOS or Linux:
demo_parent="$(mktemp -d)"
demo_parent="$(cd "$demo_parent" && pwd -P)"
demo_dir="$demo_parent/chat-archive-guard-demo"
PYTHONDONTWRITEBYTECODE=1 python3 scripts/generate_demo.py "$demo_dir"
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python3 -m chat_archive_guard "$demo_dir" --summary-onlyThe README records the output as `synthetic demo: PASS files=2`, then `FAIL files_seen=2 files_scanned=2 finding_count=3 complete=true truncated=false`, followed by three categories: `format.invalid_jsonl`, `secret.assignment` and `secret.provider_key`. Both scan commands exit 1 by design, because the demo data intentionally contains three findings. That is the gate reporting problems, not a crash. On Windows PowerShell the same text checks run, but the README records a different result: standard Python refuses to inspect the SQLite file directly across a security boundary, so `files_scanned=1`, `complete=false`, `truncated=true`, and `sqlite.sidecar_unsafe` replaces the provider-key category. That divergence is worth knowing before you build a Windows CI gate around this tool.
Where the privacy model stops helping you
The scanner runs locally, uses only the Python standard library at runtime, does not modify source files or source databases, and the README states there is no network client, telemetry or auto-update. Hit values never enter the report, and read exceptions map to fixed categories. Symlinks, link-like entries, concurrent changes and SQLite files that cannot be read safely are rejected or marked incomplete. Hard caps apply to file counts, text bytes, SQLite rows, single-value size and finding counts. The limitation is the default report: relative file names are still metadata. `--summary-only` strips findings and relative names from both JSON and text output and keeps only real status, scan counts and category totals, which is the mode for CI or for sharing a redacted report. Exit codes and `finding_count` are not rewritten in either mode. More importantly, the README states that summary mode does not create user or channel isolation: category counts aggregate over the whole scan root, so the caller must first narrow the root to a single dataset they are entitled to inspect. Pointing it at a directory that spans several users and then sharing the summary leaks the shape of the whole set. The second limitation is conceptual. The tool cannot prove message-level completeness, cannot prove provenance, and cannot prove a file was never tampered with. If your question is whether an archive is authentic, this is the wrong instrument.
Alternatives, and where the boundary actually sits
The README positions ChatArchiveGuard against two sibling tools from the same author, and the contrast is about what gets verified. ArtifactProof targets final PPTX deliverables: it confirms the artifact and its acceptance evidence still match an HMAC-signed receipt generated from a structural check. That is authenticity of a signed deliverable, not scanning of chat text. TaskStateGuard targets task state after a restart: it reconciles stuck jobs, timeouts and pending deliveries so an unknown result is not guessed as success. That is state reconciliation, not content auditing. Neither overlaps with what ChatArchiveGuard reads. Against general-purpose secret scanners, the difference is the archive-specific layer: JSON and JSONL structural validation, SQLite quick check plus FTS text scanning, WAL and SHM handling through a private copy, and the coverage counters that tell you whether the scan was complete. A generic grep-based secret scan gives you hits and nothing about whether the file was readable end to end. The trade-off is that ChatArchiveGuard is narrow by design. It does not read conversations, import them, or search them, and the README says so directly.
Maintenance, licence and what a v0.1.0 pin buys you
The last push to the default branch was on 2026-08-25, and v0.1.0 was released the same day, so this is a young project with a single published release and a pre-alpha classifier in `pyproject.toml`. The repository is not archived. That combination means upgrade cost is currently near zero and also that there is no track record of breaking changes to reason about. The runtime has no third-party dependencies, which keeps the upgrade surface small: a version bump is a Python package swap, not a dependency tree migration. The project is Apache-2.0, with `license-files = ["LICENSE"]` declared in the build metadata and a `PROVENANCE.md` and `THREAT_MODEL.md` at the repository root, so the security assumptions are written down rather than implied. Apache-2.0 includes an explicit patent grant and requires attribution and notice retention when you redistribute; if you vendor the wheel into an internal artifact store, keep the licence file with it. That is a description of the licence text, not legal advice for your situation.
Editorial conclusion
Adopt ChatArchiveGuard if you hand chat exports to analysts, migration scripts or backup pipelines and want a fixed-exit-code gate that never uploads the archive. Skip it if you need a conversation reader, an importer, or proof that no messages were lost: the README states plainly that it cannot show message-level completeness or provenance. Before trusting it, run the synthetic demo from the repository root, confirm you see the three expected categories, and then check on your own archive that complete is true and truncated is false, because ok is only true when both hold.
Frequently asked questions
What does ChatArchiveGuard do with an archived chat?
It runs a read-only local check over the export and reports three things: whether supported files contain common secret, credential or personal-data shapes; whether JSON, JSONL and SQLite content reads as expected and the SQLite quick check passes; and whether the scan covered everything in scope or left a blind spot. It does not read, import or search conversations.
Can someone still message you if you archive the chat?
This is outside what ChatArchiveGuard covers. The tool operates on files you already exported, does not connect to a chat service, and the README states there is no network client at runtime.
How do I access archived chats with ChatArchiveGuard?
You point the scanner at a file or directory, for example `chat-archive-guard /path/to/archive`, and read the report plus the exit code. The README is explicit that the tool is not a chat archive reader, so accessing the conversations themselves is outside its scope.
How do I keep a chat in archive while scanning it?
The scanner never modifies source files or source databases, and SQLite is only read from a private copy, so running it does not disturb the archive. Rotated logs are handled as separate files, and compressed `.gz` files are not auto-recognised as text.
Community notes