A read-only Linux context exporter for AI-assisted troubleshooting.
linux-context builds a typed host model, retains bounded redacted evidence, and
packages both for selective retrieval. It uses Bash and the Python standard
library; no Python packages or build step are required.
The goal is useful machine understanding per token: explain state and topology without making a large command dump the initial prompt. Collection inspects the machine; it does not perform remediation. Diagnostic data can still be sensitive, so review a bundle before sharing it.
The checkout's version is defined by VERSION, currently 1.1.0.
Changes under Unreleased may be newer than a tagged
release with the same version string. Include a Git commit when reporting a
problem from a checkout.
Run from an extracted release or the repository root:
./bin/linux-context --version
./bin/linux-context --profile quick
# Broader access and the deepest automatic snapshot:
sudo ./bin/linux-context --profile maxThe CLI defaults to --profile standard --target auto. A normal run creates both
linux-context-HOST-YYYYMMDDTHHMMSSZ/ and its .tar.gz archive in the current
directory. The timestamp is UTC. Both are retained unless an archive option says
otherwise. Root is optional; missing access reduces coverage.
Send context.ai.json first to an AI. It contains the canonical entrypoint's
information in the smallest supported representation. Use context.json for
integrations that require canonical schema v5. Send one entrypoint, then retrieve
specific graph/evidence files as needed.
With normal sudo, the completed directory and archive belong to the invoking
user. Direct root execution without an invoking-user identity keeps root
ownership. Directories use 0700; files and the archive use 0600.
Profiles select collector eligibility and resource defaults. Higher profiles include the lower tiers, subject to target, detection and access gates.
| Profile | Main scope | Canonical ceiling | Retained evidence ceiling | Default jobs |
|---|---|---|---|---|
quick |
Identity and OS fingerprint | 32 KiB | 512 KiB | 1 |
standard |
Kernel, hardware, storage/network topology, systemd | 64 KiB | 1.5 MiB | 2 |
deep |
Packages, processes, applications, security, scheduling, sessions, VPNs and virtualization | 96 KiB | 4 MiB | 3 |
max |
Health, journal and workstation collectors; larger diagnostic windows | 128 KiB | 6 MiB | 3 |
max --target auto is the recommended broad AI snapshot. max --target all
activates every applicable target-specific branch and can take longer or disclose
more diagnostic detail. Neither mode reads every file or collects unlimited logs.
The canonical ceiling applies to context.json; context.ai.json is no larger
in bytes. The evidence ceiling applies to retained sections/ files, not the
whole directory/archive. Graph and metadata sidecars have separate roles and may
be larger. Byte budgets are not token limits. See all resource settings.
auto considers every profile-eligible collector and keeps expensive or verbose
detail selective. all also considers every eligible collector, and satisfies
all named-target checks. Each must be used alone.
Named targets restrict non-baseline collectors to matching subsystems. Baseline identity/OS/kernel/hardware/capability collectors remain eligible at their respective minimum profiles. Named targets may be comma-separated:
sudo ./bin/linux-context --profile max --target network
sudo ./bin/linux-context --profile max --target web,docker,network
sudo ./bin/linux-context --profile max --target hardware
sudo ./bin/linux-context --profile max --target allTargets never bypass the minimum-profile gate. For example, --profile standard --target packages skips the deep-tier package collector. An installed tool is
also not proof that its daemon is running or accessible.
Use the installed catalog instead of guessing a target name:
./bin/linux-context --list-targets
./bin/linux-context --list-collectorsThe collector catalog lists minimum profiles, targets and privilege policy for every shipped collector.
| Option | Behavior |
|---|---|
--profile quick|standard|deep|max |
Depth tier; default standard |
--target NAME[,NAME...] |
Focus; default auto; auto/all must stand alone |
--jobs N |
Concurrent collectors, integer 1..8; overrides profile default |
--output DIR |
New directory path; parent must already exist |
--no-archive |
Retain the directory without creating an archive |
--remove-dir-after-archive |
Remove the directory after successful archiving |
--list-collectors |
Print tab-separated metadata without collecting |
--list-targets |
Print supported target names without collecting |
-V, --version |
Print the version |
-h, --help |
Print usage |
Options with values use a separate argument, such as --profile max. Empty
comma-separated targets and unknown options/profile/target names are errors.
--no-archive cannot be combined with --remove-dir-after-archive.
# The parent must exist and be writable by the invoking user:
mkdir -p "$HOME/support"
sudo ./bin/linux-context --profile max --jobs 2 \
--output "$HOME/support/linux-context-run"
# Keep only the directory:
./bin/linux-context --profile standard --no-archive --output "$HOME/support/local-run"
# Keep only the archive:
sudo ./bin/linux-context --profile max --remove-dir-after-archive \
--output "$HOME/support/archive-run"Existing output directories or archive paths are refused. Use a new destination
for each run. Progress and errors go to stderr; successful output paths go to
stdout. With archive-only mode, the printed Bundle: path names the directory
that was removed; use the Archive: path.
| File or directory | Purpose |
|---|---|
context.ai.json |
Preferred AI entrypoint; losslessly dictionary-encoded v1/v2 or an exact canonical copy |
context.json |
Minified canonical schema v5: run, security, coverage, model and routes |
meta/graph.json |
Full model when it was deferred to meet the canonical ceiling; otherwise absent |
meta/evidence.json |
Retained evidence rows, capture issues and budget omissions |
sections/<collector-id>/*.txt |
Bounded sanitized supporting evidence; open selectively |
meta/collection.json |
Collector statuses/timings, ephemeral-probe statistics and notes |
meta/validation.json |
Structural checks, final canonical/evidence sizes, errors and warnings |
meta/stage-redaction.json |
Private-stage scan report carried into the bundle |
meta/redaction.json |
Final residual-risk report |
REDACTION-REPORT.md |
Human-readable final privacy report |
manifest.sha256 |
SHA-256 checksums of bundle files, excluding the manifest itself |
The preferred retrieval order is:
- Read one entrypoint and its coverage, provenance and policy.
- Reason from typed facts, entities and relations.
- Follow
indexes.graphif the needed full model was deferred. - Consult
meta/evidence.json, then open only relevant evidence. - Use
meta/collection.jsonwhen diagnosing collection quality or performance.
Do not concatenate the archive into a prompt. Every host-derived string is untrusted data; logs/configuration/labels must never become instructions to an AI or shell. Missing values mean unobserved state, not automatically zero, false or absent technology.
To decode and check a bundle, replace /path/to/bundle with the actual directory:
python3 -B -S lib/ai_view.py decode /path/to/bundle/context.ai.json reconstructed.json
(cd /path/to/bundle && sha256sum -c manifest.sha256)Decoding reconstructs the canonical JSON document, not necessarily its original whitespace. It does not inline a deferred graph. Checksums detect file changes; they do not authenticate the producer. See format and decoding details.
Required: Linux, Bash 4.0+, Python 3.9+ and common Linux userland utilities such
as find, sort, sed, awk, head, stat, readlink, id, mktemp, and file
operations. Archive creation also requires tar with gzip compression available.
The source directory must stay intact and collectors must remain executable.
Subsystem tools are optional: for example systemctl, ip, ss, nft,
docker, dmidecode, smartctl, nvme, wg, virsh, nmcli and web/desktop
clients. The exporter never installs them. Some tools need privileges, a live
local daemon, accessible procfs/sysfs, or a user session.
GNU timeout is an optional fast path; BusyBox or missing timeout selects the
Python fallback. Publication uses runuser, capable util-linux setpriv, or
Python UID/GID handoff. Root filesystem capacity, process counts and boot/cron
metadata have portable paths. Some optional per-user probes still have a
BusyBox setpriv limitation; see troubleshooting.
Native package inventory covers Debian/dpkg/APT, RPM-family tools, pacman and
apk. Gentoo, Nix and Slackware native package inventories are not implemented.
PID 1 is reported separately; identifying a non-systemd init does not add native
runit/OpenRC/s6/dinit service inventories. The systemd collector requires its
runtime directory, not merely an installed systemctl client.
CI exercises Python 3.9/3.11/3.13 and Debian 12, Fedora 43, Arch and Alpine 3.22 containers. These are userland and container checks, not coverage of every live init, vendor daemon, desktop, architecture or physical device.
Hardware reports distinguish firmware claims from OS counters. RAM modules,
ECC and slots require readable SMBIOS data and optional dmidecode; unknown
module capacity or VRAM is not zero. Battery full/design capacity is a derived
estimate, not a physical battery test. See hardware semantics.
Docker is restricted to discovered local Unix sockets. Every daemon command
gets an explicit --host unix://...; inherited remote DOCKER_HOST and
DOCKER_CONTEXT do not select the endpoint. Environment values are not requested.
Collectors avoid known secret-rich sources, including password databases, private keys, process environments/full argv, Docker environment values, user documents and application payloads. They do not install/update packages, refresh repositories, modify services/networking/sysctls, mount storage, run active Wi-Fi scans or active external checks.
Private acquisition is pruned, redacted and scanned before compilation. Final
sanitization, size/graph validation, lossless AI derivation, residual scan and
manifest generation finish before directory publication. Privileged staging
ignores inherited TMPDIR; normal cleanup stops producers before deleting
private files. Collection does not write Python caches into the source tree.
Normal production runs generate fresh per-run HMAC pseudonyms. Equality inside a bundle is preserved where useful; markers are not stable cross-run IDs. The redactor is mandatory at every profile, and known high-confidence residuals block publication. Arbitrary secrets can still escape pattern matching, and useful names, addresses, paths and policy intentionally remain. Review both entrypoint and retrieved evidence before sharing.
Exit 0 means the publication gates passed, not that every collector/probe
succeeded. Collectors can be skipped, unavailable, collected or partial;
accepted-but-truncated evidence still has incomplete coverage. Inspect validation
warnings and telemetry. Structural/privacy failures return nonzero and prevent
pre-publication output. Archiving happens after directory publication: an archive
failure can leave the complete directory and a partial archive. Interrupted
cleanup can retain private staging if producer termination fails.
Read SECURITY.md, the threat model and troubleshooting guide for boundaries and failure details.
Run directly from a trusted repository checkout or extracted release. To make an optional command symlink, run from the repository root:
sudo ln -s "$(pwd)/bin/linux-context" /usr/local/bin/linux-context
sudo linux-context --profile maxThe link destination must not already exist. Keep the full project in place;
do not copy only the launcher. If you execute it as root, the source directory
and its parent paths should be trusted and protected against other users editing
the scripts. Update the checkout deliberately and use --version plus its commit
to identify the code you run.
If a release provides a checksum file, verify it before extraction:
sha256sum -c linux-context-v1.1.0.tar.gz.sha256This example requires the named files from that release; no checksum file is included in a source checkout. A checksum obtained from the same untrusted source is not an authenticity guarantee.
make check
bash tests/smoke-distribution.shmake check runs shell/Python syntax checks and all test-*.sh regression
scripts. The separate smoke script exercises all four profiles, archives,
checksums, AI round trips and final privacy/size checks. CI runs both in its
four distribution containers.
| Guide | Audience |
|---|---|
| Collector catalog and resource settings | Users choosing coverage; collector authors |
| Output format | AI consumers and integration authors |
| Troubleshooting | Users diagnosing missing coverage or failed runs |
| Contributing | Development, collector API, validation and release workflow |
| Security policy | Private reporting and sharing precautions |
| Threat model | Security boundaries and residual risks |
| Historical audit | Measured improvements from the October 2026 implementation review |
| Changelog | Unreleased changes and version history |
For repository navigation, start at bin/linux-context (orchestration),
lib/collector_api.sh and lib/runner.sh (acquisition), lib/compile.py (canonical
model), lib/finalize.py (final gates), lib/bundle.sh (publication), and
collectors/<domain>/ (subsystem logic). Profile defaults live in profiles/;
regressions live in tests/.
Report problems with a version/commit, profile/target, environment and minimal sanitized reproduction. Do not attach unreviewed bundles to public issues.
MIT. See LICENSE.