{"id":26777844,"url":"https://github.com/bluejay909/runex","last_synced_at":"2026-04-27T12:02:55.848Z","repository":{"id":284449815,"uuid":"954233992","full_name":"BlueJay909/runex","owner":"BlueJay909","description":"Runex - a python tool that generates a plain-text or json representation of a project's directory structure and file contents following Git's .gitignore path and file matching rules.","archived":false,"fork":false,"pushed_at":"2025-06-05T15:28:54.000Z","size":185,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-05T16:35:31.717Z","etag":null,"topics":["context-generation","json","project-structure","python","tree","vibe-coding"],"latest_commit_sha":null,"homepage":"https://bluejay909.github.io/runex/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BlueJay909.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-03-24T19:06:33.000Z","updated_at":"2025-06-05T15:28:56.000Z","dependencies_parsed_at":null,"dependency_job_id":"54f1b544-910f-46aa-a21d-81a8c745eb19","html_url":"https://github.com/BlueJay909/runex","commit_stats":null,"previous_names":["bluejay909/runex"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/BlueJay909/runex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlueJay909%2Frunex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlueJay909%2Frunex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlueJay909%2Frunex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlueJay909%2Frunex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BlueJay909","download_url":"https://codeload.github.com/BlueJay909/runex/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlueJay909%2Frunex/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32335297,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["context-generation","json","project-structure","python","tree","vibe-coding"],"created_at":"2025-03-29T05:18:13.119Z","updated_at":"2026-04-27T12:02:55.842Z","avatar_url":"https://github.com/BlueJay909.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Runex\n\u003e A context generation tool to bring vibe coding in your life... or do even more.\n\n```bash\npip install runex\n```\n---\n\n## Introduction\n\n`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.\n\n\u003e _Everything's close enough... `until it isn't.`_\n\n\u003e [!NOTE]\n\u003e Before using this program it is highly recommended you read the [`Use of AI during development`](#use-of-ai-during-development) paragraph\n\n---\n\n## Example output(s)\n\n_Let's see if this can be good for you, will it be love at first sight?_\n\n### Default behavior\n\n#### `plain-text`\n\u003e no args needed\n\n**You ask:**\n```bash\nrunex .\n```\n\n**You get:**\n```plaintext\nProject Structure:\n\nmy-project/\n├── .gitignore\n├── src/\n│   └── next-big-thing.py\n└── tests/\n\n\n# File: next-big-thing.py\n# Path: src/next-big-thing.py\n\n#!/usr/bin/env python\n\"\"\"\nHey there\n\"\"\"\n    \nif __name__ == \"__main__\":\n    print(\"Hello World!\")\n```\n\n#### `json`\n\u003e add `-oj`\n\n**You ask:**\n```bash\nrunex . -oj\n```\n\n**You get:**\n```json\n{\n  \"structure\": {\n    \"name\": \"my-project\",\n    \"children\": [\n      {\n        \"name\": \".gitignore\"\n      },\n      {\n        \"name\": \"src\",\n        \"children\": [\n          {\n            \"name\": \"next-big-thing.py\"\n          }\n        ]\n      },\n      {\n        \"name\": \"tests\",\n        \"children\": []\n      }\n    ]\n  },\n  \"files\": [\n    {\n      \"filename\": \"next-big-thing.py\",\n      \"path\": \"src/next-big-thing.py\",\n      \"content\": \"#!/usr/bin/env python\\n\\\"\\\"\\\"\\nHey there\\n\\\"\\\"\\\"\\n    \\nif __name__ == \\\"__main__\\\":\\n    print(\\\"Hello World!\\\")\\n\"\n    }\n  ]\n}\n```\n\n---\n\n### No need for file contents?\n\u003e just add `-s`\n\n#### `plain text`\n\n**You ask:**\n```bash\nrunex . -s\n```\n\n**You get:**\n```plaintext\nProject Structure:\n\nmy-project/\n├── .gitignore\n├── src/\n│   └── next-big-thing.py\n└── tests/\n```\n\n#### `json`\n\n**You ask:**\n```bash\nrunex . -oj -s\n```\n\n**You get:**\n```json\n{\n  \"structure\": {\n    \"name\": \"my-project\",\n    \"children\": [\n      {\n        \"name\": \".gitignore\"\n      },\n      {\n        \"name\": \"src\",\n        \"children\": [\n          {\n            \"name\": \"next-big-thing.py\"\n          }\n        ]\n      },\n      {\n        \"name\": \"tests\",\n        \"children\": []\n      }\n    ]\n  }\n}\n```\n\n---\n\nSo, you got this far.\n\nYou _might_ need this tool? \u003cbr\u003e\nWell...\n\n\u003cdetails\u003e\n  \u003csummary\u003eWhat have we learned other than that?\u003c/summary\u003e\n  \n  \u003e Answer:  \n  _You ask, You get_ \u003cbr\u003e\n\u003c/details\u003e\n\n---\n\n## Purpose of This Program\n\nThe _og_ scope of _the program_ was to cater the need for an easy and quick way ([see rfc1925 point 7a](https://www.rfc-editor.org/rfc/rfc1925.txt)) 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)\n\nIf you want that, _we_ (me and gpt) will have a [`runex visual studio code extension`](#) available. (COMING-SOON)\n\n---\n\n## Usage - Deep Dive\n\n```bash\nrunex [--help] [--casefold] [--json] [--only-structure] [--relative-root] \u003croot_dir\u003e [output_file]\n```\n\n### Positional arguments:\n- **root_dir**  \n  Root directory of the project to be scanned\n- **output_file**  \n  Optional output file (default: stdout)\n\n### Options:\n- `--help`  \n  show this help message and exit\n- `--casefold, -c`  \n  Enable case-insensitive matching (WM_CASEFOLD)\n- `--json, -oj`  \n  Output JSON instead of text\n- `--only-structure, -s`  \n  Omit file contents in the output\n- `--relative-root, -rr`  \n  Force the root directory name to be '.' instead of basename\n\nIn the default mode, after traversing the specified project directory, `runex` builds and concatenates into a single file (or stdout):\n\n1. A pretty-printed tree-style output of the folder structure (excluding ignored paths).\n2. A concatenated listing of the file contents found along it's path (excluding ignored files).\n\nThe 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.\n\n---\n\n## Examples\n\n### Tool executed with the `--only-structure` arg on the \".\" directory:\n\n```bash\nrunex . -s\n```\n\n```plaintext\nProject Structure:\n\nrunex/\n├── .gitignore\n├── LICENSE\n├── README.md\n├── json_test_cases/\n│   ├── t_00.json\n│   ├── t_01.json\n│   ├── t_02.json\n│   ├── t_03.json\n│   ├── t_04.json\n│   ├── t_05.json\n│   ├── t_06.json\n│   ├── t_07.json\n│   ├── t_08.json\n│   ├── t_09.json\n│   ├── t_10.json\n│   ├── t_11.json\n│   ├── t_12.json\n│   └── t_13.json\n├── poetry.lock\n├── pyproject.toml\n├── runex/\n│   ├── __init__.py\n│   ├── cli.py\n│   ├── core.py\n│   ├── ignore_logic.py\n│   └── wildmatch.py\n└── tests/\n    ├── __init__.py\n    ├── all_unicode_posix_extended_test.py\n    ├── all_unicode_posix_test.py\n    ├── custom_posix_test.py\n    ├── deepseek_test.py\n    ├── extreme_test.py\n    ├── gitignore_doc_json_test.py\n    ├── ignore_logic_test.py\n    ├── posix_test.py\n    ├── prompt_generation_test.py\n    ├── prompt_generator_json_test.py\n    ├── suite_test.py\n    ├── te_test.py\n    └── wildmatch_test.py\n```\n\n---\n\n### Tool executed with the `--only-structure` and `--json` args on the \".\" directory:\n\n```bash\nrunex . -oj -s\n```\n\n```json\n{\n  \"structure\": {\n    \"name\": \"codetext\",\n    \"children\": [\n      {\n        \"name\": \".gitignore\"\n      },\n      {\n        \"name\": \"LICENSE\"\n      },\n      {\n        \"name\": \"README.md\"\n      },\n      {\n        \"name\": \"json_test_cases\",\n        \"children\": [\n          {\n            \"name\": \"t_00.json\"\n          },\n          {\n            \"name\": \"t_01.json\"\n          },\n          {\n            \"name\": \"t_02.json\"\n          },\n          {\n            \"name\": \"t_03.json\"\n          },\n          {\n            \"name\": \"t_04.json\"\n          },\n          {\n            \"name\": \"t_05.json\"\n          },\n          {\n            \"name\": \"t_06.json\"\n          },\n          {\n            \"name\": \"t_07.json\"\n          },\n          {\n            \"name\": \"t_08.json\"\n          },\n          {\n            \"name\": \"t_09.json\"\n          },\n          {\n            \"name\": \"t_10.json\"\n          },\n          {\n            \"name\": \"t_11.json\"\n          },\n          {\n            \"name\": \"t_12.json\"\n          },\n          {\n            \"name\": \"t_13.json\"\n          }\n        ]\n      },\n      {\n        \"name\": \"poetry.lock\"\n      },\n      {\n        \"name\": \"pyproject.toml\"\n      },\n      {\n        \"name\": \"runex\",\n        \"children\": [\n          {\n            \"name\": \"__init__.py\"\n          },\n          {\n            \"name\": \"cli.py\"\n          },\n          {\n            \"name\": \"core.py\"\n          },\n          {\n            \"name\": \"ignore_logic.py\"\n          },\n          {\n            \"name\": \"wildmatch.py\"\n          }\n        ]\n      },\n      {\n        \"name\": \"tests\",\n        \"children\": [\n          {\n            \"name\": \"__init__.py\"\n          },\n          {\n            \"name\": \"all_unicode_posix_extended_test.py\"\n          },\n          {\n            \"name\": \"all_unicode_posix_test.py\"\n          },\n          {\n            \"name\": \"custom_posix_test.py\"\n          },\n          {\n            \"name\": \"deepseek_test.py\"\n          },\n          {\n            \"name\": \"extreme_test.py\"\n          },\n          {\n            \"name\": \"gitignore_doc_json_test.py\"\n          },\n          {\n            \"name\": \"ignore_logic_test.py\"\n          },\n          {\n            \"name\": \"posix_test.py\"\n          },\n          {\n            \"name\": \"prompt_generation_test.py\"\n          },\n          {\n            \"name\": \"prompt_generator_json_test.py\"\n          },\n          {\n            \"name\": \"suite_test.py\"\n          },\n          {\n            \"name\": \"te_test.py\"\n          },\n          {\n            \"name\": \"wildmatch_test.py\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\nThe `plain text` output without the `-s` will output everything, following the `.gitignore` rules:\n\n```plaintext\nProject Structure:\n\n...tree representation...\n\n# File: README.md\n# Path: README.md\n\n# Runex\n\n`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.\n\nWithout further ado let's share the motto of this project:\n\n_Well_ \u003cbr\u003e\n_I guess that it's close enough until it isn't._\n\netc etc etc etc\n```\n\nThe `json` output will follow this standard:\n- files will never have a children attribute  \n- directories, even if empty, will always have a children attribute\n\nThat's how you will be able to differentiate between them.\n\nIn `-s` mode the following will be omitted:\n- \"path\" - full file path  \n- \"content\" - actual file source content\n\n---\n\n## Testing\n\nThe goal of this program is to mimic 100% the `.gitignore` logic, so we need a way of testing that.\n\nThe 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.\n\nSo now, there is a single test file that actually matters, it is: `tests/suite_test.py`\n\nThis, 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`.\n\nThis 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.\n\nThe test format goes as follows:\n\n#### ex, t_00.json\n```json\n{\n    \"gitignore\": [],\n    \"initial_structure\": {\n        \"structure\": {\n            \"name\": \"project\",\n            \"children\": [\n                {\"name\": \".gitignore\"},\n                {\"name\": \"file.txt\"}\n            ]\n        }\n    },\n    \"tracked_structure\": {\n        \"structure\": {\n            \"name\": \"project\",\n            \"children\": [\n                {\"name\": \".gitignore\"},\n                {\"name\": \"file.txt\"}\n            ]\n        }\n    }\n}\n```\n\nThat's it, a `json` file:\n\n- `\"gitignore\": []` is an array containing strings that represent ignore rules, `\"gitignore\": [\"file.txt\", \"file2.csv\"]` ignores those two files, `\"gitignore\": [\"!file.txt\", \"!file2.csv\"]` unignores them and so on, see each element of the array as being one line of a `.gitignore`.\n\n- `\"initial_structure\"` will be used by the script to build, using `tempfile`, the actual directory and file structure to test against  \n    - the `.gitignore`, if present in the `initial_structure`, will be populated with the contents found in the array of _step 1_.\n\n- `\"tracked_structure\"` is the expected behavior, if our script correctly mimics `.gitignore` rules, it will produce this output.\n\nIf the output produced by `runex` when run against `initial_structure` matches 100% the `tracked_structure` the single test case will be passed.\n\n### What about nested `.gitignore files`?\n\nThis is how you can do it:\n```json\n{\n    \"gitignore\": [\"file.txt\"],\n    \"initial_structure\": {\n        \"structure\": {\n            \"name\": \"project\",\n            \"children\": [\n                {\n                    \"name\": \".gitignore\",\n                    \"contents\": [\"!file.txt\"]\n                },\n                {\"name\": \"file.txt\"}\n            ]\n        }\n    },\n    \"tracked_structure\": {\n        \"structure\": {\n            \"name\": \"project\",\n            \"children\": [\n                {\"name\": \".gitignore\"},\n                {\"name\": \"file.txt\"}\n            ]\n        }\n    }\n}\n```\n\nIn 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.  \nIf no contents are provided the program will just leave it empty.\n\nPlease, write a lot of edge cases that will make this program **_literally burn_**, this is the only way it will become better.\n\nI mean everything, posix bracket expressions, unicode characters, nested structures combined and coordinated firework explosions etcetera.\n\nAt `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.\n\nThe 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!_**\n\nThe main intended way of testing this program from now on is adding tests under the folder `json_test_cases`\n\n---\n\n## Use of AI during development\n\n**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\n\n`o3-mini-high` overrall kept this project together,  \nwhen it got stuck i used `Deepseek R1` to get it-unstuck,  \n`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)\n\nCode 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.\n\nThis 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.\n\n---\n\nHopefully it was useful!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbluejay909%2Frunex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbluejay909%2Frunex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbluejay909%2Frunex/lists"}