Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

pctx generates LLM-ready context from your codebase.

It scans files, applies sensible filters, truncates oversized content, and formats the result as Markdown, XML, plain text, or structured JSON. The output is designed to be pasted into, copied to, or consumed by AI coding assistants.

Why pctx?

AI coding agents often spend many tool calls discovering a project:

  1. list files
  2. inspect directories
  3. read files
  4. skip build artifacts
  5. recover from oversized or binary files
  6. repeat

That exploration costs time and tokens. pctx packages the useful parts of a repository into one controlled context snapshot.

Use it to:

  • Reduce latency by avoiding repeated filesystem exploration.
  • Improve accuracy by giving an assistant a broad project view up front.
  • Save tokens with default exclusions and truncation.
  • Control scope with include/exclude patterns and .pctx.toml.
  • Automate workflows with JSON output and stable exit codes.

What pctx outputs

By default, pctx writes Markdown to stdout:

`src/lib.rs`:
```rust
pub mod cli;
pub mod config;
```

`README.md`:
```markdown
# My Project
```

You can also include a file tree:

pctx --tree

Or produce structured output for scripts:

pctx --json

Features

  • Recursive file discovery
  • .gitignore support
  • Built-in exclusions for common noisy paths
  • Hidden-path filtering with explicit --hidden opt-in
  • Binary-file detection
  • File size limits
  • Include/exclude patterns using gitignore-style syntax
  • Markdown, XML, and plain text output
  • Clipboard and file destinations
  • JSON output for automation
  • Stdin mode for integrating with find, fd, git diff, and other tools
  • Truncation for long files and long lines
  • Approximate token estimation

Safety note

pctx reads local files and emits their contents. Review the generated context before sharing it with external services.

Default exclusions skip many common secrets and environment files, such as .env, .env.*, *.pem, and *.key, but no automatic filter can guarantee that sensitive information is excluded.

Installation

From crates.io

Install the latest published version with Cargo:

cargo install pctx

Verify the installation:

pctx --version
pctx --help

Update an existing installation:

cargo install pctx --force

Uninstall:

cargo uninstall pctx

Build from source

git clone https://github.com/mc-marcocheng/pctx
cd pctx
cargo build --release

The compiled binary will be available at:

target/release/pctx

You can run it directly:

./target/release/pctx --help

Or install it locally from the checkout:

cargo install --path .

Shell completions

Generate completions with:

pctx completions bash
pctx completions zsh
pctx completions fish
pctx completions powershell
pctx completions elvish

Example for Bash:

pctx completions bash > pctx.bash
source pctx.bash

Example for Zsh:

pctx completions zsh > _pctx

Then move _pctx into a directory listed in your $fpath.

Build the documentation locally

If you have mdbook installed:

cd docs
mdbook serve

Then open the local URL printed by mdbook.

Usage

Quick start

# Generate context for the current directory
pctx

# Include a file tree
pctx --tree

# Copy generated context to the clipboard
pctx --clipboard

# Write generated context to a file
pctx --output context.md

# Overwrite an existing output file
pctx --output context.md --force

# Generate structured JSON
pctx --json

# Preview files without writing the final context
pctx --dry-run

Command overview

# Generate context
pctx [OPTIONS] [PATHS...]

# List files that would be included
pctx files list [OPTIONS]

# Display the included file tree
pctx files tree [OPTIONS]

# Configuration management
pctx config show
pctx config init
pctx config defaults

# Shell completions
pctx completions bash
pctx completions zsh
pctx completions fish
pctx completions powershell
pctx completions elvish

If no path is supplied, pctx scans the current directory:

pctx

You can pass files or directories explicitly:

pctx src README.md Cargo.toml

Output options

FlagDescription
--clipboard, -cCopy output to the system clipboard
--output FILE, -oWrite output to a file
--forceOverwrite the output file if it already exists
--format FORMAT, -fOutput format: markdown, xml, or plain
--tree, -tInclude a file tree at the beginning of the output
--stats, -sPrint a statistics summary
--jsonEmit structured JSON
--absolute-pathsDisplay absolute paths instead of relative paths
--stdinRead file paths from stdin, one per line
--stdin0Read NUL-delimited file paths from stdin
--paths-file0 FILERead NUL-delimited file paths from a file
--path-alias ALIAS=PATHDisplay files under PATH using ALIAS instead of a relative or absolute path; repeatable

Examples:

pctx --format markdown
pctx --format xml
pctx --format plain
pctx --tree --stats
pctx --absolute-paths

Filtering options

FlagDescription
--exclude PATTERN, -eExclude files matching a pattern; repeatable
--include PATTERN, -iInclude only files matching a pattern; repeatable
--hiddenInclude dot-prefixed files and directories
--no-default-excludesDisable built-in exclusion patterns
--no-gitignoreIgnore .gitignore rules
--max-size KBMaximum file size to include, in KiB. Default: 1024
--max-depth N, -dMaximum traversal depth. 0 means unlimited

Examples:

# Include only Rust and TOML files
pctx --include "*.rs" --include "*.toml"

# Exclude test files
pctx --exclude "*.test.ts" --exclude "__tests__"

# Disable built-in exclusions
pctx --no-default-excludes

# Ignore .gitignore files
pctx --no-gitignore

# Include files up to 2 MiB
pctx --max-size 2048

# Only scan immediate children
pctx --max-depth 1

# Scan children and grandchildren
pctx --max-depth 2

Hidden files and directories

Dot-prefixed paths are hidden by default. Examples include:

  • .github
  • .vscode
  • .env
  • project/.config/file.toml

Use --hidden to include them:

pctx --hidden .github
pctx --hidden .github/workflows

Hidden-path filtering is separate from default exclusions and .gitignore rules.

This does not include .github:

pctx --no-default-excludes .github

Use:

pctx --hidden --no-default-excludes .github

The filtering layers are independent:

MechanismControlled by
Dot-prefixed paths--hidden
Built-in exclusions such as node_modules and target--no-default-excludes
.gitignore and related git ignore rules--no-gitignore

Truncation options

FlagDescription
--no-truncationDisable file and line truncation
--max-lines NMaximum lines per file before truncation. 0 means unlimited
--head-lines NLines to keep at the start of a truncated file
--tail-lines NLines to keep at the end of a truncated file
--max-line-length NMaximum characters per line before truncation. 0 means unlimited
--head-chars NCharacters to keep at the start of a truncated line
--tail-chars NCharacters to keep at the end of a truncated line

Defaults:

SettingDefault
max_lines500
head_lines20
tail_lines10
max_line_length500
head_chars200
tail_chars100

Examples:

# Keep more of long files
pctx --max-lines 1000 --head-lines 50 --tail-lines 25

# Disable only line-count truncation
pctx --max-lines 0

# Disable only long-line truncation
pctx --max-line-length 0

# Disable all truncation
pctx --no-truncation

When a file is truncated, pctx preserves the beginning and end of the file and inserts an omission marker between them.

Stdin mode

Use --stdin to read paths from standard input:

find . -name "*.rs" -mtime -1 | pctx --stdin

This is useful for composing with other tools:

# Recently changed Rust files
find . -name "*.rs" -mtime -7 | pctx --stdin

# Files from a saved list
cat files_to_review.txt | pctx --stdin

# Files selected by pctx itself
pctx files list --quiet | grep -v test | pctx --stdin

# Changed files in git
git diff --name-only HEAD~5 | pctx --stdin

# Files found by fd
fd -e rs -e toml --changed-within 2weeks | pctx --stdin

Behavior in stdin mode:

  • Empty lines are ignored.
  • Whitespace around each line is trimmed.
  • File paths are processed directly.
  • Directory paths are expanded recursively.
  • Positional paths are ignored when --stdin is used.
  • Non-existent paths are reported as file errors; if some files succeed, the command exits with partial success.

NUL-delimited path input

--stdin splits on newlines, which breaks for paths that contain them. Use --stdin0 or --paths-file0 for NUL-delimited input instead:

# NUL-delimited stdin (pairs naturally with `find -print0`)
find . -type f -print0 | pctx --stdin0

# NUL-delimited path file — avoids command-line length limits and does not
# require keeping an interactive stdin pipe open
pctx --paths-file0 selected-paths.bin

--stdin, --stdin0, and --paths-file0 are mutually exclusive. Positional paths are ignored whenever any of them is used, and an empty input is treated as no matching files (exit code 6).

Path aliases

--path-alias ALIAS=PATH maps files under an absolute directory to a short display name, which is useful for combining unrelated roots (e.g. multiple repositories) without leaking absolute paths into the generated output:

pctx \
  /home/me/api/src/main.rs \
  /home/me/shared/src/lib.rs \
  --path-alias api=/home/me/api \
  --path-alias shared=/home/me/shared

This renders paths as api/src/main.rs and shared/src/lib.rs. Notes:

  • PATH must exist and resolve to a directory.
  • Aliases must be unique, and each PATH may only be aliased once.
  • When aliased roots are nested, the most specific (deepest) root wins.
  • --absolute-paths overrides aliases and always shows the full path.

Configuration file selection

By default, pctx searches the current directory and its parents for .pctx.toml. Override this with:

FlagDescription
--config FILELoad exactly this config file; errors (missing or malformed) are fatal
--no-configDisable automatic and explicit .pctx.toml loading entirely
# Explicit configuration
pctx --config /workspace/.pctx.toml

# Ignore all config files
pctx --no-config

--config and --no-config are mutually exclusive. Only an automatically discovered malformed config warns and falls back to defaults; an explicitly supplied --config file that is missing or malformed is a hard error.

Capabilities

pctx capabilities reports which machine-readable features this build supports, which is useful for integrations that need to detect support before using a flag:

pctx --json capabilities

Listing files

# Human-readable file list
pctx files list

# Bare paths only, one per line
pctx files list --quiet

# JSON output
pctx files list --json

--quiet is designed for pipelines:

pctx files list --quiet | xargs wc -l

File tree

pctx files tree
pctx files tree --json

To include the same tree in generated context:

pctx --tree

Dry run

Use --dry-run to inspect what would be included:

pctx --dry-run
pctx --dry-run --json

Dry run still scans and processes files so it can report truncation and approximate token counts, but it does not write the final context document.

Global options

FlagDescription
--jsonUse structured JSON output
--verbose, -vPrint additional diagnostics to stderr
--quiet, -qSuppress non-essential output
--no-colorDisable colored output

Practical recipes

# Generate compact context for a Rust crate
pctx --include "*.rs" --include "*.toml" --tree

# Prepare context for a code review from changed files
git diff --name-only main...HEAD | pctx --stdin --tree

# Generate XML for a downstream parser
pctx --format xml --output context.xml

# Copy only source-like files to clipboard
pctx src Cargo.toml README.md --clipboard

# Show what would be included after filters
pctx --include "*.ts" --exclude "*.test.ts" --dry-run

# Find files pctx would include, then post-filter with grep
pctx files list --quiet | grep -E '\.(rs|toml)$' | pctx --stdin

Configuration

pctx can load project defaults from a .pctx.toml file.

Create one with:

pctx config init

By default, pctx searches for .pctx.toml in the current directory and then in parent directories. This can be overridden:

FlagDescription
--config FILELoad exactly this config file instead of searching. A missing or malformed file is a fatal error
--no-configDisable automatic and explicit .pctx.toml loading; only built-in defaults and CLI arguments apply
pctx --config /workspace/.pctx.toml
pctx --no-config

--config and --no-config are mutually exclusive.

Supported keys

The configuration file currently supports:

KeyTypeDescription
excludearray of stringsAdditional gitignore-style exclusion patterns
includearray of stringsIf non-empty, only matching files are included
max_linesintegerMaximum lines per file before truncation. 0 means unlimited
head_linesintegerLines to keep at the start of a truncated file
tail_linesintegerLines to keep at the end of a truncated file
max_line_lengthintegerMaximum characters per line before truncation. 0 means unlimited
head_charsintegerCharacters to keep at the start of a truncated line
tail_charsintegerCharacters to keep at the end of a truncated line

Example:

# Patterns to exclude in addition to built-in defaults
exclude = [
    "*.generated.ts",
    "vendor/",
    "__snapshots__",
]

# If specified, only matching files are included
include = [
    "*.rs",
    "*.toml",
    "*.md",
]

# File truncation
max_lines = 500
head_lines = 20
tail_lines = 10

# Long-line truncation
max_line_length = 500
head_chars = 200
tail_chars = 100

Precedence

Settings are applied in this order, highest priority first:

  1. Command-line arguments
  2. .pctx.toml
  3. Built-in defaults

For example:

