Skip to content

jeffmm/project-context

Repository files navigation

Project Context

Generate LLM-friendly markdown from your project files.

CI/CD codecov PyPI version

Project Context Generator

project-context is a Python tool that generates LLM-friendly markdown documentation of your entire project structure and contents. It creates a single markdown file containing both a visual tree representation of your project and the actual content of your source files, making it easy to share your codebase context with AI assistants.

Key Features

  • Intelligent file filtering: Automatically respects .gitignore files and Git tracking status
  • Flexible inclusion/exclusion: Use regex patterns to precisely control which files are included or excluded
  • Customizable output: Support for custom Jinja2 templates to format the output
  • Smart content selection: Automatically includes the most common file type in your project for markdown output
  • Pre-commit integration: Can automatically generate context files on every commit

Example

Let's say you have a basic Python package with this structure:

hello-world-pkg/
├── .gitignore
├── README.md
├── pyproject.toml
└── src/
    └── hello_world/
        ├── __init__.py
        └── main.py

Where src/hello_world/main.py contains:

def main():
    print("Hello, World!")

if __name__ == "__main__":
    main()

Running project-context from the project root would generate the following output to stdout:

# hello-world-pkg

## Project Structure

hello-world-pkg/
├── .gitignore
├── README.md
├── pyproject.toml
└── src/
    └── hello_world/
        ├── __init__.py
        └── main.py

## Project Contents

### src/hello_world/main.py

```
def main():
    print("Hello, World!")

if __name__ == "__main__":
    main()
```

This single markdown file now contains your entire project context in a format that's perfect for pasting into ChatGPT, Claude, Gemini, or any other LLM when you need help with your code!

Usage

Installation

Using uv (recommended)

uv tool install project-context

Evoke using uvx project-context

Using pip

pip install project-context

Evoke using project-context

Basic Usage

By default, all files tracked by Git are included in the directory tree.

Generate context for the current directory and write it to stdout:

project-context

Save output to a file:

project-context -o CONTEXT.md

Customizing the Output

By default, all files that are tracked by Git are included in the directory tree in the Project structure section, and only the most common file type is included as part of the Project contents section. In the above example, the only file included was src/hello_world/main.py since .py is the most common file type in this project (__init__.py was excluded since it was empty).

Command Line Options

Flag Description Example
--root, -r Root directory to use. Defaults to the current working directory. -r my-repo
--exclude, -e Regex patterns to exclude paths from the tree -e 'test.*'
--include, -i Only include paths matching these regex patterns -i '.*\.py$' -i '.*\.y[a]?ml$
--always-include, -a Always include these paths regardless of exclusion rules -a 'README.*'
--contents, -c Regex patterns to include paths matching these patterns in contents section -c '.*\.py$' -c '^README\.*'
--output, -o Output file path (prints to stdout if not specified) -o CONTEXT.md
--template, -t Path to custom Jinja2 template file -t my_template.md.j2

Important: Be careful to escape your regex args properly. Notice the use of single quotes around regex patterns to avoid issues due to shell expansion.

All regex flags can be specified multiple times to include/exclude multiple patterns, and combined as needed.

For any file in the root directory, the inclusion/exclusion rules are applied in the following order:

Project Structure ("tree") Inclusion/Exclusion Rules

  • IF the path matches any pattern in always-include, THEN it is included in the tree
  • ELSE IF the path matches any pattern in exclude, THEN it is excluded from the tree
  • ELSE IF there are include patterns THEN
    • IF the path matches any pattern in include, THEN it is included in the tree
    • ELSE it is excluded from the tree
  • ELSE IF the path is a file tracked by Git, THEN it is included in the tree
  • ELSE IF the path is a file that is ignored using a .gitignore, THEN it is excluded from the tree
  • ELSE IF the path is a dot-file (ie its name starts with a .), THEN it is excluded from the tree
  • ELSE the path is included in the tree

Project Contents Inclusion/Exclusion Rules

  • IF the path is included in the tree, THEN
    • IF there are contents patterns, THEN
      • IF the path matches any patterns in contents, THEN its contents are included in the contents section
      • ELSE the path's contents are excluded from the contents section
    • ELSE IF the path suffix is the most common file type in the project, THEN its contents are included in the contents section
    • ELSE the path's contents are excluded from the contents section
  • ELSE the path's contents are excluded from the contents section

Advanced Usage Examples

Write the context of a subdirectory to a custom dot-file:

project-context -r src/my_project -o src/my_project/.context.md

Include Python files, YAML files, and markdown files in the content section:

project-context -c '.*\.(py|md|yaml)$'

Exclude multiple patterns from the project context:

project-context -e '^\..*' -e '.*\.yaml$'

Exclude all YAML files, except for your .pre-commit-config.yaml:

project-context -e '.*\.yaml$' -a '\.pre-commit-config\.yaml'

Only include typescript files and README files:

project-context -i '.*\.ts$' -a 'README.*'

Generate the output using a custom template and write to file:

project-context -t custom_template.md.j2 -o CONTEXT.md

Pre-commit Hook Integration

For automated context generation on each commit, add this to your .pre-commit-config.yaml:

repos:
  - repo: https://github.com/jeffmm/project-context
    rev: main  # or specific version tag
    hooks:
      - id: project-context
        name: Generate LLM context from project contents
        files: ''  # change as needed if you only want to update when specific files change
        args: ['-o', 'CONTEXT.md']  # default args, update as needed

Important: Consider adding CONTEXT.md to your .gitignore file if you don't want to track the generated context file in your repository, since it effectively duplicates your project contents.

The pre-commit hook will automatically regenerate the context file whenever you make a commit, ensuring your project context is always up-to-date for sharing with LLMs.

Jinja2 Template Customization

The default output template is:

# {{ root }}

## Project Structure

{{ tree }}

## Project Contents

{{ contents }}

For a well-documented project, the default can work well enough on its own, but you can further customize the output format by providing your own Jinja2 template file. This can be useful for providing additional context or constraints that might improve the quality of AI responses.

project-context defines three variables for rendering the output: root, tree, and contents.

For example, using a template like this would add a header to the context with some project-specific details that can help steer the LLM to produce output that's more aligned to your project's needs:

{# custom_template.md.j2 #}
# {{ root }}

## Project Description

### High-level Overview:
Here is a brief description of the project and its purpose...

### Project Roadmap
Here is the planned roadmap for the project...

### Developer Guidelines
Here are some guidelines and constraints on how the project should be maintained...

## Project Structure

{{ tree }}

## Project Contents

{{ contents }}

Then you can generate the context using your custom template like this:

project-context -t custom_template.md.j2 -o CONTEXT.md

About

Generate LLM-friendly markdown from your project files.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages