Manage read-only external projects for AI coding assistants.
Project description
ki2-externai
🔒 Manage read-only external projects for AI coding assistants (Codex, Copilot, etc.)
ki2-externai is a tiny command-line tool that lets you mount external libraries or frameworks in read-only mode inside your project.
It’s especially useful when working with code-assistant tools (e.g. OpenAI Codex) that need to see your internal frameworks, but should never modify them.
🧠 Why?
When developing with AI assistants, sometimes you want the assistant to explore your internal codebases (frameworks, utils, etc.) to understand project context — but you don’t want it to modify them.
ki2-externai makes this safe and transparent:
- Every external library is visible inside your project,
- but physically read-only thanks to
mount --bind+remount,ro, - and easily reversible.
Works great in Linux and WSL2.
🚀 Quick start
1. Install
# Recommended for CLI tools (isolated, global command)
pipx install ki2-externai
# Alternative (inside an existing Python environment)
pip install ki2-externai
2. Register projects once (from inside them)
cd /path/to/libA
externai register libA
This stores a name → absolute path mapping in your OS data dir (e.g.
~/.local/share/ki2/externai/registry.json). If you omit a name, the folder name
is used.
3. Link externals inside your project (CLI creates config)
cd /path/to/your-project
externai add libA
If externai.json is missing, externai add creates a minimal config before
appending the entry.
4. Mount everything read-only
externai mount
This creates one folder per import under .externals/ (e.g. .externals/libA).
Each entry is a bind mount that is then remounted read-only.
5. Check status (or unmount)
externai status
Output example:
name src_exists mounted mount_source ntfs-ish?
-----------------------------------------------------------------------------------------------
libA yes mounted /home/adrien/dev/libA no
externai unmount
⚙️ Commands
| Command | Description |
|---|---|
externai mount |
Mount all configured externals in read-only mode |
externai unmount |
Unmount all externals |
externai status |
Show status table |
externai doctor |
Run system checks (detect NTFS / missing tools) |
externai register |
Register the current directory (optional custom name) |
externai unregister |
Remove a registry entry (by name or current folder) |
externai registry |
List every registered name and its source path |
externai add |
Add an import by name or path |
externai remove |
Remove an import from externai.json |
🧾 Config file (optional)
You can edit externai.json manually if you want, but you don’t have to.
The CLI commands above are enough for most workflows.
Example config (package.json‑like):
{
"version": 1,
"externalsDir": ".externals",
"imports": [
"libA",
{ "name": "frameworkX", "path": "/home/adrien/dev/frameworkX" },
{ "name": "toolkit", "mount": "tk" }
]
}
Config semantics:
version(number, optional): schema version. Default1.externalsDir(string, optional): destination folder for mounts. Default.externals.imports(array, required, can be empty): list of projects to import. Each entry can be:- a string: the registered project
name(itspathis resolved from the registry), - or an object with at least
nameand optional fields:path(string, optional): source path on disk (if omitted, resolved from registry),mount(string, optional): name of the subfolder underexternalsDir(defaults toname).
- a string: the registered project
🧾 Registry details
-
Run
externai register [custom-name]inside the folder you want to expose. The command stores an absolute path → name mapping in your OS data dir (e.g.~/.local/share/ki2/externai/registry.json). If you omit the name, the current folder name is used. -
externai register <name>refuses to overwrite existing entries or duplicate paths unless you confirm. Registering the exact same name/path is a no-op. -
To remove an entry, run
externai unregister <name>or simplyexternai unregisterinside the project root to drop any entry pointing to the current path. -
Use
externai registryto list all registered names and their directories. You can then reference these names directly insideexternai.jsonimports. -
Example config relying on the registry only:
{ "imports": ["libA", "frameworkX"] }
All paths are injected dynamically at mount time.
🧪 Tests
uv run pytest(ensure thetestsoptional dependency is installed viauv sync)
➕ Add/remove imports
externai add <name>adds the named project toexternai.jsonusing a registered path. If the name is missing from the registry,externaiexplains how to register it or how to pass an explicit path (see below).externai add <name> <path>creates an object import for the provided path (will fail if the path does not exist).- When
externai.jsonis absent,externai addcreates a minimal config before appending the entry. externai remove <name>drops the import entry with the given name.
The commands operate on the externai.json file at the project root, so you must run them
from within your project (the same directory that contains the config).
💡 Tips
- Best results on WSL ext4 filesystem (not
/mnt/c). - Requires
mount,umount, and optionallyfindmnt. - No root install:
sudois used only for mount operations.
📦 Project structure
your-project/
├── externai.json # config file
├── .externals/
│ ├── libA/ # bind-mounted (read-only)
│ └── frameworkX/
└── ki2_externai/
├── __init__.py
├── cli.py
├── config.py
├── operations.py
└── utils.py
pip install ki2-externai exposes the externai console script (defined in pyproject.toml), so you can run externai mount directly.
🪪 License
MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ki2_externai-0.3.1.tar.gz.
File metadata
- Download URL: ki2_externai-0.3.1.tar.gz
- Upload date:
- Size: 18.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Linux Mint","version":"21.3","id":"virginia","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eed53d3baa544c5976e51aa9c4a310b1b78cb5645d67260e36272a125f8ce304
|
|
| MD5 |
19f73d3a11aad0174a7734f67582b7b0
|
|
| BLAKE2b-256 |
52ecd3ab906a24ecab3016159f1dc30ce8204d2c8d143a878840533ba5df4503
|
File details
Details for the file ki2_externai-0.3.1-py3-none-any.whl.
File metadata
- Download URL: ki2_externai-0.3.1-py3-none-any.whl
- Upload date:
- Size: 15.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Linux Mint","version":"21.3","id":"virginia","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aee8836583a6bf8482f5326d216f4cdf99bc2c5457a6ed10cb8109b883dbd2a4
|
|
| MD5 |
ec06e26127604e64c0d0044bbbe3f6e0
|
|
| BLAKE2b-256 |
4f1f920baf165f98439a94565bce1fa207f9e6e81cfcbdf7fcd6078f3744e1f0
|