max_lines = 500

can be overridden with:

pctx --max-lines 1000

Include and exclude patterns are additive:

  1. Built-in excludes are added first, unless --no-default-excludes is used.
  2. Config-file excludes are added.
  3. CLI excludes are added.
  4. Config-file includes are added.
  5. CLI includes are added.

Config commands

# Show the resolved config file contents or defaults
pctx config show

# Create .pctx.toml in the current directory
pctx config init

# Overwrite an existing .pctx.toml
pctx config init --force

# Print built-in exclusion patterns
pctx config defaults

JSON is also supported:

pctx config show --json
pctx config defaults --json

Syntax errors

If a config file is automatically discovered (no --config given) but cannot be parsed, pctx prints a warning and continues without that config file.

If a config file is loaded via an explicit --config FILE, a missing file or parse error is a fatal error instead — the same is true for --config with pctx config show.

Default exclusions

pctx excludes many common noisy or unsafe files by default.

Examples include:

  • Version control: .git, .svn, .hg
  • Dependencies: node_modules, vendor, bower_components
  • Rust: target, Cargo.lock
  • Python: __pycache__, .pytest_cache, .mypy_cache, .venv
  • Build outputs: dist, build, out, bin, obj
  • Editor files: .idea, .vscode, *.swp
  • Caches: .cache, .parcel-cache, .turbo, .next
  • Environment/secrets: .env, .env.*, *.pem, *.key
  • Logs: *.log, logs
  • Media and binaries: *.png, *.jpg, *.pdf, *.zip, *.dll, *.so
  • Generated/minified files: *.map, *.min.js, *.min.css

View the exact list:

pctx config defaults

Disable built-in exclusions:

pctx --no-default-excludes

Hidden paths are separate

Hidden-path filtering is not part of the default exclusion pattern list.

Dot-prefixed paths such as .github require --hidden, even when:

  • --no-default-excludes is used
  • --no-gitignore is used
  • .gitignore does not exclude them

Example:

# Usually no files matched, because .github is hidden
pctx --no-default-excludes .github

# Include it explicitly
pctx --hidden --no-default-excludes .github

Pattern syntax

Patterns use gitignore-style matching.

PatternMatches
*.log.log files at any level
test_*Files or path components starting with test_
**/tests/**Any tests directory at any level
/src/generatedsrc/generated at the scan root
docs/A directory named docs
src/configsrc/config and files below it
src/config/Files below a directory named src/config

Examples:

exclude = [
    "*.log",
    "node_modules",
    "dist/",
    "**/*.generated.ts",
]

include = [
    "*.rs",
    "src/**/*.toml",
]

Pattern limitations

  • Negation patterns such as !important.log are not supported.
  • Unsupported negation patterns are ignored with a warning.
  • Character-class behavior such as [abc] depends on the underlying glob implementation.
  • Some **/ edge cases may differ from exact git behavior.
  • Leading ./ or .\ is stripped with a warning because include/exclude values are patterns, not positional paths.

Prefer positional paths when selecting a concrete directory:

# Good: scan this path
pctx src/config

# Also valid: pattern filtering
pctx --include "src/config"

Troubleshooting

No files matched

Try:

pctx --dry-run --verbose

Common causes:

  • The path is dot-prefixed and needs --hidden.
  • Include patterns are too restrictive.
  • A custom exclude pattern matched more than expected.
  • Built-in exclusions filtered the files.
  • .gitignore filtered the files.
  • Files exceeded --max-size.
  • Files are binary.

A hidden directory is still skipped

Use --hidden:

pctx --hidden .github

--no-default-excludes does not affect hidden-path filtering.

A config pattern did not behave like git

pctx supports gitignore-style patterns, but not every gitignore feature. Avoid negation patterns and test with:

pctx files list --dry-run

For file listing, use:

pctx files list --verbose

JSON & Exit Codes

Use --json for machine-readable output:

pctx --json

In JSON mode:

  • The structured response is written to stdout.
  • Progress and diagnostic messages are written to stderr.
  • Errors are also written to stdout as JSON.
  • The process exit code still indicates success or failure.
  • Requested side effects (--output FILE, --clipboard) are completed before the JSON response is printed, so a side-effect failure produces a single JSON error response rather than a success response followed by an error.

Capabilities

Integrations that need to detect which features a given pctx build supports can query them in a stable, machine-readable form:

pctx --json capabilities
{
  "schema_version": 1,
  "name": "pctx",
  "version": "1.1.0",
  "clipboard": true,
  "tokens": true,
  "json_output": true,
  "stdin": true,
  "stdin0": true,
  "paths_file0": true,
  "path_aliases": true,
  "formats": ["markdown", "xml", "plain"]
}

Response statuses

Every JSON response has a top-level status.

Possible values:

StatusMeaning
successOperation completed successfully
partialSome files were processed, but some failed or were skipped with errors
errorThe operation failed

Successful context response

pctx --json

Example shape:

{
  "status": "success",
  "data": {
    "content": "`src/lib.rs`:\n```rust\npub mod cli;\n```\n",
    "format": "markdown",
    "files": [
      {
        "path": "src/lib.rs",
        "extension": "rs",
        "size_bytes": 128,
        "line_count": 8,
        "truncated": false
      }
    ]
  },
  "stats": {
    "file_count": 1,
    "total_lines": 8,
    "total_bytes": 128,
    "truncated_count": 0,
    "skipped_count": 0,
    "token_estimate": 42,
    "duration_ms": 3
  }
}

Partial response

If some files fail but others succeed, pctx returns partial and exits with code 7.

Example:

{
  "status": "partial",
  "data": {
    "content": "...",
    "format": "markdown",
    "files": [
      {
        "path": "src/lib.rs",
        "extension": "rs",
        "size_bytes": 128,
        "line_count": 8,
        "truncated": false
      }
    ]
  },
  "stats": {
    "file_count": 1,
    "total_lines": 8,
    "total_bytes": 128,
    "truncated_count": 0,
    "skipped_count": 0,
    "token_estimate": 42,
    "duration_ms": 3
  },
  "errors": [
    {
      "path": "large.log",
      "code": "file_too_large",
      "message": "File too large (2000000 bytes, max 1048576): large.log",
      "transient": false
    }
  ]
}

Error response

Example:

{
  "status": "error",
  "code": "no_files_matched",
  "message": "No files matched the specified filters",
  "input": {
    "paths": [],
    "exclude": [],
    "include": ["*.rs"],
    "hidden": false,
    "no_default_excludes": false,
    "no_gitignore": false,
    "max_size_kb": 1024,
    "max_depth": 0,
    "stdin": false
  },
  "suggestion": "Include patterns are active; check whether the files match `--include` or the `include` entries in `.pctx.toml`.",
  "transient": false,
  "exit_code": 6
}

File list JSON

pctx files list --json

Example shape:

{
  "status": "success",
  "data": [
    {
      "path": "src/lib.rs",
      "extension": "rs",
      "size_bytes": 128,
      "truncated": false
    }
  ],
  "stats": {
    "file_count": 1,
    "total_lines": 0,
    "total_bytes": 0,
    "truncated_count": 0,
    "skipped_count": 0,
    "duration_ms": 0
  }
}

files list does not read file contents, so line_count is omitted.

Tree JSON

pctx files tree --json

Example shape:

{
  "status": "success",
  "data": {
    "tree": "src\n└── lib.rs\n"
  },
  "stats": {
    "file_count": 1,
    "total_lines": 0,
    "total_bytes": 0,
    "truncated_count": 0,
    "skipped_count": 0,
    "duration_ms": 0
  }
}

Error codes

Common machine-readable error codes include:

CodeMeaning
file_not_foundFile or directory does not exist
permission_deniedFile or directory could not be read
binary_fileFile appears to be binary
file_too_largeFile exceeds --max-size
encoding_errorFile encoding could not be handled
invalid_patternInclude/exclude pattern is invalid
no_files_matchedFilters matched no files
output_existsOutput file exists and --force was not used
git_errorGit command failed
config_errorConfig file could not be parsed or used
clipboard_errorClipboard write failed
io_errorGeneric I/O error
json_errorJSON serialization failed
walk_errorDirectory traversal failed
ignore_errorIgnore-pattern handling failed

Exit codes

Exit codes are part of the CLI contract.

