Runex

A context generation tool to bring vibe coding in your life… or do even more.

pip install runex

Introduction

runex is a python tool that generates a plain-text or json representation of a project’s directory structure (plus file contents), following Git’s own .gitignore path and file matching rules.

Everything’s close enough… until it isn't.

[!NOTE] Before using this program it is highly recommended you read the Use of AI during development paragraph


Example output(s)

Let’s see if this can be good for you, will it be love at first sight?

Default behavior

plain-text

no args needed

You ask:

runex .

You get:

Project Structure:

my-project/
├── .gitignore
├── src/
│   └── next-big-thing.py
└── tests/


# File: next-big-thing.py
# Path: src/next-big-thing.py

#!/usr/bin/env python
"""
Hey there
"""
    
if __name__ == "__main__":
    print("Hello World!")

json

add -oj

You ask:

runex . -oj

You get:

{
  "structure": {
    "name": "my-project",
    "children": [
      {
        "name": ".gitignore"
      },
      {
        "name": "src",
        "children": [
          {
            "name": "next-big-thing.py"
          }
        ]
      },
      {
        "name": "tests",
        "children": []
      }
    ]
  },
  "files": [
    {
      "filename": "next-big-thing.py",
      "path": "src/next-big-thing.py",
      "content": "#!/usr/bin/env python\n\"\"\"\nHey there\n\"\"\"\n    \nif __name__ == \"__main__\":\n    print(\"Hello World!\")\n"
    }
  ]
}

No need for file contents?

just add -s

plain text

You ask:

runex . -s

You get:

Project Structure:

my-project/
├── .gitignore
├── src/
│   └── next-big-thing.py
└── tests/

json

You ask:

runex . -oj -s

You get:

{
  "structure": {
    "name": "my-project",
    "children": [
      {
        "name": ".gitignore"
      },
      {
        "name": "src",
        "children": [
          {
            "name": "next-big-thing.py"
          }
        ]
      },
      {
        "name": "tests",
        "children": []
      }
    ]
  }
}

So, you got this far.

You might need this tool?
Well…

What have we learned other than that? > Answer: _You ask, You get_

Purpose of This Program

The og scope of the program was to cater the need for an easy and quick way (see rfc1925 point 7a) of providing “context” to a large language model service, without painstakingly ctrl-c and ctrl-v(ing) source code out of the IDE into the browser, all while t(c)rying to explain to the llm where a file should be read from and what it should actually do. (you still have to paste it back to the IDE so at least it’s almost half of the work done)

If you want that, we (me and gpt) will have a runex visual studio code extension available. (COMING-SOON)


Usage - Deep Dive

runex [--help] [--casefold] [--json] [--only-structure] [--relative-root] <root_dir> [output_file]

Positional arguments:

Options:

In the default mode, after traversing the specified project directory, runex builds and concatenates into a single file (or stdout):

  1. A pretty-printed tree-style output of the folder structure (excluding ignored paths).
  2. A concatenated listing of the file contents found along it’s path (excluding ignored files).

The same output can be also requested in a json format and for both you can request only the structure of the project to be returned.


Examples

Tool executed with the --only-structure arg on the “.” directory:

runex . -s
Project Structure:

runex/
├── .gitignore
├── LICENSE
├── README.md
├── json_test_cases/
│   ├── t_00.json
│   ├── t_01.json
│   ├── t_02.json
│   ├── t_03.json
│   ├── t_04.json
│   ├── t_05.json
│   ├── t_06.json
│   ├── t_07.json
│   ├── t_08.json
│   ├── t_09.json
│   ├── t_10.json
│   ├── t_11.json
│   ├── t_12.json
│   └── t_13.json
├── poetry.lock
├── pyproject.toml
├── runex/
│   ├── __init__.py
│   ├── cli.py
│   ├── core.py
│   ├── ignore_logic.py
│   └── wildmatch.py
└── tests/
    ├── __init__.py
    ├── all_unicode_posix_extended_test.py
    ├── all_unicode_posix_test.py
    ├── custom_posix_test.py
    ├── deepseek_test.py
    ├── extreme_test.py
    ├── gitignore_doc_json_test.py
    ├── ignore_logic_test.py
    ├── posix_test.py
    ├── prompt_generation_test.py
    ├── prompt_generator_json_test.py
    ├── suite_test.py
    ├── te_test.py
    └── wildmatch_test.py

Tool executed with the --only-structure and --json args on the “.” directory:

