> ## Documentation Index
> Fetch the complete documentation index at: https://filetrace.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Use Filetrace output in scripts and pipelines

> Read Filetrace results as JSON, JSON Lines or CSV, process them with jq, follow the event stream, and handle the exit codes that signal incomplete answers.

Every Filetrace listing prints as a table for people and as JSON, JSON Lines or CSV for programs. Machine-readable formats carry exact byte counts instead of rounded sizes, RFC 3339 timestamps, and one schema for a transfer whether it comes from `files` or from `events`. This guide shows the common patterns: query, filter with jq, follow the stream, and react to exit codes.

## Choose a format

| Format | Option | Shape |
| - | - | - |
| `table` | default | Aligned columns with rounded sizes, for reading |
| `json` | `--format json` or `--json` | One JSON document: an array of records, or an object for `inspect` and `stats` |
| `jsonl` | `--format jsonl` or `--jsonl` | One JSON record per line |
| `csv` | `--format csv` | A header row, then one row per record |
| `quiet` | `--format quiet` | One identifier per row: a file path, transfer, process, socket or flow ID |

`--output <file>` writes to a file instead of standard output. `[output] format` in the configuration file sets the default for every listing command. [Output formats](https://filetrace.mintlify.site/cli/output-formats.md) describes each format per command, and [JSON output schema](https://filetrace.mintlify.site/reference/json-output.md) lists every field.

## Read a transfer record

A record from `filetrace files --jsonl`, wrapped for reading:

```json theme={null}
{
  "event": "file_transfer",
  "transfer_id": "tr_4",
  "timestamp": "2026-11-11T12:00:04.561Z",
  "host": "web-01",
  "platform": "linux",
  "process": {"pid": 1245, "ppid": 1, "name": "nginx", "executable": "/usr/sbin/nginx"},
  "file": {"path": "/var/www/video.mp4", "inode": 366815, "device": 64768,
           "size": 50000000, "owner": "www-data", "filesystem": "ext4", "deleted": false},
  "network": {"protocol": "tcp", "socket_id": 421,
              "local_ip": "192.0.2.7", "local_port": 443,
              "remote_ip": "198.51.100.10", "remote_port": 48175},
  "transfer": {"method": "sendfile", "bytes_sent": 50000000, "bytes_per_second": 0,
               "operations": 1, "started": "2026-11-11T12:00:04.561Z", "duration_ms": 0,
               "state": "active", "confidence": "exact",
               "evidence": ["direct_file_to_socket_transfer", "file_identity",
                            "socket_identity", "remote_endpoint"],
               "incomplete": false}
}
```

`transfer.bytes_sent` is what the socket accepted from the file, `file.size` the size of the file when it was first seen, and, for read-write transfers, `transfer.bytes_read` what the thread read from it. `incomplete` is `true` when events were lost during the transfer.

## Filter and aggregate with jq

Narrow the result with Filetrace's own options, then shape it with jq.

```bash theme={null}
# Bytes sent per remote address in the last hour, largest first
sudo filetrace files --since 1h --jsonl |
    jq -s 'group_by(.network.remote_ip)
           | map({remote: .[0].network.remote_ip, bytes: (map(.transfer.bytes_sent) | add)})
           | sort_by(-.bytes)'

# Paths of files sent by a given process, one per line
sudo filetrace files --process python --format quiet

# Exact transfers over 100 MB, as tab-separated values
sudo filetrace files --confidence exact --min-bytes 100MB --jsonl |
    jq -r '[.file.path, .process.name, .network.remote_ip, .transfer.bytes_sent] | @tsv'
```

## Follow the event stream

`filetrace events --follow --jsonl` prints one JSON record per event as it happens, which suits a log shipper or a small daemon:

```bash theme={null}
sudo filetrace events --follow --jsonl --type file_transfer |
    jq -c 'select(.network.remote_ip | startswith("203.0.113.")) | {file: .file.path, bytes: .transfer.bytes_sent}'
```

Each event carries the bytes of one collection interval, so a long transfer produces several events whose `bytes_sent` add up to the transfer. Event records have a `sequence` number that increases with every record. For a stream to another system, the [OTLP exporter](https://filetrace.mintlify.site/integrations/opentelemetry.md) or the [gRPC API](https://filetrace.mintlify.site/integrations/grpc-api.md) are sturdier than a pipe.

## Handle exit codes

Filetrace distinguishes an empty answer from an incomplete one:

| Code | Meaning |
| - | - |
| `0` | Success |
| `1` | General error |
| `2` | Invalid arguments |
| `3` | Permission denied |
| `4` | Agent unavailable |
| `5` | Unsupported platform or capability |
| `9` | Partial results: events were lost in the queried time range |

Code `9` still comes with output. Treat it as a warning, not a failure:

```bash theme={null}
sudo filetrace files --since 1h --jsonl >transfers.jsonl
status=$?
case $status in
0) ;;
9) echo "warning: events were lost; the list may be incomplete" >&2 ;;
*) echo "filetrace failed with exit code $status" >&2; exit "$status" ;;
esac
```

[Exit codes](https://filetrace.mintlify.site/reference/exit-codes.md) lists the codes of every command, including `doctor`, `config validate` and `agent status`.

## Run periodic reports

Because history lives in the agent's memory and is bounded, a periodic job that writes each period's results to disk keeps a longer record than the agent does:

```bash theme={null}
# /etc/cron.hourly/filetrace-report
#!/bin/sh
out=/var/log/filetrace/files-$(date +%Y%m%d%H).csv
mkdir -p /var/log/filetrace
filetrace files --since 1h --format csv --output "$out"
status=$?
[ "$status" -eq 0 ] || [ "$status" -eq 9 ]
```

Run the job as root, or as the user the agent runs as, so it can reach the agent's socket.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.