Exit codeNameMeaning
0SuccessOperation completed successfully
1FailureGeneral or unspecified failure
2Usage errorInvalid arguments or bad flag combinations
3Not foundFile, directory, or config file not found
4Permission deniedCannot read a file or directory
5ConflictOutput file exists without --force
6No matchNo files matched filters
7PartialSome files succeeded and some failed

Scripting examples

# Extract generated context
pctx --json | jq -r '.data.content'

# Get included file paths
pctx --json | jq -r '.data.files[].path'

# Fail on partial success
response="$(pctx --json)"
status="$(printf '%s' "$response" | jq -r '.status')"
test "$status" = "success"

# List large files pctx would include
pctx files list --json \
  | jq -r '.data[] | select(.size_bytes > 10000) | .path'

# Use exit codes
if pctx --json > context.json; then
  echo "success"
else
  case "$?" in
    6) echo "no files matched" ;;
    7) echo "partial success" ;;
    *) echo "failed" ;;
  esac
fi

Architecture & Developer Guide

pctx is implemented in Rust as both a CLI application and a library crate.

The CLI entry point lives in src/main.rs. Most reusable functionality is exposed through modules under src/lib.rs.

High-level pipeline

A normal pctx run follows this pipeline:

CLI args
   │
   ▼
Config resolution
   │
   ▼
File discovery
   │
   ▼
Filtering
   │
   ▼
Content reading
   │
   ▼
Truncation
   │
   ▼
Formatting
   │
   ▼
Destination output

In JSON mode, the same pipeline is used, but responses are wrapped in structured JSON.

Module overview

ModulePurpose
cliDefines command-line arguments and subcommands with clap
configResolves defaults, .pctx.toml, and CLI overrides
scannerDiscovers candidate files from paths, git, stdin, or directory walking
filterHandles binary detection and gitignore-style include/exclude patterns
contentReads files and builds FileEntry values
content::truncatorApplies file and long-line truncation
outputFormats content and writes to stdout, files, or clipboard
output::json_typesDefines the structured JSON API
output::treeBuilds and renders file trees
statsTracks file counts, sizes, truncation counts, and token estimates
errorDefines typed errors, suggestions, and error codes
exit_codesDefines stable process exit codes

CLI layer

src/cli.rs defines:

  • global options such as --json, --verbose, --quiet, and --no-color
  • generate options, used when no subcommand is supplied
  • files list
  • files tree
  • config show
  • config init
  • config defaults
  • completions

The CLI is intentionally designed for both humans and automation:

  • Human-readable output goes to stdout or stderr depending on purpose.
  • JSON result payloads go to stdout.
  • Diagnostic messages go to stderr.
  • Exit codes communicate command outcome.

Configuration

Configuration is represented by Config in src/config/mod.rs.

Sources are merged in this order:

  1. CLI arguments
  2. .pctx.toml
  3. built-in defaults

The config file type is FileConfig in src/config/file.rs.

Currently, .pctx.toml supports:

  • exclude
  • include
  • truncation settings

Built-in exclusions are defined in src/config/defaults.rs.

Scanning

File discovery is handled by Scanner in src/scanner/mod.rs.

There are two primary scanning paths:

  1. Configured paths

    • Used by normal pctx generation.
    • Defaults to ..
    • Accepts files and directories.
  2. Explicit stdin paths

    • Used with --stdin.
    • Reads one path per line.
    • Expands directories recursively.

Directory traversal is implemented in src/scanner/walker.rs using the ignore crate.

When gitignore support is enabled and the target is inside a git repository, src/scanner/git.rs can use:

git ls-files -z --cached --others --exclude-standard

This gives git-aware file discovery for tracked and untracked files while respecting standard git exclusions.

Filtering model

Filtering happens in several layers:

  1. Traversal-level filtering

    • Hidden paths may be skipped during walking.
    • Gitignore rules may be applied during walking or git scanning.
    • Maximum depth may limit recursion.
  2. Pattern filtering

    • Built-in excludes
    • Config-file excludes
    • CLI excludes
    • Config-file includes
    • CLI includes
  3. File validation

    • Maximum file size
    • Binary detection

Hidden-path filtering is independent from default exclusions and gitignore rules.

Pattern matching

src/filter/patterns.rs implements gitignore-style matching using the glob crate.

Important behavior:

  • Simple patterns can match path components anywhere.
  • Multi-component patterns can match nested paths.
  • Trailing slash patterns match directories.
  • Leading / anchors a pattern to the scan root.
  • Negation patterns are not supported.