runex . -oj -s
{
  "structure": {
    "name": "codetext",
    "children": [
      {
        "name": ".gitignore"
      },
      {
        "name": "LICENSE"
      },
      {
        "name": "README.md"
      },
      {
        "name": "json_test_cases",
        "children": [
          {
            "name": "t_00.json"
          },
          {
            "name": "t_01.json"
          },
          {
            "name": "t_02.json"
          },
          {
            "name": "t_03.json"
          },
          {
            "name": "t_04.json"
          },
          {
            "name": "t_05.json"
          },
          {
            "name": "t_06.json"
          },
          {
            "name": "t_07.json"
          },
          {
            "name": "t_08.json"
          },
          {
            "name": "t_09.json"
          },
          {
            "name": "t_10.json"
          },
          {
            "name": "t_11.json"
          },
          {
            "name": "t_12.json"
          },
          {
            "name": "t_13.json"
          }
        ]
      },
      {
        "name": "poetry.lock"
      },
      {
        "name": "pyproject.toml"
      },
      {
        "name": "runex",
        "children": [
          {
            "name": "__init__.py"
          },
          {
            "name": "cli.py"
          },
          {
            "name": "core.py"
          },
          {
            "name": "ignore_logic.py"
          },
          {
            "name": "wildmatch.py"
          }
        ]
      },
      {
        "name": "tests",
        "children": [
          {
            "name": "__init__.py"
          },
          {
            "name": "all_unicode_posix_extended_test.py"
          },
          {
            "name": "all_unicode_posix_test.py"
          },
          {
            "name": "custom_posix_test.py"
          },
          {
            "name": "deepseek_test.py"
          },
          {
            "name": "extreme_test.py"
          },
          {
            "name": "gitignore_doc_json_test.py"
          },
          {
            "name": "ignore_logic_test.py"
          },
          {
            "name": "posix_test.py"
          },
          {
            "name": "prompt_generation_test.py"
          },
          {
            "name": "prompt_generator_json_test.py"
          },
          {
            "name": "suite_test.py"
          },
          {
            "name": "te_test.py"
          },
          {
            "name": "wildmatch_test.py"
          }
        ]
      }
    ]
  }
}

The plain text output without the -s will output everything, following the .gitignore rules:

Project Structure:

...tree representation...

# File: README.md
# Path: README.md

# Runex

`runex` is a python tool that generates a plain text or json representation of a project's directory structure (plus file contents) following Git's `.gitignore` path and file matching rules.

Without further ado let's share the motto of this project:

_Well_ <br>
_I guess that it's close enough until it isn't._

etc etc etc etc

The json output will follow this standard:

That’s how you will be able to differentiate between them.

In -s mode the following will be omitted:


Testing

The goal of this program is to mimic 100% the .gitignore logic, so we need a way of testing that.

The initial tests during development were written with AI in an unreliable way (you will find them under the tests directory) and were a pain to maintain.

So now, there is a single test file that actually matters, it is: tests/suite_test.py

This, will read and execute against runex’s json output, multiple test cases, written and evaluated by a human, found in a specific dedicated folder json_test_cases all following the naming t_*.json.

This will enable you to just submit truly tested cases to which the expected git behavior is known, this way we can just make this implementation bulletproof.

The test format goes as follows:

ex, t_00.json

{
    "gitignore": [],
    "initial_structure": {
        "structure": {
            "name": "project",
            "children": [
                {"name": ".gitignore"},
                {"name": "file.txt"}
            ]
        }
    },
    "tracked_structure": {
        "structure": {
            "name": "project",
            "children": [
                {"name": ".gitignore"},
                {"name": "file.txt"}
            ]
        }
    }
}

That’s it, a json file:

If the output produced by runex when run against initial_structure matches 100% the tracked_structure the single test case will be passed.

What about nested .gitignore files?

This is how you can do it:

{
    "gitignore": ["file.txt"],
    "initial_structure": {
        "structure": {
            "name": "project",
            "children": [
                {
                    "name": ".gitignore",
                    "contents": ["!file.txt"]
                },
                {"name": "file.txt"}
            ]
        }
    },
    "tracked_structure": {
        "structure": {
            "name": "project",
            "children": [
                {"name": ".gitignore"},
                {"name": "file.txt"}
            ]
        }
    }
}

In the initial_structure if you create a child named .gitignore and you give it a contents key whose value is an array structured just like the array in the simple test cases described before, upon folder creation that file will be written with the specified contents.
If no contents are provided the program will just leave it empty.

Please, write a lot of edge cases that will make this program literally burn, this is the only way it will become better.

I mean everything, posix bracket expressions, unicode characters, nested structures combined and coordinated firework explosions etcetera.

At tests/suite_test.py there is the code that will run all of the t_*.json test cases present in the json_test_cases folder.

The other tests found under tests all pass for now, so in theory the program should be kept so that they keep passing in the future, but given that they were all AI generated… they might just be wrong, a lot of them are duplicated, and i’m not even sure what all of them actually do, they are too many, and i’m too lazy, so, you’ll do the work if you want the tool!

The main intended way of testing this program from now on is adding tests under the folder json_test_cases


Use of AI during development

Keep in mind: this was written extensively with the use of AI llm models, in particular you can find code from OpenAI o3-mini-high, o3-mini - Deepseek R1 - Gemini 2.0 Flash

o3-mini-high overrall kept this project together,
when it got stuck i used Deepseek R1 to get it-unstuck,
Gemini 2.0 Flash, well i played with it for a while but for now wasn’t really helpful (it truly wasn’t i can safely say now)

Code and Comments as well as knowledge on how git works come from the AI, and i just kind of directed the whole thing by approximation and intuition, in fact, the only thing that is not AI generated is this readme.

This code is not guaranteed to mimic 100% the behavior of the .gitignore ignore logic of the master and commander (c git) - it is the dream though, but, well, don’t ask for the differences between .gitignore and this, because the AI doesn’t know for now, and i certainly don’t. I guess that it’s close enough.


Hopefully it was useful!