Binary detection

src/filter/binary.rs detects binary files using:

  • known binary extensions
  • common magic-byte signatures
  • null-byte checks
  • non-printable byte ratio

Binary files are skipped before content processing.

Content processing

ContentProcessor in src/content/mod.rs turns paths into FileEntry values.

A FileEntry contains:

  • absolute path
  • relative display path
  • extension
  • original byte count
  • original line count
  • processed line count
  • truncation metadata
  • processed content

Files are read by src/content/reader.rs.

Invalid UTF-8 is converted lossily rather than failing immediately, which makes pctx tolerant of mixed or imperfect text encodings.

Truncation

src/content/truncator.rs handles two truncation modes:

  1. File-level truncation

    • Triggered when a file exceeds max_lines.
    • Preserves the configured head and tail line counts.
    • Inserts an omission marker.
  2. Line-level truncation

    • Triggered when a line exceeds max_line_length.
    • Preserves the configured head and tail character counts.
    • Inserts a character omission marker.

0 disables the corresponding truncation limit.

Formatting

Formatting lives in src/output/formatter.rs.

Supported formats:

FormatDescription
markdownFile labels and fenced code blocks
xmlXML document with file contents in CDATA
plainSimple text separators

Markdown formatting automatically grows code fences if file content already contains triple backticks.

XML formatting escapes attributes and protects against CDATA termination sequences.

Output destinations

Output destination handling is split across:

  • src/output/stdout.rs
  • src/output/file.rs
  • src/output/clipboard.rs

File output uses an atomic create-new behavior by default, so existing files are not overwritten unless --force is supplied.

JSON API

Structured JSON types are defined in src/output/json_types.rs.

Top-level responses are:

  • success
  • partial
  • error

Errors include:

  • machine-readable code
  • message
  • optional input context
  • optional suggestion
  • transient flag
  • exit code

The JSON API is intended for scripts, CI jobs, and agent harnesses.

Errors and exit codes

src/error.rs defines PctxError.

Each error can provide:

  • display message
  • machine-readable code
  • suggested fix
  • transient/non-transient classification
  • structured input context
  • exit code

Stable exit code constants are defined in src/exit_codes.rs.

When changing exit codes, update:

  1. src/exit_codes.rs
  2. CLI help text in src/cli.rs
  3. user documentation
  4. scripts or integrations that depend on the code

Statistics

src/stats.rs tracks:

  • file count
  • total original lines
  • total original bytes
  • truncated file count
  • skipped count
  • approximate token estimate
  • duration

Token estimation uses a tokenizer when compiled with token support; otherwise it falls back to an approximate character-based estimate.

Tests

The project includes unit tests for:

  • config loading and merging
  • default exclusions
  • content processing
  • truncation
  • binary detection
  • pattern matching
  • output formatting
  • tree rendering
  • stats formatting
  • error metadata

Snapshot tests are used for formatter and tree output.

Run tests with:

cargo test

If an intentional formatting change affects snapshots, review/update snapshots with the normal insta workflow.

Developer workflow

Useful commands:

# Format code
cargo fmt

# Lint
cargo clippy --all-targets --all-features

# Run tests
cargo test

# Build release binary
cargo build --release

# Try the CLI locally
cargo run -- --help
cargo run -- --dry-run --tree
cargo run -- files list --quiet

Build and serve documentation:

cd docs
mdbook serve

Extension points

Common areas to extend:

GoalLikely files
Add a CLI flagsrc/cli.rs, src/config/mod.rs, docs
Add a config keysrc/config/file.rs, src/config/mod.rs, docs
Add an output formatsrc/cli.rs, src/output/formatter.rs, snapshot tests
Change default excludessrc/config/defaults.rs, docs
Improve pattern behaviorsrc/filter/patterns.rs
Change JSON response shapesrc/output/json_types.rs, docs
Add a new subcommandsrc/cli.rs, src/main.rs, docs

Notes for maintainers

  • Keep CLI help and documentation in sync.
  • Keep JSON response shapes stable where possible.
  • Treat exit codes as public API.
  • Prefer adding tests for filtering and formatting changes.
  • Be careful when changing hidden-file behavior; it is intentionally independent from default exclusions and gitignore rules.